如果我们在休眠中开始事务但不提交它会发生什么?

时间:2014-12-11 10:38:15

标签: java database hibernate orm

如果我们在hibernate中开始事务,然后做一些事务但不提交它会发生什么? 它会拯救它还是会立即回滚?

由于 阿赫亚

2 个答案:

答案 0 :(得分:4)

查看以下代码,该代码使用事务边界访问数据库,而不使用commit:

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

默认情况下,在具有JDBC配置的Java SE环境中,如果您执行此代码段会发生这种情况:

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

    未提交的交易会怎样?

  5. 该问题的答案是,“它取决于!”在连接上调用close()时,JDBC规范没有提及有关挂起事务的任何信息。发生的情况取决于供应商如何实施规范。例如,使用Oracle JDBC驱动程序,对close()的调用将提交事务!当JDBC Connection对象关闭并且资源返回到池时,大多数其他JDBC供应商采用理智的路由并回滚任何挂起的事务。

    显然,这对你执行的SELECT不会有问题,但请看这个变化:

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

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

答案 1 :(得分:0)

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

当尝试关闭一个打开事务的会话时,默认情况下hibernate不会调用关闭连接代理(如果你想改变这个你需要定义--hibernate.ejb.discard_pc_on_close是真的)

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() )