1

我一直试图让 GORM 在集成测试中抛出乐观锁定错误。之前有人说过,如果不使用多个线程,就不可能测试并发更新错误,但即便如此,我发现我的测试用例的行为令人惊讶:

void testOptimisticLocking() {

    new Widget(foo:"bar").save(flush:true)

    // Get the widget and change a property
    def widget = Widget.findByFoo("bar")
    assertNotNull widget
    widget.foo = "baz"
    def widgetVersion = widget.version
    println "widget: $widgetVersion"   // >>>  widget: 0

    // Discard the widget without saving; Hibernate now knows nothing about it
    widget.discard()

    // Get a different instance of the same widget from the database,
    // with the old value for foo
    def sameWidget = Widget.findByFoo("bar")
    assertNotNull sameWidget
    assertFalse System.identityHashCode(sameWidget) == System.identityHashCode(widget)

    // Change the foo property and save
    sameWidget.foo = "bat"
    sameWidget.save(flush:true)

    // Check the version has incremented
    println "sameWidget: $sameWidget.version"         // >>>  sameWidget: 1
    assertTrue widgetVersion < sameWidget.version

    // Check the database hold the "bat" widget
    sameWidget.discard()
    assertEquals 0, Widget.countByFoo("bar")
    assertEquals 1, Widget.countByFoo("bat")

    // Reattach the original widget and try to save it
    assertFalse widget.isAttached()
    widget.attach()
    println "widget: $widget.version"            // >>>  widget: 0
    assertEquals widgetVersion, widget.version
    assertEquals "baz", widget.foo

    // TEST FAILS HERE
    // No error is thrown, and the update fails silently!
    shouldFail(org.hibernate.StaleStateException) {
        assertTrue widget.validate()
        widget.save(flush:true)
        println widget.foo              // >>>  baz
        widget.discard()
        println "baz: " + Widget.countByFoo("baz")    // >>>  baz: 0
        println "bat: " + Widget.countByFoo("bat")    // >>>  bat: 1
    }



}

重新挂载的Widget实例不会持久化到数据库中,但不会抛出异常!

我的测试用例相当做作,但我仍然对结果感到惊讶。

有人可以解释一下吗?

4

0 回答 0