Spring(5.0.3)+Hibernate(5.2.12)事务管理:增查正常改删失效求助
老哥,我之前也碰到过类似的SpringWS+Hibernate事务问题,结合你用的Spring 5.0.3 + Hibernate 5.2.12技术栈,UPDATE/DELETE不生效但INSERT/SELECT正常,大概率是这几个核心点出了问题,给你捋捋解决方案:
1. 先排查SpringWS的上下文隔离陷阱
SpringWS的spring-ws-servlet.xml属于Servlet级别的上下文,而我们通常会把事务、数据源、Hibernate核心配置放在根上下文(比如applicationContext.xml)里。如果你的WS端点(Endpoint)是在servlet上下文里扫描的,它可能无法获取到根上下文的事务代理Bean,导致UPDATE/DELETE操作根本没走事务。
解决方法:
- 把Service、DAO层的组件扫描放在根上下文,servlet上下文只扫描Endpoint类
- 或者在
spring-ws-servlet.xml里通过<import>导入根上下文的配置,确保事务配置能被servlet上下文识别
2. 检查事务注解的正确性
这是最常见的坑:
- 确保你的Service层方法加了
@Transactional注解,别把注解直接加在DAO或Endpoint上(Spring事务AOP的代理逻辑需要在Service层生效) - 绝对不能给UPDATE/DELETE方法加
@Transactional(readOnly = true)!这个属性会让Hibernate跳过flush操作,更新/删除自然不会生效 - 可以指定事务的传播行为,比如
@Transactional(propagation = Propagation.REQUIRED)(默认就是这个,但显式写出来更稳妥)
示例正确的Service方法:
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional @Override public void updateUser(User user) { userDao.update(user); } @Transactional @Override public void deleteUser(Integer userId) { userDao.delete(userId); } }
3. 验证Hibernate的Session与Flush模式
- 确保DAO里用的是
sessionFactory.getCurrentSession(),而不是openSession():getCurrentSession()会绑定到Spring的事务,事务提交时自动flush;openSession()是独立Session,需要手动flush和关闭,很容易导致更新丢失 - 检查Hibernate配置的flush模式,别设成
FLUSH_NEVER,正常应该是FLUSH_AUTO(默认值),这样事务提交时Hibernate会自动同步更新到数据库 - 如果是手动管理Session,一定要在事务结束前调用
session.flush(),但更推荐让Spring全权管理Session
4. 确认实体的状态是否正确
Hibernate只对持久化状态的实体自动跟踪更新:
- 如果是更新操作,要确保操作的是从数据库查询出来的实体(比如先
getById拿到实体,修改后直接保存);如果是外部传入的 detached 实体,要调用session.merge(entity)来合并状态 - 删除操作同理,要么传入持久化状态的实体,要么通过ID调用
session.delete()时确保实体存在
错误示例(detached实体直接更新):
// 错误:new出来的实体是transient状态,Hibernate不会自动更新 User user = new User(); user.setId(1); user.setName("NewName"); userDao.update(user);
正确做法:
// 先查询获取持久化实体,修改后自动更新 User user = userDao.getById(1); user.setName("NewName"); userDao.update(user); // 或者不需要显式update,事务提交时Hibernate会自动同步
5. 检查事务管理器的配置
确保根上下文里的事务管理器正确关联了Hibernate的SessionFactory:
<!-- 根上下文配置示例 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!-- 数据源、Hibernate属性、实体映射配置 --> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 开启注解驱动的事务管理 --> <tx:annotation-driven transaction-manager="transactionManager"/>
如果是用JavaConfig,要确保@EnableTransactionManagement注解和HibernateTransactionManager的Bean配置正确。
最后一招:开日志排查
开启Spring事务和Hibernate的DEBUG日志,直接看底层执行情况:
- 配置日志框架(Logback/Log4j),添加以下日志级别:
<logger name="org.springframework.transaction" level="DEBUG"/> <logger name="org.hibernate.SQL" level="DEBUG"/> <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE"/>
通过日志可以看到:
- 事务是否被正确开启、提交
- Hibernate有没有生成UPDATE/DELETE的SQL语句
- 如果SQL生成了但没生效,是不是事务被回滚了
内容的提问来源于stack exchange,提问作者blueDaisy




