为什么 Hibernate Session 的行为是这样的
why Hibernate Session behavor like this
我有一个有效的 JUnit 测试代码来测试我的休眠数据库访问代码。对于每个数据库访问方法,我打开一个Session并关闭 它在 finally 块中的末尾。一切正常。
现在我想打开一个会话进行多路访问并让user/caller/business模块打开和关闭会话。
所以我的JUnit测试代码改成如下,加上一个Session参数。在 each 数据库访问方法中,有一个 beginTransaction 和 commit/回滚.
//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 的 userName 更改为另一个值,userName1,更新应该成功完成。但结果是错误的。错误消息告诉我 user 仍然具有步骤 2 的值。
我可以在第 2 步中修改持久对象、用户,但为什么不能在第 3 步中修改?
如果我在第 3 步之前关闭会话并在下一行重新打开会话,那么它将起作用。
与第 4 步类似,我创建了一个空的 UserAccount,newUser 并尝试将数据库值刷新到其中。但其 userName 为空。如果我在这些 Assert.assertXXX() 调用之前关闭会话,那么它将起作用。
这是否意味着每次数据库访问我都必须 open/close 会话?
Hibernate Session 应该是 discarded once you get an exception:
If the Session throws an exception, the transaction must be rolled
back and the session discarded. The internal state of the Session
might not be consistent with the database after the exception occurs.
在你的测试中你需要使用一个新的会话,一旦前一个会话产生了异常。这模拟了现实生活中的行为,异常会破坏当前的业务逻辑并通知用户出现了问题。然后,用户无论如何都会使用新的请求和新的 Hibernate Session。
我有一个有效的 JUnit 测试代码来测试我的休眠数据库访问代码。对于每个数据库访问方法,我打开一个Session并关闭 它在 finally 块中的末尾。一切正常。
现在我想打开一个会话进行多路访问并让user/caller/business模块打开和关闭会话。
所以我的JUnit测试代码改成如下,加上一个Session参数。在 each 数据库访问方法中,有一个 beginTransaction 和 commit/回滚.
//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 的 userName 更改为另一个值,userName1,更新应该成功完成。但结果是错误的。错误消息告诉我 user 仍然具有步骤 2 的值。
我可以在第 2 步中修改持久对象、用户,但为什么不能在第 3 步中修改?
如果我在第 3 步之前关闭会话并在下一行重新打开会话,那么它将起作用。
与第 4 步类似,我创建了一个空的 UserAccount,newUser 并尝试将数据库值刷新到其中。但其 userName 为空。如果我在这些 Assert.assertXXX() 调用之前关闭会话,那么它将起作用。
这是否意味着每次数据库访问我都必须 open/close 会话?
Hibernate Session 应该是 discarded once you get an exception:
If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs.
在你的测试中你需要使用一个新的会话,一旦前一个会话产生了异常。这模拟了现实生活中的行为,异常会破坏当前的业务逻辑并通知用户出现了问题。然后,用户无论如何都会使用新的请求和新的 Hibernate Session。