JAVA平台事务管理
JamesGore119@gmail.com
事务是用户定义的操作序列,是一个逻辑工作单元。事务存在的目的是保证系统的正确性,保证系统对应的数据资源,如数据库、文件系统,以受控的方式操作,所以事务本身具有4个限定属性:原子性、一致性、隔离性、持久性。
一、 局部事务与全局事务
一个事务处理场景中,一般包含以下几个角色:
资源管理者:ResourceManger ,负责存储并管理系统数据资源的状态,如数据库服务器,JMS消息服务器等。
事务处理监视者:TransactionProcess Monitor,负责分布式事务场景中协调多个RM的事务处理。一般中间件或应用服务器担当此角色。
事务管理者:TransactionManager,可以认为是TP monitor的核心模块,直接负责RM事务处理,包括事务界定,事务上下文传递等功能。
应用程序:触发事务的边界点
事实上,并不是每个事务处理过程都包含这些角色,根据整个事务过程中涉及到资源管理者多少,可以分为局部事务与全局事务。这两类事务,具体的参与者不一样。
1. 全局事务
如果整个事务处理过程中,包含多个RM,那么就需要引入TP Monitor来协调多个RM之间的事务处理。
应用程序提交事务请求,TPMonitor调配之后,由TM统一协调,TM将使用两阶段协议来协调多个RM之间的事务处理。
2. 局部事务
如果当前事务中有一个资源管理者参与,那么当前事务就是局部事务。比如说一个系统只有一个数据源,或者有多个数据源,但每次事务只涉及到一个数据源。
局部事务中只涉及到一个RM,那TP Monitor就没有存在的必要,应用程序直接和RM打交道,通常情况下,RM都有内置的事务支持,如数据库的事务管理。局部事务,实践当中,更倾向使用内置事务支持,减少复杂度与事务开销。
二、 JAVA事务管理
在程序开发中,我们关心的是通过相应的产品API获取事务资源,考虑在业务逻辑中界定事务边界,并不关心各供应商如何实现事务。JAVA平台提供了各种各样的事务管理API,应用于局部事务场景与全局事务场景。
1. 局部事务支持
局部事务管理方式,不使用专门的事务管理API,而使用数据访问技术的API进行事务管理,局部事务随着数据访问技术的不同而异。从前面可知,局部事务RM都有内置事务支持,所以局部事务管理是基于数据访问技术所提供,应用程序与数据资源之间通信通道的API来管理事务,也就是说基于连接的API管理事务。
l JDBC
JDBC是java平台数据访问最基础的API,基于java.sql.Connection,控制事务的提交与回滚。
Connection connection = ...
connnection.setAutoCommit(false)
...
connection.commit();或connection.rollback();
l Ibatis\Mybatis
mybatis是基于jdbc的封装,封装了jdbc模板代码,实现了实体与sql语句之间的映射。
SqlSession session = sqlSessionFractory.open(false);
...
session.commit();或session.rollback();
l Hibernate
如果说mybatis是实体与sql之间的映射,那么hibernate是实体与表之间的映射。hibernate基于Session进行数据访问的事务管理(可以配置hibernate基于jdbc的局部事务管理,或者使用分布式事务管理)。
Session session = factory.open();
Transaction transaction =session.beginTransaction;
...
transaction.commit(); 或 transaction.rollback();
l JPA
JPA是一个持久化规范,hiberante是其中的一种实现方式(也是事实上的标准),其它实现还有TopLink、OpenJPA。JPA基于EntityManage进行事务管理。
EntityManger em = ...
em.getTransaction().begin();
...
em.getTransaction().commit() 或 em.getTransaction().rollback();
l JMS
JMS是基于javax.jmx.Session进行事务控制。
Session session = ...
...
session.commit(); 或 session.rollback();
局部事务管理常常涉及到一的一个问题是“连接”的传递,当在一个服务中包含多次数据访问时,数据访问层必须使用同一个“连接”,这是程序设计需要考虑的问题,否则无法地做到事务的原子性。
一般有两种思路解决这个问题,一个是参数传递,服务层开启连接(事务),传递给各个数据访问层;另一个是使用ThreadLocal,把“连接”绑定到线程上。
2. 全局事务支持
Java平台上的分布式事务,主要通过JTA支持。JTA是java标准分布式事务接口规范,具体实现由相应的供应商实现,各j2ee应用服务器需要提供对JTA的支持。除了应用服务器支持外,还有其它独立的JTA实现产品,如JOTM、Atomikos、JBoss Transaction等。
JTA采用X/Open XA实现两阶段协议,X/OpenXA接口是双向的系统接口,在事务管理器及资源管理者之间形成通售通道。仅在同一个事务上下文中需要协调多种资源时,才有必要使用X/Open XA接口。大多数场景,应用使用局部事务,单阶段提交,非必要引入XA数据库驱动,会导致不可预料的后果。
JTA是开发人员进行事务管理的接口,JTS是应用服务器使用的,实现了JTA的底层事务服务。
JTA进行分布式事务管理有两种方式:编程事务管理、声明性事务管理。
l 编程事务管理
使用编程事务管理,首先得获取Usertransaction,各应用服务器提供了JNDI查找服务。
InitialContext ctx = new InitialContext();
UserTransaction transaction =ctx.lookup("UserTransaction");
...
transaction.commit() 或 transaction.rollback();
其中不同的应用服务器给定的查找名称不同,如Jboss 查找名为“UserTransaction”,而Weblogic,查找名为"javax.transaction.UserTransaction"。
在EJB中时,编程事务管理又称之为BMT,Bean ManageTransaction。在EJB中需要使用配置文件或注解配置为BMT,Usertransaction可以直接从EJBContext中获取。
l 声明性事务管理
编程事务管理中,必须手动开启与结束事务,声明性事务管理,容器管理事务,开发人员不用编写任务代码,可以通过配置文件或注解,告诉容器如何管理事务。EJB声明性事务也称为容器管理事务,CMT,Container Manage Transaction。使用CMT,必须有EJB容器提供支持。
使用CMT仅要做的工作是配置事务属性,需要回滚时调用EJBContex方法setRollbackOnly()。
容器不会在应用发生异常时自行将事务标记为回滚,所有我们要在应用发生异常时告知容器回滚事务:setRollbackOnly()。
在CMT事务管理中,一个必然的决定,什么地方抛异常,什么地方和什么时机调用setRollbackOnly。一般的决策,开启事务的方法,具有事务管理的责任。
EJB中包含一个@ApplicationException注解,该注解告知应用服务器,当用异常抛出时是否自动将事务标记为回滚。带来的好处是不用写setRollbackOnly方法。缺点是注解针对异常类,只要抛出该异常,无论对象本身有没有开启事务,都会导致整体事务回滚,负责处理事务的方法无任何对回滚事务的补救。另一缺点是,将事务处理与异常处理混在一起,导致异常粒度过大。
三、 问题
JAVA平台提供的事务管理API多种多样,可以根据不的场景选择不同的事务管理API。但过多的选择,也带来一些问题。
1. 局部事务管理依赖于具体数据访问技术。事务管理代码与数据访问代码、业务代码混杂,将导致数据访问代码、业务代码不可重用;事务代码分散,降低了可重用性。
2. 无统一事务相关异常体系,需要事务管理代码处理checked exception.
3. 选择太多,缺少统一的事务抽象。
4. CMT必须借助于EJB容器。CMT代码清晰,事务管理与业务代码分离,但受限于容器。
有需求就有解决方案,Spring事务框架,对事务管理与数据访问关注点进行了分离与抽象,使开发人员仅关心事务界定。
...... 原创文章,转载请注明出处, 本文地址: http://blog.csdn.net/jamesgore/article/details/8979089 ......
1. http://baike.baidu.com/view/351106.htm
2. http://www.ibm.com/developerworks/cn/java/j-lo-jta/
3. spring framework refrerence
4. spring 揭秘
5. Java Transaction DesignStrategies