昨天改EJB程序时出现了一个bug,服务器报了一个transaction does not exist,研究了大半天,终于发现原来是因为我的两个事物同时修改一条记录,weblogic两阶段提交时产生的问题,先上代码(示例,不是真实那个啊):
第一个接口:
@Stateless
@Remote( { ARmote.class })
public class ABean implements ARmote{
@EJB
private ARmote aRmote;
@EJB
private BRmote bRmote;
public void invoke(DTO dto){
bRmote.update(dto);
aRmote.update(dto);
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public int update(DTO dto){
return dao.update(dto);
}
}
第二个接口:
@Stateless
@Remote( { BRmote.class })
public class BBean implements BRmote{
public int update(DTO dto){
return dao.update(dto);
}
}
第一个接口和第二个接口分别改同一个表中不同的字段,当我调用ARemote的invoke方法时报错(别问问啥这么写,需求)。
原因是:当程序执行到BRemote的update方法时,由于使用的是默认的事物级别(required),因此会加入ARemote的事物中,BRemote的update方法执行完毕后,weblogic会执行第一阶段提交;然后程序继续执行到aRmote.update(dto);这行时,又新起了一个事物,去操作刚刚修改的记录,导致oracle报错。
后来将aRmote.update(dto);这行挪到BRemote的update方法中,虽然修改的也是这条记录,但程序不会出现问题。
分析后得出如下结论:
假设方法A内调用方法B,方法B内调用方法C,假设A、B使用REQUIRED级别、C使用REQUIRES_NEW级别的事物,这时,方法A、B在事物1中进行,方法C在事物2中进行,那么事物的出栈顺序为:
1、执行方法C之前,方法B内所做的数据库操作不进行提交。
2、方法C执行完毕后,事物2两阶段全部提交。
3、方法B执行完毕后,方法B内所做的数据库操作进行第一阶段提交。
4、方法A执行完毕后,方法A、B内所做的数据库操作进行两阶段端提交。
大致如下