You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动