【问题标题】:why Hibernate Session behavor like this为什么 Hibernate Session 会这样
【发布时间】:2015-04-17 04:18:55
【问题描述】:

我有一个有效的 JUnit 测试代码来测试我的休眠数据库访问代码。对于每个数据库访问方法,我打开一个会话并在finally块内关闭它。一切正常。

现在我想打开一个会话来进行多重访问,让用户/呼叫者/业务模块打开和关闭会话。

所以我的 JUnit 测试代码使用 Session 参数更改如下。而在each数据库访问方法里面,有一个beginTransactioncommit/rollback

//session opened before here
System.out.println("step1, load back userAccount, expect success");
UserAccount user = DataMgmtMgrTest.dataMgr.findUserAccountByTblId(user2Id, errorInfo, session);
Assert.assertNotNull(user);
Assert.assertEquals(user.getUsername(), userName2);
Assert.assertEquals(errorInfo.getCode(), ErrorCode.No_ERROR);

System.out.println("step2, update userAccount, expect fail");
user.setUsername(userName3);
boolean rslt = DataMgmtMgrTest.dataMgr.updateUserAccount(user, errorInfo, session);
Assert.assertFalse(rslt);
Assert.assertNotEquals(errorInfo.getCode(), ErrorCode.No_ERROR);

System.out.println("step3, update userAccount, expect success");
user.setUsername(userName1);
rslt = DataMgmtMgrTest.dataMgr.updateUserAccount(user, errorInfo, session);
Assert.assertTrue(rslt);
Assert.assertEquals(errorInfo.getCode(), ErrorCode.No_ERROR);

System.out.println("step4, load back check, expect true");
UserAccount newUser = new UserAccount();
newUser.setUserAccountTblId(user2Id);
rslt = HibernateDBUtil.refreshFromDB(newUser, session, true, false, errorInfo);
Assert.assertTrue(rslt);
Assert.assertEquals(errorInfo.getCode(), ErrorCode.No_ERROR);
Assert.assertEquals(newUser.getUsername(),userName1);

//session closed after here

我的问题如下:

在第 2 步中,我尝试使用相同的备用键(必须是唯一的)更新现有行,它按预期失败,Hibernate 完成回滚,数据库也很好。

在第 4 步之后,user.setUsername(userName1); 应该将 user 的用户名更改为另一个值 userName1,更新应该会成功完成。但结果是错误的。错误消息告诉我 user 仍然具有第 2 步的值。

我可以在步骤 2 中修改 持久对象用户,但为什么在步骤 3 中不能?

如果我在第 3 步之前关闭会话并在下一行重新打开会话,那么它将起作用。

与第 4 步类似,我创建了一个空的 UserAccount,newUser 并尝试将数据库值刷新到其中。但它的 userName 为空。如果我在这些 Assert.assertXXX() 调用之前关闭会话,那么它将起作用。

这是否意味着我必须为每个数据库访问打开/关闭会话?

【问题讨论】:

    标签: java hibernate orm junit transactions


    【解决方案1】:

    Hibernate Session 应该是discarded once you get an exception:

    如果 Session 抛出异常,事务必须滚动 返回并丢弃会话。 Session的内部状态 异常发生后可能与数据库不一致。

    在您的测试中,您需要使用新的会话,一旦前一个会话产生异常。这模拟了现实生活中的行为,其中异常会破坏当前的业务逻辑并通知用户出现问题。然后,用户无论如何都会使用带有新 Hibernate Session 的新请求。

    【讨论】:

    • 第二种情况如何?我在步骤 3 中的异常之后重新打开了一个新会话,并在步骤 4 中实例化了一个新的空 UserAccount 实例 newUser,只有它的 ID。我调用 session.refresh() 从数据库中获取值,我提交了事务并调用了会话.flush()。但是在我物理关闭会话之前, newUser 仍然是空的。这是正常行为吗?我应该回到一个会话一个数据库访问方法吗?
    • 如果有新实体,你必须调用persist。对于分离的,您可以调用合并。刷新对于分离或托管实体很有用,可以丢弃任何脏更改并重新加载最新的数据库快照。
    猜你喜欢
    • 2018-10-15
    • 2011-06-03
    • 2018-06-08
    • 2014-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多