单元测试Hibernate乐观锁定(使用Spring)

时间:2010-03-16 15:43:53

标签: hibernate spring testing

我想编写一个单元测试来验证是否正确设置了乐观锁定(使用Spring和Hibernate)。

我希望测试类扩展Spring的AbstractTransactionalJUnit4SpringContextTests

我想要最终得到的是这样的方法:


@Test (expected = StaleObjectStateException.class) 
public void testOptimisticLocking() {
    A a = getCurrentSession().load(A.class, 1);
    a.setVersion(a.getVersion()-1);
    getCurrentSession().saveOrUpdate(a);
    getCurrentSession().flush();           
    fail("Optimistic locking does not work");
}

此测试失败。你推荐什么作为最佳实践?

我尝试这样做的原因是我想将version转移到客户端(使用DTO)。我想证明当DTO被发送回服务器并与新加载的实体合并时,如果在此期间其他人更新了实体,那么保存该实体将会失败。

3 个答案:

答案 0 :(得分:5)

似乎根本不是将所有字段从DTO(包括版本)转移到新加载的实体,尝试保存它,以及在DTO是DOB时修改实体时获得异常的选项在客户端修改。

原因是Hibernate根本不关心你对版本字段做了什么,因为你在同一个会话中工作。会话会记住版本字段的值。

一个简单的证明:


@Test (expected = StaleObjectStateException.class) 
public void testOptimisticLocking() {
    A a = getCurrentSession().load(A.class, 1);
    getCurrentSession().evict(a); //comment this out and the test fails
    a.setVersion(a.getVersion()-1);
    getCurrentSession().saveOrUpdate(a);
    getCurrentSession().flush();           
    fail("Optimistic locking does not work");
}

无论如何,谢谢大家的帮助!

答案 1 :(得分:2)

你在这里失踪的是

A a1 = getCurrentSession().load(A.class, 1);
A a2 = getCurrentSession().load(A.class, 1);    

System.out.println("the following is true!! " + a1 == a2) ;

Hibernate将为同一会话返回相同类/ id的相同实例。

为了测试乐观锁定尝试一些事情:

A a1 = getCurrentSession().load(A.class, 1);

// update the version number in the db using some sql.
runSql("update A set version = version + 1 where id = 1");

// change object
a1.setField1("Thing");

getCurrentSession().flush(); // bang should get exception here

答案 2 :(得分:1)

使用AbstractTransactionalDataSourceSpringContextTests,您可以这样做(代码取自this thread):

public void testStatelessDetectedOnObjectWithOptimisticLocking () {
    long id = 1l;
    CoffeeMachine cm1 = (CoffeeMachine) hibernateTemplate.get(CoffeeMachine.class, id);
    Session firstSession = hibernateTemplate.getSessionFactory().getCurrentSession();

    endTransaction();

    // Change outside session
    cm1.setManufacturerName("And now for something completely different");

    startNewTransaction();
    Session secondSession = hibernateTemplate.getSessionFactory().getCurrentSe ssion();
    assertNotSame(firstSession, secondSession);

    CoffeeMachine cm2 = (CoffeeMachine) hibernateTemplate.get(CoffeeMachine.class, id);
    cm2.setManufacturerName("Ha ha! Changed by someone else first. Beat you!");

    hibernateTemplate.flush();

    try {
        hibernateTemplate.merge(cm1);
        fail("Stateless should be detected");
    }
    catch (OptimisticLockingFailureException ex) {
    // OK
    }
}

请注意使用 startNewTransaction() (这是此处的关键字)。