三、事务的范围
以前的一个项目是直接使用JDBC来访问数据库的,后来决定重构到Hibernate和Spring上去,事务控制也由原来的本地JDBC事务转换为Spring的声明式事务。好像一切都很顺利,直到交给性能测试人员。
造成性能低下的原因也很明显,就是由于使用了声明式事务,事务的控制范围是从一个方法的开始到它的结束。如果这个方法很长,而只需要确保其中的某几条数据库的操作语句在一个事务中执行,这样,本来只需要一个很短的事务,结果却使用了一个很长的事务。事务一旦过长,它就会影响别的进程或线程来操作同一个事务源。合理的方法应该是在确实需要事务的时候才开始一个事务,而且要及时提交或回滚它,以释放对事务源的访问,这也就是EJB中,使用BMP(Bean管理事务)相对与CMP(容器管理事务)的好处。如果确定需要在Spring中使用类似BMP的做法,也就是说开发人员自己控制事务,可以通过Spring容器注入Spring的TransactionManager来实现,当然这也就违背了“无浸入”的原则,需要大家在实际中权衡。
另外Spring的事务标注还给我们提供了一些其他的属性,比如说readOnly,isolation和timeout等。当一个方法需要添加事务控制,而且这个方法只做查询操作的时候,千万别忘记标记“readOnly = true”,这样这个事务就可以和别的事务同时访问事务源了。
四、分布式事务
一提到分布式事务,大家可能都想到有多个数据库分布在不同的计算机上。其实,不仅如此,例如一个事务需要同时控制对本地的数据库操作和本地的JMS队列,也可以称为分布式事务。在EJB容器中,例如JBoss,我们会配置一些数据源,一些JMS队列等,无论采用BMP(Bean管理事务)还是CMP(容器管理事务),我们在真正使用的是JTA(Java Transaction API)的UserTransaction,它就是一个分布式事务,它可以控制容器中所有的事务源。
但是在Spring的应用中,要想使用分布式事务就有点困难了,好在还有JTOM,它可以做到分布式事务的控制,最终我们可以使用JOTM提供的UserTransaction,而原来的事务控制部分只需要很小的修改。我所经历的一个项目就是从JBoss迁移到Jetty中去,因为Jetty这样的Web容器不支持分布式事务,问题也就暴露出来了。所以如果大家在项目中需要迁移一个EJB项目到Spring中,千万别忽略了分布式事务的控制。