Ibatis事务管理
基于 JDBC的事务管理机制ibatis提供了自动化的JDBC事务管理机制。
对于传统JDBC Connection 而言,我们获取Connection 实例之后,需要调用Connection.setAutoCommit设定事务提交模式。
在 AutoCommit为true的情况下,JDBC会对我们的操作进行自动提交,此时,每个JDBC操作都是一个独立的任务。
为了实现整体事务的原子性,我们需要将AutoCommit 设为false,并结合Connection.commit/rollback方法进行事务的提交/回滚操作。ibatis 的所谓“自动化的事务提交机制”,即ibatis 会根据当前的调用环境,自动
判断操作是否需要自动提交。
如果代码没有显式的调用SqlMapClient.startTransaction()方法,则ibatis会将当前的数据库操作视为自动提交模式(AutoCommit=true),如:
sqlMap = xmlBuilder.buildSqlMap(reader);
User user = new User();
user.setId(new Integer(1));
user.setName("Erica");
user.setSex(new Integer(0));
sqlMap.update("User.updateUser", user);
User user2 = new User();
user2.setId(new Integer(2));
user2.setName("Kevin");
user2.setSex(new Integer(1));
sqlMap.update("User.updateUser", user2);
在执行sqlMap.update的时候,ibatis会自动判定当前的运行环境,这里update操作并没有相对应的事务范围(startTransaction和endTransaction代码块),于是ibatis 将其作为一个单独的事务,并自动提交。对于上面的代码,update 执行了两次,与其相对应,事务也提交了两次(即每个update操作为一个单独的事务)。
不过,值得注意的是,这里的所谓“自动判定”,可能有些误导,ibatis 并没有去检查当前是否已经有事务开启,从而判断当前数据库连接是否设定为自动提交。
实际上,在执行update语句时,sqlMap会检查当前的Session是否已经关联了某个数据库连接,如果没有,则取一个数据库连接,将其AutoCommit属性设为true,然后执行update 操作,执行完之后又将这个连接释放。这样,上面两次update 操作实际上先后获取了两个数据库连接,而不是我们通常所认为的两次update 操作都基于同一个JDBC Connection。这点在开发时需特别注意。
对于多条SQL 组合而成的一个JDBC 事务操作而言,必须使用startTransaction、commit和endTransaction操作以实现整体事务的原子性。
如:
try{
sqlMap = xmlBuilder.buildSqlMap(reader);
sqlMap.startTransaction();
User user = new User();
user.setId(new Integer(1));
user.setName("Erica");
user.setSex(new Integer(0));
sqlMap.update("User.updateUser", user);
User user2 = new User();
user2.setId(new Integer(2));
user2.setName("Kevin");
user2.setSex(new Integer(1));
sqlMap.update("User.updateUser", user2);
sqlMap.commitTransaction();
}finally{
sqlMap.endTransaction();
}
如果 user1 或者user2的update操作失败,整个事务就会在endTransaction时回滚,从而保证了两次update操作的原子性。
基于 JTA的事务管理机制
JTA提供了跨数据库连接(或其他JTA资源)的事务管理能力。这一点是与JDBCTransaction最大的差异。
JDBC事务由Connnection管理,也就是说,事务管理实际上是在JDBC Connection中实现。事务周期限于Connection的生命周期。同样,对于基于JDBC的ibatis事务管理机制而言,事务管理在SqlMapClient所依托的JDBC Connection中实现,事务周期限于SqlMapClient 的生命周期。
JTA事务管理则由JTA容器实现,JTA容器对当前加入事务的众多Connection进行调度,实现其事务性要求。JTA的事务周期可横跨多个JDBC Connection生命周期。同样,对于基于JTA事务的ibatis而言,JTA事务横跨可横跨多个SqlMapClient。
为了在ibatis中使用JTA事务管理,我们需要在配置文件中加以设定:
……
外部事务管理
基于JTA的事务管理还有另外一个特殊情况,就是利用外部事务管理机制。
对于外部事务管理,我们需要在配置文件中进行如下设定:
……
Cache
在特定硬件基础上(同时假设系统不存在设计上的缺漏和糟糕低效的SQL 语句)Cache往往是提升系统性能的最关键因素)。
相对Hibernate 等封装较为严密的ORM 实现而言(因为对数据对象的操作实现了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭的封装实现,因此对缓存的操作难以做到完全的自动化同步)。
ibatis 的缓存机制使用必须特别谨慎。特别是flushOnExecute 的设定(见“ibatis配置”一节中的相关内容),需要考虑到所有可能引起实际数据与缓存数据不符的操作。如本模块中其他Statement对数据的更新,其他模块对数据的更新,甚至第三方系统对数据的更新。否则,脏数据的出现将为系统的正常运行造成极大隐患。
如果不能完全确定数据更新操作的波及范围,建议避免Cache的盲目使用。
可以看到,Cache有如下几个比较重要的属性:
Ø readOnly
Ø serialize
Ø type
readOnly
readOnly值的是缓存中的数据对象是否只读。这里的只读并不是意味着数据对象一旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要重新从数据库读取数据,构造新的数据对象。
而 readOnly="false"则意味着缓存中的数据对象可更新,如user 对象的name属性发生改变。
只读Cache能提供更高的读取性能,但一旦数据发生改变,则效率降低。系统设计时需根据系统的实际情况(数据发生更新的概率有多大)来决定Cache的读写策略。
serialize
如果需要全局的数据缓存,CacheModel的serialize属性必须被设为true。否则数据缓存只对当前Session(可简单理解为当前线程)有效,局部缓存对系统的整体性能提升有限。
在 serialize="true"的情况下,如果有多个Session同时从Cache 中读取某个数据对象,Cache 将为每个Session返回一个对象的复本,也就是说,每个Session 将、得到包含相同信息的不同对象实例。因而Session 可以对其从Cache 获得的数据进行存取而无需担心多线程并发情况下的同步冲突。
Cache Type:
与hibernate类似,ibatis通过缓冲接口的插件式实现,提供了多种Cache的实现机
制可供选择:
1.MEMORY
2.LRU
3.FIFO
4.OSCACHE
MEMORY类型Cache与WeakReference
MEMORY 类型的Cache 实现,实际上是通过Java 对象引用进行。ibatis 中,其实现类
为com.ibatis.db.sqlmap.cache.memory.MemoryCacheController,MemoryCacheController 内部,
使用一个HashMap来保存当前需要缓存的数据对象的引用。
这里需要注意的是Java2中的三种对象引用关系:
a SoftReference
b WeakReference
c PhantomReference
传统的Java 对象引用,如:
public void doSomeThing(){
User user = new User()
……
}
当doSomeThing方法结束时,user 对象的引用丢失,其所占的内存空间将由JVM在下次垃圾回收时收回
LRU型Cache
当Cache达到预先设定的最大容量时,ibatis会按照“最少使用”原则将使用频率最少的对象从缓冲中清除。
FIFO型Cache
先进先出型缓存,最先放入Cache中的数据将被最先废除
OSCache来自第三方组织Opensymphony。可以通过以下网址获得OSCache的最新版
在生产部署时,建议采用OSCache,OSCache 是得到了广泛使用的开源Cache 实现
(Hibernate 中也提供了对OSCache 的支持),它基于更加可靠高效的设计,更重要的是,
最新版本的OSCache 已经支持Cache 集群。如果系统需要部署在集群中,或者需要部署在
多机负载均衡模式的环境中以获得性能上的优势,那么OSCache在这里则是不二之选。