Hibernate session.update如果不在事务

时间:2017-05-19 10:22:40

标签: java mysql hibernate java-ee transactions

我的hibernate配置:

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应用程序中使用了hibernate(没有spring),并且没有使用事务,因为我使用MySql数据库并且MySql autocommit是真的,所以反过来, hibernate,我也将autocommit设为true。 (我也在使用mysql-connector-java-5.1.23-bin.jar

三种模式,我只能得到模式3的作品。我现在完全糊涂了。我在下面几个问题:

1)我无法理解为什么模式1不起作用,我的所有select(通过休眠CriteriaBuilderload)和insert(通过hibernate {{ 1}})有效,但只有更新不起作用。

2)好的然后我尝试使用类似模式2的事务,我的hibernate session.save是真的,所以我假设当我关闭会话时,事务应该自动提交但它不起作用。为什么呢?

3)模式3有效,为什么我需要事务管理器?我希望auto-commit在每个事务中执行每个单独的查询(在一个事务中一个sql),我不担心性能,但我必须在这里包含事务,为什么?

对于模式1和模式2,我发现甚至没有生成jdbc脚本(基于休眠日志),问题不在于脚本生成但提交失败。不明白为什么?请帮忙......

PS:

在经过一些试验和错误之后,只需将一些要点包括在内以供将来参考:

1)Hibernate只会在调用update但不调用session.flush()时生成sql脚本,并且必须在Transaction块中调用tx.commit()。没有交易,就会导致例外。如果刷新模式为自动,则不需要显式刷新,session.flush()将触发刷新。

2)Hibernate Transaction不等同于数据库事务,经过一些尝试,我发现,如果hibernate autocommit为false,是的,它们在功能上是等价的,并且相应的commit()脚本是通过JDBC生成并发送到数据库(我的猜测)。如果hibernate autocommit为true,虽然我们在休眠begin transaction中声明它,但没有启动begin transaction,所有查询都将自动提交,Transaction tx = s.beginTransaction()将不起作用。

3)我的案例的原因rollback(以及session.save())在没有交易的情况下工作,它有点特殊,因为必须触发select才能获得表格标识符(主键),因此即使没有刷新也会生成sql脚本。

4)对于模式2,我错过了解,自动提交并不意味着save,它的真正含义应该是autocommit upon session closed。因此模式2不起作用,因为没有autocommit upon each sql reach database,这意味着没有刷新,因此不会生成sql脚本。 (tx.commit是否会在tx.commit时自动调用,它取决于供应商的实现,有些将会回滚。)

结论,Hibernate中需要Transaction block而不管是什么。

1 个答案:

答案 0 :(得分:2)

我觉得你有点混乱。事务(org.hibernate.transaction)不完全是数据库事务。 当您刷新Session(Session.flush)以在单个db事务中绑定指令时,hibernate使用此类Object。换句话说,不要将Hibernate Session与DB会话混淆,但不要将hibernate Sessio与db连接混淆。 最重要的是,通过具体的hibernate生成sql代码,仅用于hibernate事务之间的内容。这就是为什么模式A和B不起作用并且不生成sql代码的原因。更具体地说,模式B中的自动提交没有影响,因为从不生成sql cod。此外,根据hibernate的最佳实践,即使是简单的选择指令,您也必须记住打开和关闭事务。顺便说一下,即使没有交易,选择也应该有效,但是你可能会有一些麻烦。

为了更好地理解我们可以恢复架构的概念:

  • hibernate session:是一个容器,它将你的hibernate对象和你的db操作保存为java对象,以及许多其他东西。 hibernate事务:是一个引用hibernate会话的事务对象。
  • db connection:是您与DB的连接
  • conenction pool:是一组db连接。

刷新会话时的appen可以通过以下步骤恢复:

  1. 从连接池获取连接
  2. 为每个承诺 您的会话中的事务是从池中获取数据库连接, 生成sql命令并将其发送到DB
  3. 将数据库连接放回池中
  4. 这只是一个小小的回顾,但希望对此有所帮助 河