我正在使用grails 2.5.3
我的配置如下:
grails {
hibernate {
cache.queries = true
cache.use_second_level_cache = true
cache.use_query_cache = true
cache.provider_class = 'net.sf.ehcache.hibernate.SingletonEhCacheProvider'
我有域类:
class AuthorizedDevice implements JSONFormat {
int id
String authKey = generateAuthKey()
String owner
String name
String permittedUsers
String userAgent
Date lastVisit
Date lastInitialized
String lastUser
String lastIpAddress
Date dateCreated
boolean enabled = true
String notes
static constraints = {
authKey(blank: false, unique: true, maxSize: 8)
owner(blank: false, validator: GormValidators.isCorpUserName)
name(blank: false, unique: 'owner')
permittedUsers(nullable: true, validator: permittedUsersValidator)
userAgent(nullable: true, maxSize: 500)
lastVisit(nullable: true)
lastInitialized(nullable: true)
lastUser(nullable: true, maxSize: 50)
lastIpAddress(nullable: true, maxSize: 50)
notes(nullable: true, maxSize: 500)
}
def auditService
def afterInsert() {auditService.noteDeviceChange('Created Device', id)}
def afterUpdate() {auditService.noteDeviceChange('Updated Device', id)}
def afterDelete() {auditService.noteDeviceChange('Deleted Device', null)} // Not allowed by GUI, but just in case.
public Object formatForJSON() {
return [
id: id,
authKey: authKey,
owner: owner,
name: name,
permittedUsers: permittedUsers,
userAgent: userAgent,
lastVisit: lastVisit,
lastInitialized: lastInitialized,
lastUser: lastUser,
lastIpAddress: lastIpAddress,
enabled: enabled,
notes: notes
]
}
//------------------
// Implementation
//------------------
private String generateAuthKey() {
....
}
static permittedUsersValidator = {String val, Object obj, Errors errors ->
if (!val || val.trim().equals('*')) return
val.split(',').each {
if (!getCorprUser(it.trim())) {
errors.rejectValue('permittedUsers', '',
"Unknown User ${it}. Use a comma-delimited list of usernames or * to indicate all users."
)
}
}
}
}
我构建了一个设备列表,如:
def devices = AuthorizedDevice.list()
我注意到每次调用AuthorizedDevice.list()时,GORM / hibernate都会对表中的每一行执行一次SQL查询。
我们在模型字段中没有会产生N + 1个查询的任何关联。
即使没有关联,有人知道是什么促使这种N + 1行为吗?
第一次调用.list()时,以下SQL只运行一次:
select
this_.id as id4_0_,
this_.version as version4_0_,
this_.auth_key as auth3_4_0_,
this_.date_created as date4_4_0_,
this_.enabled as enabled4_0_,
this_.last_initialized as last6_4_0_,
this_.last_ip_address as last7_4_0_,
this_.last_user as last8_4_0_,
this_.last_visit as last9_4_0_,
this_.name as name4_0_,
this_.notes as notes4_0_,
this_.owner as owner4_0_,
this_.permitted_users as permitted13_4_0_,
this_.user_agent as user14_4_0_
from
authorized_device this_
每次调用.list()之后,都会为表中的每一行运行此SQL:
select
authorized0_.id as id4_0_,
authorized0_.version as version4_0_,
authorized0_.auth_key as auth3_4_0_,
authorized0_.date_created as date4_4_0_,
authorized0_.enabled as enabled4_0_,
authorized0_.last_initialized as last6_4_0_,
authorized0_.last_ip_address as last7_4_0_,
authorized0_.last_user as last8_4_0_,
authorized0_.last_visit as last9_4_0_,
authorized0_.name as name4_0_,
authorized0_.notes as notes4_0_,
authorized0_.owner as owner4_0_,
authorized0_.permitted_users as permitted13_4_0_,
authorized0_.user_agent as user14_4_0_
from
authorized_device authorized0_
where
authorized0_.id=?
答案 0 :(得分:1)
https://dzone.com/articles/pitfalls-hibernate-second-0
如果查询缓存了结果,则会返回实体ID列表 然后针对二级缓存解析。如果实体用 那些没有配置为可缓存的ID或它们已过期的ID 然后,select将按实体Id命中数据库。
例如,如果缓存的查询返回1000个实体ID,而非 那些缓存在二级缓存中的实体,然后是1000 将通过Id选择将针对数据库发出。
此问题的解决方案是配置查询结果到期 与...返回的实体的到期一致 查询。
在您的情况下,解决方案可能只是添加到AuthorizedDevice:
static mapping = { cache true }
为了在域类AuthorizedDevice上启用二级缓存(hibernate默认不启用它)。
因为它似乎是第一个sql日志的结果,所以你给出了:
select
this_.
...
from
位于缓存中(查询缓存)。所以它没有被执行两次。在我给出的链接中,解释了结果被缓存为实体ID列表。但并非每个实体的所有数据都在缓存中,只有ids。 然后在对.list()的另一个调用期间,hibernate会在缓存中有这些id,并且会尝试在二级缓存中检索相应的实体,但是它会失败,然后hibernate会对每个ID的数据库进行查询。 / p>