Spring+Hibernate+Jpa嵌套事务型service点滴

本文讨论了Spring框架下事务型service嵌套调用引发的问题及解决方案,特别是当两个service都开启了事务时,如何避免因过早flush导致的数据错误。

近期和团队兄弟一起处理了一个事务型service嵌套调用引发的问题,总结起来。

环境

spring4.2.5+hibernate4.3.11+jpa2.1
spring xml 配置使用注解事务方式:

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    <!-- 方法中使用@Transactional注解 -->

问题描述

 service1.method--->(调用)service2.method,当1和2都开启事务,且1开启的读写事务,

默认情况下2会嵌套在事务1中,即传播类型为Propagation.REQUIRED。

因此当1中创建了某个实体,未提交,开始调用2。

当从2返回时hibernate会自动做flush,此时是一个hibernate session,1中创建的实体也会被flush到db。

可能1中创建的实体并不完整,会导致sql错误。

1中本来会在自己结束之前构建完整实体,flush提交到db中,是不会出错,但2提前给flush了。

解决办法

  • 若2可以不开启事务则在service2.method中增加注@Transactional(readOnly = true,propagation=Propagation.NOT_SUPPORTED),这时执行到2时1中的事务会被挂起,2中不开启事务,也不会在结束时flush db了,就不会报错。
  • 若2需要事务,并且希望和1是同一个事务。则需要可配置hibernate的flush mode 为COMMIT。通过在xml中配置:

<bean id="entityManagerFactory"	class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" abstract="true">
...
		<property name="jpaProperties">
			<props>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.hbm2ddl.auto">${auto.ddl}</prop>
				<prop key="org.hibernate.flushMode">COMMIT</prop>
			</props>
		</property>
...
</bean>
  • 2需求事务时,还可以不通过hibernate属性配置,而是代码中实现。即1在调用2之前,先将flushmode设置为COMMIT,调用完2之后再还原为原来的flushmode:
@PersistenceContext(unitName="entityManagerFactory")
private EntityManager entityManager;
...
@Transactional
public void method(){ // service1
...
    FlushModeType orgFlushModeType = entityManager.getFlushMode();
    entityManager.setFlushMode(FlushModeType.COMMIT);
    Map<String, List<Tracking>> dbTrackingMap = null;
    try {
	service2.method();
    } finally {
	entityManager.setFlushMode(orgFlushModeType);
    }
...
}
...

  • 另外,如果2只是需求事务,但可以与1在不同的事务,可以将2的事务传播类型使用@Transactional(readOnly = true,propagation=Propagation.REQUIRES_NEW),未深入测试,读者可以自行测试。



评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值