6
回答
让JFinal的ActiveRecord支持多数据源。
注册华为云得mate10,2.9折抢先购!>>>   

比较喜欢JFinal简单的设计。但是我们的不少项目都需要连接至少两个数据库,而JFinal的ActiveRecord对多数据源支持比较若。周末断断续续花了一天的时间对JFinal进行的ActiveRecord做改造。让JFinal的ActiveRecord支持多数据源。详细见我的博客。

http://my.oschina.net/myaniu/blog/185331

举报
玛雅牛
发帖于4年前 6回/1K+阅
共有6个答案 最后回答: 4年前

      第一次有人对这个功能提出挑战!感谢 @玛雅牛 对 JFinal 的支持,希望能早点将代码分享给大家 

    这个功能的确很多朋友提出来需要,我也一直在纠结要不要做这个,有几个纠结之处:

1:多数据源下的事务处理问题,如果要支持多数据源下的事务,代码想着就比较难看,将会违反极简设计风格

2:多数据源使用了不同的数据库时,多个 Dialect 的问题,还是代码难看的问题

3:同一个 Model 可以使用不同的 DataSource的问题

4:性能损失问题

5:还有一些其它问题,一时想不起来了

    所以 JFinal 一直没有开发这个功能,而是一直在建议开发者将多数据源的项目拆分成多个小项目或子服务,每一个小项目只使用一个数据源

   不过一切都不好说,说不定 @玛雅牛 的这个实现能解决我的这些纠结。

   在此说一下以前对多数据源的设计思路,看与楼主的有多少共同之处:

1:创建多连接池与多ActiveRecordPlugin对象,将不同连接池关联给不同的ActiveRecordPlugin对象,这个与 @玛雅牛 的思路完全一样

2:将不同的 Model 添加到不同的 ActiveRecordPlugin中

3:TableInfo 中添加一个 DataSource属性,在ActiveRecordPlugin初始化时,使 Model 与 DataSource建立关联

4:在 DbKit中添加 getConnection(Class<Model>) 方法,在获取连接时指定modelClass,即不同的 Model 会从不同的 DataSource得到Connection对象

   要是 @玛雅牛 的设计方案能够避免掉我的纠结之处,那就极好了

引用来自“JFinal”的答案

      第一次有人对这个功能提出挑战!感谢 @玛雅牛 对 JFinal 的支持,希望能早点将代码分享给大家 

    这个功能的确很多朋友提出来需要,我也一直在纠结要不要做这个,有几个纠结之处:

1:多数据源下的事务处理问题,如果要支持多数据源下的事务,代码想着就比较难看,将会违反极简设计风格

2:多数据源使用了不同的数据库时,多个 Dialect 的问题,还是代码难看的问题

3:同一个 Model 可以使用不同的 DataSource的问题

4:性能损失问题

5:还有一些其它问题,一时想不起来了

    所以 JFinal 一直没有开发这个功能,而是一直在建议开发者将多数据源的项目拆分成多个小项目或子服务,每一个小项目只使用一个数据源

   不过一切都不好说,说不定 @玛雅牛 的这个实现能解决我的这些纠结。

   在此说一下以前对多数据源的设计思路,看与楼主的有多少共同之处:

1:创建多连接池与多ActiveRecordPlugin对象,将不同连接池关联给不同的ActiveRecordPlugin对象,这个与 @玛雅牛 的思路完全一样

2:将不同的 Model 添加到不同的 ActiveRecordPlugin中

3:TableInfo 中添加一个 DataSource属性,在ActiveRecordPlugin初始化时,使 Model 与 DataSource建立关联

4:在 DbKit中添加 getConnection(Class<Model>) 方法,在获取连接时指定modelClass,即不同的 Model 会从不同的 DataSource得到Connection对象

   要是 @玛雅牛 的设计方案能够避免掉我的纠结之处,那就极好了

多谢@JFinal的建议。我说说我的设计,希望@JFinal多给些建议。

几个关键点的设计:
核心数据结构:

private static class GroupEntry{
	private DataSource dataSource = null;
	private Dialect dialect = null;
	private ICache cache = new EhCache();
	private boolean showSql = false;
	private int transactionLevel = Connection.TRANSACTION_READ_COMMITTED;
	private ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
	//此处省略getset方法
};
public static final String DEFAULT_GROUP = "default";
private static ConcurrentMap<String, GroupEntry> groupMap= new ConcurrentHashMap<String, GroupEntry>();
static{
	GroupEntry defaultGroupEntry = new GroupEntry();
	groupMap.put(DEFAULT_GROUP, defaultGroupEntry);
}
public static GroupEntry registGroup(String group){
	GroupEntry groupEntry = new GroupEntry();
	groupMap.put(group, groupEntry);
	return groupEntry;
}
public static GroupEntry getGroupEntry(String group){
	return groupMap.get(group);
}

多个ActiveRecordPlugin间基本是独立的。

Model中添加如下代码,以获得所属分组: 
private final String group = tableInfoMapping.getGroupOfClass(getClass());

当然处于性能考虑tableInfoMapping中新增了: 

private static final Map<Class<? extends Model<?>>, String> classGroupMap =
 new HashMap<Class<? extends Model<?>>, String>();

这个结构会在buildTableInfo时构建。

Model,Db,DbKit相关操作都添加了group参数。通过

public static GroupEntry getGroupEntry(String group)

就能拿到所需的各种信息。

目前比较麻烦的是多数据源的事务问题,还有原来的Tx系列拦截器也只能在一个数据源的事务中运行,如果涉及多数据源的事务问题,目前只能手工写事务处理代码,不能用拦截器。

关于性能损失问题,我简单测试了一下,几乎没有损失,只是比以前多了一次从Map中查找操作。

对于同一个Model使用不同数据源的问题:
1)目前Model初始化时会自动查到自己所属group,如果一个Model只属于一个数据源,对开发者而言,这里不用做改动。静态dao也没问题。
2)继续1),如果两个数据源都有相同的table,想用同一个Model解决,可以建立一个Model,然后再建立两个Model,直接继承即可,这种方式本质还是一个Model一个数据源,实现也简单,不好就是会多出一些类来。
3)一个Model使用多个数据源,Model本身有一个M group(String group)方法。可以这样:

new User().group("systemA").set("name","玛雅牛").save();
List<User> users = new User().group("systemA").find("select * from user"); 
List<User> users = User.dao.group("systemA").find("select * from user");
这种方式下,User.dao.group("systemA")可能会有副作用,就是在多线程情况下,非线程安全。线程安全起见,建议用 new User().group("systemA")的方式。  



--- 共有 4 条评论 ---
callmeHEN@JFinal 我现在就遇到了 很多个数据库的问题 。 可能有上千个数据库,里面的表都一样。所以在代码里,要不停的切换切换再切换。我建了相同的Model,但是没有发现你说的Group这个对象呢。请问怎么处理,谢谢指导 3年前 回复
玛雅牛回复 @JFinal : 这个目前已经做到了。 4年前 回复
JFinal总之,用户在使用时,除了在 configPlugin(Plugins me)中有点不同外,其它地方完全一样,User.dao.find(...) 会自动匹配对应的DataSource、Dialect、showSql这样的配置 4年前 回复
JFinal设计方向跟我大致是一样的,最大的不同是,获取 Group 变量需要是透明的,在 YourModel中通过 getClass() 作为参数来获取 Gourp对象,这样在 User.dao.find(..) 时就不需要再 group("systemA")这样的代码了极方便 4年前 回复

引用来自“猎户座”的答案

表示我最近也在纠结这个问题。。。
可以尝试一下,能给出建议最好。
顶部