Hibernate+Spring LocalSessionFactory执行更新查询但数据库无变更
嘿,我来帮你搞定这个头疼的问题——代码里的更新语句明明执行了,数据库却一点变化都没有。结合你给出的代码片段,咱们一步步来排查:
1. 先确认SQL语句是否真的命中数据
这是最基础但最容易忽略的一步:把你拼接的SQL直接复制到数据库客户端(比如MySQL Workbench、Navicat)里执行一遍,看看有没有返回“影响行数”。
- 如果执行后也没变更,那问题出在**
WHERE SID='412'这个条件根本没匹配到任何记录**,你得检查SID的值是不是打错了,或者对应的数据是不是已经被删除了。 - 如果直接执行SQL能成功更新,那咱们继续往下找原因。
2. 检查事务配置是否真的生效
你的Repository类加了@Transactional注解,但得确保Spring的事务管理真的在干活:
- 先看你的Spring配置类有没有加
@EnableTransactionManagement注解,这是开启事务管理的开关。 - 再确认事务管理器Bean是否正确关联了LocalSessionFactory,比如:
@Bean public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) { HibernateTransactionManager txManager = new HibernateTransactionManager(); txManager.setSessionFactory(sessionFactory); return txManager; }
另外,@Transactional默认的传播行为是REQUIRED——如果调用这个方法的上层方法没开事务,Spring会自动新建一个;但如果上层事务被标记为回滚,那你的更新也会跟着回滚。你可以在方法里加个日志,或者用TransactionSynchronizationManager.isActualTransactionActive()判断当前有没有活跃事务。
3. 检查Session的Flush模式
Hibernate的Session默认是AUTO模式,会在合适的时机把变更同步到数据库,但有时候如果Flush模式被改成了MANUAL或者COMMIT,就会导致更新操作“攒”在内存里,没写到数据库。
你可以试试在执行更新后显式调用flush:
Session session = sessionFactory.getObject().getCurrentSession(); int affectedRows = session.createSQLQuery(sbCover.toString()).executeUpdate(); // 显式触发同步 session.flush(); // 顺便打印下影响行数,确认SQL真的执行了 System.out.println("影响行数:" + affectedRows);
不过更稳妥的是检查LocalSessionFactory的配置,确保Flush模式是默认的AUTO。
4. 检查是否有异常悄悄导致事务回滚
你的方法里有try-catch块,但如果捕获了异常却没有正确处理,比如吞掉了RuntimeException,Spring可能会误以为没有异常,但Hibernate已经悄悄把事务标记成了回滚状态。
你可以在catch块里打印完整的异常栈,或者重新抛出异常让Spring处理回滚:
try { // 你的更新代码 } catch (Exception e) { // 别吞掉异常,打个日志再抛出去 System.err.println("更新出错了:" + e.getMessage()); e.printStackTrace(); throw e; }
另外,@Transactional默认只对RuntimeException和Error触发回滚,如果是检查型异常(比如SQLException),你得在注解里加上rollbackFor = Exception.class。
5. 确认LocalSessionFactory的配置没踩坑
检查你的LocalSessionFactoryBean配置,重点看这两个点:
- 有没有绑定正确的数据源?如果数据源配置错了,你更新的可能是另一个数据库!
- 有没有设置
hibernate.connection.autocommit = false?如果开启了自动提交,会和Spring的事务管理冲突,导致变更不被持久化。
示例配置:
@Bean public LocalSessionFactoryBean sessionFactory(DataSource dataSource) { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setPackagesToScan("com.kk.mypackage"); Properties hibernateProps = new Properties(); hibernateProps.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); hibernateProps.setProperty("hibernate.connection.autocommit", "false"); sessionFactory.setHibernateProperties(hibernateProps); return sessionFactory; }
6. 试试用HQL代替原生SQL(可选)
原生SQL有时候会绕开Hibernate的会话管理,换成HQL的话,Hibernate会更智能地处理事务和同步:
String hql = "UPDATE EmailSaveRequest e SET e.corelationId = :coreId WHERE e.sid = :sid"; int affectedRows = sessionFactory.getObject().getCurrentSession() .createQuery(hql) .setParameter("coreId", "12345") .setParameter("sid", "412") .executeUpdate();
这样也能避免拼接SQL时可能出现的语法错误。
先从这几个方向排查,应该能找到问题所在!
内容的提问来源于stack exchange,提问作者Kovid Kumar

