想象一下,Grails 2.5.5应用程序中有以下控制器:
def index() {
bookService.method()
Book bako = Book.findById(4)
System.out.println(bako.title);
}
在bookService(使用Grails默认事务管理)中,您有以下方法:
class BookService
def method() {
Book bako = Book.findById(4)
System.out.println(bako.title);
// MANUAL UPDATE OF DB HAPPENS HERE
Book bako = Book.findById(4)
System.out.println(bako.title);
}
}
并且你的数据库确实有一本名为4的书叫做#34;指环王"。
如果你在所有System.out.println()上设置了断点,并且在执行了第一个findById之后,你手动编辑该对象的标题"哈利波特和火焰杯",我预料到:
但是,输出将始终是处于开头状态的对象。
更新:输出为:
The Lord Of The Rings
The Lord Of The Rings
The Lord Of The Rings
如果在任何情况下修改了控制器,为了:
def index() {
bookService.method()
Book.withNewTransaction {
Book bako = Book.findById(4)
System.out.println(bako.title);
}
}
结果仍然相同。
更新:输出为:
The Lord Of The Rings
The Lord Of The Rings
The Lord Of The Rings
仅在将其修改为:
时def index() {
bookService.method()
Book.withNewSession {
Book bako = Book.findById(4)
System.out.println(bako.title);
}
}
是否会产生正确的行为。
更新:输出为:
The Lord Of The Rings
The Lord Of The Rings
Harry Potter and the Goblet of Fire
有人可以解释一下原因:
答案 0 :(得分:1)
首先应使用Book bako = Book.findById(4)
findById,在极少数情况下请参考Book.get(1L) Book.load(1L) Book.read(1L)
当您刚刚运行.get
实际问题
经过多次讨论,无论服务多么具有交易性。如果您决定手动使用mysql更新数据库。你将破坏hibernate缓存。您可以尝试停用 - 首先/ second level cache。首先,如果您在域类映射中声明了缓存。
这实在是不明智,会对应用程序产生影响。现实是交易服务应该为您做更新。如果需要手动更新数据库。停止应用更新/启动应用。这真的很简单
有一个原因让我试图让你沿着尝试使用示例项目尝试此场景的路线。
为什么? 因为它有助于回答任何猜测。我已经获取了您的示例项目的副本,并在演示中添加了一些实际的记录更新。 https://github.com/vahidhedayati/grails-transactions
我还在您的版本上发出了拉取请求,因此您可以将其合并并在本地进行测试。
基本上flush:true
不是必需的。 .get(id)不是必需的。
从下面的结果中可以看出,在方法1上的.save()之后的服务中,结果已更新。在控制器中,它在服务返回后使用method()返回正确的结果。
-- transactions.Book : 1 1 added
| Server running. Browse to http://localhost:8080/transactions
2016-09-05 18:12:48,520 [http-bio-8080-exec-4] DEBUG hibernate.SQL - select book0_.id as id1_0_0_, book0_.version as version2_0_0_, book0_.title as title3_0_0_ from book book0_ where book0_.id=?
--method1: before update: ------------------------------> TITLE_SET_BY_BOOTSTRAP
--method1 before get: ---------------------------------> New title from method1
method1 after get: ----------------------------------> New title from method1
2016-09-05 18:12:48,618 [http-bio-8080-exec-4] DEBUG hibernate.SQL - update book set version=?, title=? where id=? and version=?
After service1 call 1 New title from method1
--method2 update: ------------------------------> New title from method1
2016-09-05 18:12:48,687 [http-bio-8080-exec-4] DEBUG hibernate.SQL - update book set version=?, title=? where id=? and version=?
--method2 before get: --------------------------> New title from method2
method2 after get: ----------------------------> New title from method2
After service call 2 New title from method2
--method3 before update: ---------------------------> New title from method2
2016-09-05 18:12:48,795 [http-bio-8080-exec-4] DEBUG hibernate.SQL - update book set version=?, title=? where id=? and version=?
--method3 updated before get: -------------------------> New title from method3
--method3 after get: -----------------------------------> New title from method3
After service call 3 New title from method3
在审核了用户问题的年龄,并了解到他们手动更新了DB记录,然后期望屏幕显示相同的结果。
简而言之,如果你没有在应用程序中启用缓存,那么是的,它应该全部工作。如果你启用了某种形式的Hibernate缓存或ehcache,那么很可能你会看到一些缓存对象。我曾建议重新启动应用程序以确保您拥有最新版本。但如果你只是:
换一个
DomainClass.withNewTransaction {
//get the latest copy
DomainClass clazz = DomainClass.get(recordId)
println "-- ${clazz.value}"
}
这应该确保您从数据库中获取最新信息,它不会提高速度,但是如果您期望手动数据库更新,您可以始终确保最新的更新...