Grails 3.2.8升级至3.3.3后角色更新出现ValidationErrors问题求助
解决Grails 3.3.3中Spring Security角色更新时的ValidationErrors问题
你遇到的这个问题确实和Grails 3.3.x版本中Hibernate会话的flush行为变化有关,这也是框架升级后常见的事务处理差异。
问题根源
在Grails 3.2.8中,执行UserRole.removeAll(userInstance)后,Hibernate会自动在后续数据库操作前刷新会话,确保删除操作同步到数据库和缓存。但升级到3.3.3后,默认的事务刷新策略调整了——删除操作只会标记为待执行,不会立即刷新会话。这就导致:
- 数据库里的UserRole关联已经被删除,但Hibernate的一级缓存中还保留着旧的关联实例
- 当你调用
UserRole.create()时,Hibernate先检查缓存,误以为角色关联还存在,从而抛出「角色已存在」的ValidationErrors - 最终结果就是角色被全部移除,但新角色无法添加,页面显示为空
解决方案:手动触发会话刷新
在UserRole.removeAll()执行后,强制刷新Hibernate会话,确保删除操作立即生效。有两种简单的实现方式:
方式一:通过UserRole的会话刷新
修改你的updatepermission方法,在删除后添加会话刷新逻辑:
@Transactional def updatepermission(User userInstance) { if (userInstance == null) { notFound() return } // 删除所有旧角色关联 UserRole.removeAll(userInstance) // 强制刷新会话,确保删除操作同步到缓存和数据库 UserRole.withSession { session -> session.flush() } // 添加选中的新角色 params.authorities.each { roleId -> // 这里加上flush:true,进一步确保每次创建都生效 UserRole.create(userInstance, Role.get(roleId), true) } springSecurityService.clearCachedRequestmaps() request.withFormat { form multipartForm { flash.message = message(code: 'default.updated.message', args: [message(code: 'user.label', default: 'User'), userInstance.id]) redirect(controller: "user", action: "permission", id: userInstance.id) return } '*' { respond userInstance, [status: OK] } } }
方式二:通过用户实例的save操作触发刷新
如果方式一不生效,也可以尝试在删除后保存用户实例并强制flush:
UserRole.removeAll(userInstance) userInstance.save(flush: true, failOnError: true)
额外建议
- 可以检查
UserRole类的removeAll方法实现,确认它是否在新版本中没有自动flush(默认生成的removeAll方法通常不会自动触发flush) - 如果你批量添加多个角色,在
UserRole.create()时加上flush:true虽然会增加数据库交互,但能避免批量操作中的缓存不一致问题
内容的提问来源于stack exchange,提问作者Bilgehan
相关产品推荐
相关产品推荐

