【发布时间】:2017-10-19 10:28:02
【问题描述】:
我的休眠配置:
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.hbm2ddl.auto", "validate");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.id.new_generator_mappings", "false");
properties.put("hibernate.connection.autocommit", "true");
properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.put("hibernate.connection.url", DBConnection.url);
properties.put("hibernate.connection.username", DBConnection.username);
properties.put("hibernate.connection.password", DBConnection.password);
代码示例:
// pattern 1
Session s = sessionFactory.openSession();
ObjectA A = s.load(ObjectA.class, pk);
A.setAttr("abc");
s.update(A);
s.close();
// pattern 2
Session s = sessionFactory.openSession();
s.beginTransaction();
ObjectA A = s.load(ObjectA.class, pk);
A.setAttr("abc");
s.update(A);
s.close();
// pattern 3
Session s = sessionFactory.openSession();
Transaction tx = s.beginTransaction();
ObjectA A = s.load(ObjectA.class, pk);
A.setAttr("abc");
s.update(A);
tx.commit();
s.close();
请忽略我的编译错误。我在 Web 应用程序中使用休眠(没有spring),并且没有使用事务,因为我使用的是MySql 数据库和MySql autocommit 是真的,所以反过来,在休眠中,我将其设置为@987654327 @true 也是。 (我也在使用mysql-connector-java-5.1.23-bin.jar)。
三种模式,我只能得到模式3的作品。我现在完全糊涂了。我有几个问题:
1) 我不明白为什么模式 1 不起作用,我所有的 select(通过休眠 CriteriaBuilder 或 load)和 insert(通过休眠 session.save)都有效,但只有更新不起作用没用。
2) 好的,然后我尝试使用模式 2 之类的事务,我的休眠 auto-commit 是真的,所以我假设当我关闭会话时,事务应该自动提交,但它不起作用。为什么?
3) 模式 3 有效,为什么我需要事务管理器?我希望jdbc在每个事务中执行每个查询(一个事务中一个sql),我不担心性能,但我必须在此处包含事务,为什么?
对于模式1和2,我发现update脚本甚至没有生成(基于hibernate日志),问题不是因为脚本生成但提交失败。不明白为什么?请帮忙...
PS:
经过反复试验,总结一些要点以供将来参考:
1) Hibernate 只会在调用session.flush() 而不是tx.commit() 时生成sql 脚本,并且必须在事务块中调用session.flush()。没有事务,就会导致异常。如果刷新模式为自动,则不需要显式刷新,commit() 将触发刷新。
2) Hibernate Transaction 不等同于数据库事务,经过一些尝试,我发现,如果 hibernate autocommit 为 false,是的,它们在功能上是等效的,并且通过 JDBC 生成相应的begin transaction 脚本并发送到数据库(只是我的猜测)。如果 hibernate autocommit 为 true,则不会启动 begin transaction,尽管我们在 hibernate Transaction tx = s.beginTransaction() 中声明了它,所有查询都将自动提交,rollback 将不起作用。
3)我的情况的原因,session.save()(还有select)在没有事务的情况下工作,这有点特别,因为必须触发save才能获得表标识符(主键)和所以即使没有flush也会生成sql脚本。
4) 对于模式 2,我误会了,autocommit 不代表autocommit upon session closed,它的真正含义应该是autocommit upon each sql reach database。所以模式 2 不起作用,因为没有tx.commit,这意味着没有刷新,所以没有生成 sql 脚本。 (tx.commit 是否会在session.close 上自动调用,这取决于供应商的实现,有些会回滚。)
结论,在Hibernate中无论如何都需要事务块。
【问题讨论】:
-
我的猜测是 Hibernate 本身并不处于自动提交模式,尽管您已经设置了
hibernate.connection.autocommit连接字符串。顺便说一句,将 Hibernate 设置为自动提交模式可能不是一个好主意,因为如果出现问题,它不会回滚任何东西。
标签: java mysql hibernate jakarta-ee transactions