Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate flush:true与手动刷新当前会话有何不同?_Hibernate_Grails_Gorm - Fatal编程技术网

Hibernate flush:true与手动刷新当前会话有何不同?

Hibernate flush:true与手动刷新当前会话有何不同?,hibernate,grails,gorm,Hibernate,Grails,Gorm,我有一个GORM对象,我正在进行集成测试。它有一个beforeUpdate钩子,用于保存以前密码哈希的历史记录。代码如下所示: class Credentials { List passwordHistory = [] String username String password static hasMany = [passwordHistory : String] def beforeUpdate() { // of course

我有一个GORM对象,我正在进行集成测试。它有一个
beforeUpdate
钩子,用于保存以前密码哈希的历史记录。代码如下所示:

class Credentials {
    List passwordHistory = []
    String username
    String password

    static hasMany = [passwordHistory : String]

    def beforeUpdate() {
        // of course I'm not really storing plain-text passwords, but
        // this is just for illustration.
        if (isDirty('password')) { passwordHistory << password }
    }
}
有效,但是

appUser.credentials.password = newPassword
appUser.save()
sessionFactory.currentSession.flush()
AppUser.withNewSession {
    appUser = AppUser.get(appUser.id)
    appUser.credentials.empty // eagerly fetch the list while session is open
}
assert !appUser.credentials.passwordHistory.empty() // is empty

没有。区别在于
appUser.save()
调用中的
flush:true
。我认为调用
save()
会将对象附加到当前会话,但刷新当前会话不会将密码添加到
passwordHistory
列表中。这里到底发生了什么?

如果我正确解释了Grails代码,那么实际上您正在处理两个不同的会话。从文件中:

默认情况下,集成测试在数据库事务内部运行,这 在每个测试结束时回滚。这意味着数据已保存 在测试期间,数据不会持久化到数据库

如果深入研究Grails GORM方法逻辑,您将看到当您在事务中时,GORM会从
ThreadLocal
资源映射中获取其会话,该映射由
TransactionSynchronizationManager
类维护。如果找不到,它将打开一个新会话,并将其绑定到map(重要的区别)上,它将显式打开一个新会话。它不仅仅调用
sessionFactory.getCurrentSession()

save()
GORM逻辑的末尾,如果您传入
flush:true
它将刷新与事务相关联的会话-它从
TransactionSynchronizationManager中的资源映射中获得的会话


另一方面,当您调用
flush()
时,您是在从
sessionFactory.getCurrentSession()
获得的会话上调用它,我相信这是一个从Hibernate
sessionFactory
使用的
CurrentSessionContext
绑定到线程的会话。
CurrentSessionContext
的实际实现并不重要,因为(除非我缺少一个特定于Grails的实现),在第一次刷新会话时,它不会返回由
TransactionSynchronizationManager

持有的相同会话,因此对象变为“脏”。 使用newSession闭包打开新会话时,可以修改对象,但如果要使修改变为“脏”,则必须在新会话中显式调用save()方法。 如果这样做,在关闭闭包后,可以看到在闭包中对对象所做的修改


在withNewSession之前的第二种情况下,对象不是脏的,因此修改对象需要非显式调用,这就是为什么在第二种情况下列表为空的原因。

只是想一想,如果将
get()
更改为
findById()
,会发生什么?快速思考:默认初始值设定项(
…=[]
)对于
密码历史记录
可能会让人困惑。尝试删除此。当然,您还需要更改附加到列表中的方式。还有一个问题:如果使用
addToPasswordHistory(…)
而不是直接附加,行为是否会改变(尽管我不能立即确定原始集合是否支持
addTo
)@Andrew
addToPasswordHistory(…)
似乎为我初始化了此列表,但我没有将其初始化为
[]
,但我注意到会话刷新的相同行为。换句话说,我尝试了你提到的两种情况,但似乎都没有效果。@SérgioMichels我今晚会检查。你知道为什么会有不同吗?
appUser.credentials.password = newPassword
appUser.save()
sessionFactory.currentSession.flush()
AppUser.withNewSession {
    appUser = AppUser.get(appUser.id)
    appUser.credentials.empty // eagerly fetch the list while session is open
}
assert !appUser.credentials.passwordHistory.empty() // is empty