統合テストで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 の再アタッチされたインスタンスはデータベースに永続化されませんが、例外はスローされません!
私のテストケースはかなり不自然ですが、それでも結果には驚かされます。
誰でもこれを説明できますか?