EJB事务管理有两种方式,一种是利用容器管理,称为CMT;另一种是Bean管理事务,称为BMT。
事务
事务的概念
事务是事件执行的最小单元,事务具有四个特性:
原子性:事务中的所有操作必须都成功,否则就认为是失败。
一致性:事务不能违反完整性约束,不管事务是否提交,都要遵守约束的规则。
隔离性:事务的执行是不影响同时执行的其他事务的。
事务的隔离级别
事务的隔离级别是对应事务的隔离性的,虽然同时执行的事务之间是相互不影响的,但是不影响的程度需要隔离级别来规定。
未提交读(Read Uncommitted):多个事务操作相同的数据,其中事务A读取了数据,对数据进行了更改的操作,但是还没提交的时候,其他事务就能读到事务A更改过的数据。此时如果事务A对数据又进行了一次更改之后提交事务,此时其他事务读到的已经不是最新数据了,也就造成了脏读。
提交读(Read Committed):提交读的级别防止了脏读的情况产生,也就是事务提交之后才可以读取,这样就读到了真实数据。但是会有这么一个情况,当事务A读取了数据,事务还没提交时,另外一个事务B对该数据进行了修改,并且提交了事务。在事务B提交之前,事务A的数据一直是刚开始取出的数据,事务B提交后,事务A没办法再去库里得到事务B提交的数据,也就造成了不可重复读。
重复读(Repeatable read):为了避免不重复读的问题,可以将隔离级别设置为重复读。这样,事务A读取了数据,随后事务B读取了数据,更改数据并提交了事务,这个过程事务A是不能操作数据的。当事务B更新完数据,事务A可以再次读取数据,此时发现数据跟前一次不一样了,这时就产生了幻读。
序列化(Serializable):序列化是隔离级别中的最高级别,能够防止脏读、不可重复读和幻读的问题。
脏读 | 不可重复读 | 幻读 | |
未提交读 | Possible | Possible | Possible |
提交读 | Not Possible | Possible | Possible |
重复读 | Not Possible | Not Possible | Possible |
序列化 | Not Possible | Not Possible | Not Possible |
容器管理事务
容器管理事务是容器接管EJB事务管理,隐式的完成事务的开始、提交和回滚,不需要程序员写代码。容器会自动在业务方法的开始和结束处标记事务边界,根据方法的调用情况来操作事务。在容器管理事务的过程中,是禁止手动操作事务的,也就是会禁止commit和rollback等方法。
容器管理事务时,事务具有六大属性支持,分别是:
Not Supported:不支持事务,如果当前有事务上下文,将挂起当前事务。
Supports:支持事务,如果当前有事务则使用该事务;如果没有事务就不使用事务。
Required:需要事务,如果当前有事务,则使用该事务;如果当前没有事务,则创建新事务。
Required New:需要新的事务,如果当前有事务,则挂起该事务,然后创建新的事务并执行,执行完成之后再恢复原来的事务。
Mandatory:必须要有当前事务,如果当前没有事务,则会报出异常。
Never:必须不能有事务,如果当前有事务,则会报出异常。
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class UserManagerBean implements UserManager {
@Override
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void addUser(User user) {
System.out.println("User[username=" + user.getUsername() + "]已经成功保存!");
user.setId(10);
}
public String sayHello(String name) {
return "你好," + name;
}
}
Bean管理事务
BMT相对于CMT来说是比较灵活的,CMT中容器总是在业务方法的开始和结束处标记事务边界,而BMT事务管理是由开发者决定事务边界的。BMT事务管理依赖于UserTransaction,是JTA事务中的一个API,类似于JDBC事务。
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class UserManagerBMT {
@Resource
private UserTransaction tx;
public void insert() throws Exception {
try {
// 开始事务
tx.begin();
// 业务逻辑代码
// 提交事务
tx.commit();
} catch (Exception e) {
e.printStackTrace();
// 回滚事务
tx.rollback();
}
}
}
JDBC事务和JTA事务
JDBC事务:JDBC事务是由Connection对象控制管理的,事务周期限于Connection对象的生命周期。JDBC事务只能支持一个数据库,一般是由数据库本身执行提交或回滚操作。
JTA事务:JTA事务是支持分布式的事务,可以支持多个数据源。JTA事务会提供一个事务管理器,来管理数据源之间的事务操作。一般事务提交需要经过两个阶段,首先是事务管理器向数据库确实是否可以提交或回滚,称为准备阶段;事务管理器确认后,会发指令,使得数据库提交或回滚,称为提交阶段。
总结
EJB相对来说还是比较支持CMT方式的,利用容器来管理事务。但是BMT比CMT管理事务更加灵活,各有各的缺点,也各有各的优点,结合相应业务要选择相应的事务管理方式。