由于这个问题经常被问到,nutzcn社区累计了好几十个帖子,所以有必要单独开个文档描述一下
在一些复杂或遗留系统中,通常需要操作两个或更多的数据源.
总的原则: NutDao与DataSource是一对一关系.
值得注意的是, javax.sql.DataSource只是一个接口,而且NutDao只会调用其getConnection()方法.
你可以定义无数个dataSourceXXX,只要它们使用不一样的名称, 然后建立对应的N个NutDao实例
每个NutDao实例,均refer对应的dataSource
// 主数据库 dataSource : { // 按标准的写法 }, // 主Dao实例 dao : { type : "org.nutz.dao.impl.NutDao", args : [{refer:"dataSource"}] //引用主数据源 }, //-------------------------------------------------------- // 第三方订单数据库 dataSourceOrder : { // 同样是标准的写法 }, daoOrder : { type : "org.nutz.dao.impl.NutDao", args : [{refer:"dataSourceOrder"}] //引用第三方数据源 }, //-------------------------------------------------------- // 遗留数据库 dataSourceOld : { // 同样是标准的写法 }, daoOld : { type : "org.nutz.dao.impl.NutDao", args : [{refer:"dataSourceOld"}] //引用第三方数据源 },
在Module/Service类中的注入
// 非父类字段的注入 @Inject protect Dao dao; // 注入主Dao实例 @Inject protect Dao daoOrder; // 注入第三方订单数据库Dao实例 // 通过父类字段的注入,通常是继承的EntityService的服务类. @IocBean(args={"refer:daoOrder"}) // 效果是: 调用dao()返回的将是daoOrder实例.
在一般情况下,Trans.exec下,多个数据源下的事务能正常工作,除特殊的情况: 某个数据源commit时报错,之前已经commit的数据源无法回滚.
假设有A,B,C三个数据源
Trans.exec(new Atom(){
public void run() {
dao.insert(user);
daoOrder.insert(order);
daoOld.insert(report);
}
});
事务执行时序
begin > dao begin > daoOrder begin > daoOld commit > dao commit > daoOrder commit > daoOld #出错 rollback > dao # 回滚失败,因为已经commit过 rollback > daoOrder # 回滚失败,因为已经commit过 rollback > daoOld # 可能也失败,但没有提交成功
以上特殊情况,是任何基于标准JDBC驱动的ORM都无法回避的. 走XA的JDBC API才可能解决.