在bookService中(使用Grails默认事务管理),您有以下方法:
class BookService def method(){ Book bako = Book.findById(4) System.out.println(bako.title); //手动更新DB HAPPENS HERE Book bako = Book.findById(4) System.out.println(bako.title); $ b $ p $ b而且你的db有一本书id为4称为指环王。
如果您在所有System.out.println()中设置了断点,并且在第一次执行findById之后,你手动编辑该对象的标题哈利波特与火焰杯,我预料:
但是,输出始终是处于开始时处于相同状态的对象。
更新:输出结果为:
指环王指环王指环王如果在任何情况下您修改了控制器,以便:
def index(){ bookService.method() Book.withNewTransaction { Book bako = Book.findById(4) System.out.println(bako.title); }}
结果仍然是一样的。
更新:输出结果为:
仅当您将其修改为: def index(){ bookService.method() Book.withNewSession { Book bako = Book.findById(4) System.out.println(bako.title); }}
更新:输出结果为:
<$ p $ 指环王指环王哈利波特与火焰杯有人可以解释为什么:
当您可以运行 .get时,您正在启动查询以查找id
实际值起诉
经过多番讨论,无论服务是多少交易。如果您决定手动更新数据库。你会打破休眠缓存。您可以尝试禁用 - 首先/ second级高速缓存。首先,如果你在你的域类映射中声明了缓存。
这是非常不明智的,会对应用程序产生影响。现实是交易服务应该为你做更新。如果您需要手动更新数据库。停止应用程序更新/启动应用程序。这真的很简单
我之所以试图用示例项目来试图推断这种情况,有一个原因。
为什么? 因为它有助于回答任何猜测。我已将您的示例项目的副本添加到演示中并添加了一些实际记录更新。 github/vahidhedayati/grails-transactions
我也对您的版本提出了拉取请求,因此您可以合并并在本地进行测试。
基本上 flush:true 不需要。 .get(id)不是必需的。
正如您从方法1中的.save()之后服务中的结果中看到的那样,结果已更新。在控制器中,它在服务返回后使用方法()返回了正确的结果。
- transactions.Book:1 1添加了 |服务器运行。浏览到http:// localhost:8080 / transactions 2016-09-05 18:12:48,520 [http-bio-8080-exec-4] DEBUG hibernate.SQL - 选择book0_.id作为id1_0_0_,book0_。 version2_0_0_,book0_.title as title3_0_0_ from book book0_ where book0_.id =? --method1:更新前:------------------------------> TITLE_SET_BY_BOOTSTRAP - 获得之前的方法1:--------------------------------->从method1获得新标题 method1获取后:---------------------------------->方法1新标题 2016-09-05 18:12:48,618 [http-bio-8080-exec-4] DEBUG hibernate.SQL - 更新书集版本=?,title =?其中id =?和版本=? service1调用后1方法1的新标题 --method2更新:----------------------------- - >方法1的新标题 2016-09-05 18:12:48,687 [http-bio-8080-exec-4] DEBUG hibernate.SQL - 更新书集版本=?,title =?其中id =?和版本=? --method2获得之前:-------------------------->从method2获得新标题 method2获得后:---------------------------->来自method2的新标题服务调用后2来自method2的新标题 - 更新前的方法3:------------------------ --->从method2新标题 2016-09-05 18:12:48,795 [http-bio-8080-exec-4] DEBUG hibernate.SQL - 更新书集版本=?,title =?其中id =?和版本=? --method3更新之前获取:------------------------->从method3获得新标题 --method3获得后:-----------------------------------> ;来自method3的新标题服务电话之后3来自method3的新标题查看用户问题并且了解到他们手动更新数据库记录,然后期待屏幕显示相同的结果。
总之,如果您在应用程序中没有启用缓存,那么是的应该都可以工作。如果您启用了某种形式的Hibernate缓存或ehcache,那么很可能您会查看某个缓存对象。我曾建议重新启动应用程序以确保您拥有最新版本。但如果你只是简单地说:
换行
DomainClass.withNewTransaction { //获取最新副本 DomainClass clazz = DomainClass.get(recordId) println - $ {clazz.value}}这应该可以确保您从数据库中获得最新的信息,但这不会提高速度,但如果您期待手动数据库更新,你总是可以确保最新的是高于..
Imagine you have the following controller in a Grails 2.5.5 application:
def index() { bookService.method() Book bako = Book.findById(4) System.out.println(bako.title); }And inside the bookService (with Grails default transaction management) you have the following method:
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); } }And that your db does have a Book with id 4 called "The Lord of The Rings".
If you then set breakpoints on all System.out.println() and, after the first findById has been executed, you manually edit the title of that object to "Harry Potter and the Goblet of Fire", I expected:
- Both findById(4) in bookService.method() to read the same value, after all, they were performed in isolation in the same transaction, and if that transaction read it in that state, the second one should read it too.
- The findById(4) performed in the controller to already see the new state of the object, after the manual update. After all, the first transaction has already commited, and this second find, even if done outside a service, should create a new transaction.
However, the output will always be the object in the same state it was at the beginning.
Update: The output is:
The Lord Of The Rings The Lord Of The Rings The Lord Of The RingsIf, in any case, you modifiy the controller, in order to:
def index() { bookService.method() Book.withNewTransaction { Book bako = Book.findById(4) System.out.println(bako.title); }}
The result is still the same.
Update: The output is:
The Lord Of The Rings The Lord Of The Rings The Lord Of The RingsOnly if you modify it to:
def index() { bookService.method() Book.withNewSession { Book bako = Book.findById(4) System.out.println(bako.title); }}
does the correct behavior ensue.
Update: The output is:
The Lord Of The Rings The Lord Of The Rings Harry Potter and the Goblet of FireCan someone explain me why:
解决方案
Firstly Book bako = Book.findById(4) findById should be used in rare cases refer to Book.get(1L) Book.load(1L) Book.read(1L)
You are firing up a query to look for id when you could have just run .get
Actual issue
After much talk, no matter how much a service is transactional. If you decide to update the DB using mysql manually. You will break hibernate cache. You can try disabling - first / second level cache. First being if you declared caching in your domain class mapping.
This is really unwise and will have application impact. The reality is a transaction service should be doing the updates for you. If you need to manually update the database. Stop the app update / start the app. It is really that simple
There is a reason why I have been trying to push you down the route of attempting this scenario using an example project.
Why ? Because it helps answer any speculation. I have taken a copy of your sample project and added some actual record updates to the demo. github/vahidhedayati/grails-transactions
I have also made a pull request on your version so you can merge it and test it locally.
Basically flush:true not required. .get(id) not required.
As you can see from the results below In service after .save() on method 1 the results was updated. In controller it returned the correct result using method() after service returned it.
-- transactions.Book : 1 1 added | Server running. Browse to 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 method3After reviewing the user issue ages back and having understood that they were manually updating DB record then expecting screen to show the same result.
In short if you have no cache enabled in the application then yes it should all work. If you have some form of Hibernate cache or ehcache enabled then it is likely you will be looking at some cache object. I had suggested restarting application to ensure you have latest. But if you simply:
wrap a
DomainClass.withNewTransaction { //get the latest copy DomainClass clazz = DomainClass.get(recordId) println "-- ${clazz.value}" }This should ensure you are getting the very latest from the DB, it isn't going to be speed efficient but if you are expecting manual db updates you could always ensure the latest is above..
更多推荐
Grails交易和会话
发布评论