【问题标题】:What will happen if we begin transaction in hibernate but do not commit it?如果我们在休眠中开始事务但不提交会发生什么?
【发布时间】:2015-02-09 19:34:33
【问题描述】:

如果我们在休眠中开始事务,然后执行一些事务但不提交,会发生什么? 它会临时保存还是立即回滚?

谢谢 车坦

【问题讨论】:

  • 我觉得你可以自己试试,对吧?
  • 除非您提交,否则数据库不会发生任何更改。
  • 每个事务都会有一定的空闲时间将操作数据存储在堆内存中。如果不采取任何行动,一旦到达空闲时间,它将被销毁。
  • 它还取决于事务类型和 DBMS。我遇到过这样一种情况,即到 Oracle 数据库的分布式事务被中断(服务器被残忍地关闭),导致事务在数据库端保持“打开”状态,直到管理员强行附加它——一直锁定涉及的表。
  • Jonjongot - 是的,我试过了。遇到了 Gimby 解释的一些疯狂场景。一般如果发生这种情况(由于代码错误或其他原因),解除锁定的理想解决方案是什么???

标签: java database hibernate orm


【解决方案1】:

它依赖于 hibernate-config 和连接池配置。

当尝试关闭带有打开事务的会话时,默认情况下休眠不会调用关闭连接代理(如果要更改此设置,则需要定义 - hibernate.ejb.discard_pc_on_close true)

public void close() {
    if ( !open ) {
        throw new IllegalStateException( "EntityManager is closed" );
    }
    if ( !discardOnClose && isTransactionInProgress() ) {

现在,假设您定义了discard_pc_on_close,而在这种情况下,hibernate 将调用关闭连接代理(连接池包装连接),所以现在我们取决于连接池如何实现这一点。 你可以在 NewPooledConnection 中看到 c3p0 的实现。 您会看到它依赖于这个标志 - FORCE_IGNORE_UNRESOLVED_TXNS(默认为 false),因此默认情况下它将重置事务。

static void resetTxnState( Connection pCon, 
               boolean forceIgnoreUnresolvedTransactions, 
               boolean autoCommitOnClose, 
               boolean txnKnownResolved ) throws SQLException
{
if ( !forceIgnoreUnresolvedTransactions && !pCon.getAutoCommit() )

【讨论】:

    【解决方案2】:

    看下面的代码,不使用commit就访问有事务边界的数据库:

    Session session = sessionFactory.openSession();
    session.beginTransaction(); 
    session.get(Item.class, 123l); 
    session.close(); 
    

    默认情况下,在带有 JDBC 配置的 Java SE 环境中,如果你执行这个 sn -p 会发生这种情况:

    1. 新会话已打开。它没有获得数据库连接 这一点。
    2. 如果需要新的基础交易,请开始交易。 否则在现有的范围内继续新的工作 基础交易
    3. 调用 get() 触发 SQL SELECT。会话现在获得一个 来自连接池的 JDBC 连接。休眠,默认情况下, 立即关闭此连接上的自动提交模式 设置自动提交(假)。这有效地启动了一个 JDBC 事务!
    4. SELECT 在这个 JDBC 事务中执行。会议是 关闭,连接返回池并由 Hibernate — Hibernate 在 JDBC 连接上调用 close()。

      未提交的事务会发生什么?

    这个问题的答案是,“视情况而定!”当在连接上调用 close() 时,JDBC 规范没有说明待处理的事务。会发生什么取决于供应商如何实施规范。例如,对于 Oracle JDBC 驱动程序,对 close() 的调用会提交事务!大多数其他 JDBC 供应商在 JDBC Connection 对象关闭并将资源返回到池中时,会采取理智的方式并回滚任何待处理的事务。

    显然,这对于您执行的 SELECT 来说不是问题,但看看这个变体:

    Session session = getSessionFactory().openSession(); 
    session.beginTransaction();
    Long generatedId = session.save(item); 
    session.close(); 
    

    此代码生成一个 INSERT 语句,该语句在从未提交或回滚的事务中执行。在 Oracle 上,这段代码永久插入数据;在其他数据库中,可能不会。(这种情况稍微复杂一些:只有在标识符生成器需要时才执行INSERT。例如,可以从没有INSERT的序列中获取标识符值。持久化然后实体被排队,直到刷新时插入——这在这段代码中永远不会发生。身份策略需要立即 INSERT 才能生成值。)

    【讨论】:

    • 你错了默认情况下hibernate不会调用关闭连接代理。看我的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 2016-08-15
    • 1970-01-01
    • 2014-12-04
    • 2016-12-26
    • 2018-05-06
    相关资源
    最近更新 更多