Grails 4多数据源配置:assigned主键生成器失效求助
首先,你的配置思路是对的,但多数据源下的全局映射配置有时候会因为优先级或者绑定方式的问题,没被正确应用到front数据源的保存操作上。下面我给你拆解问题原因和可行的解决方案:
为什么当前配置没生效?
你在application.groovy里设置的grails.gorm.front.mapping全局配置,理论上应该对front数据源的所有域类生效,但Grails在处理多数据源的全局映射时,偶尔会出现配置没有正确绑定到域类的情况——尤其是当域类没有明确声明属于某个数据源时,Hibernate可能还是 fallback 到默认的identity生成器,导致保存到front时不包含ID列。
可行的解决方案
1. 在域类中针对数据源明确配置主键策略(最可靠)
直接在你的域类的mapping块里,分别为back和front数据源指定主键生成器,这样优先级最高,不会出现配置冲突:
class MyObject { Long id // 你的其他属性... static mapping = { // 为back数据源配置identity生成器 id generator: 'identity', datasource: 'back' // 为front数据源配置assigned生成器 id generator: 'assigned', datasource: 'front' } }
这种方式直接把每个数据源的规则绑定到域类,Hibernate在处理myObject.front.save()时,会明确使用assigned策略,自动将ID包含到INSERT语句中。
2. 调整全局配置的写法
如果你更倾向于全局配置,建议用grails.gorm.mappings的多数据源写法,这种方式比分开的default和单个数据源配置更清晰,也能避免优先级问题:
grails.gorm.mappings = { datasource('back') { id generator: 'identity' } datasource('front') { id generator: 'assigned' } }
这种写法会把不同数据源的映射规则明确区分开,Grails能更准确地加载对应数据源的配置。
3. 确保保存时对象ID已正确赋值
虽然你是从back复制对象过来,但还是要确认myObject.id不为null——因为assigned生成器要求必须手动设置ID值,如果ID为null,Hibernate依然不会把ID列加入SQL语句。你可以在保存前加个简单验证:
if (!myObject.id) { throw new IllegalArgumentException("对象ID不能为空,无法保存到front数据源") } myObject.front.save(flush: true)
4. 检查基类的映射配置
如果你的MyObject继承自某个通用基类(比如BaseDomain),要确认基类的mapping块没有设置全局的主键生成器,否则会覆盖子类或者数据源的配置。如果基类有配置,需要在基类中也按数据源区分主键策略。
验证方法
修改配置后,打开Hibernate的SQL日志,再次执行保存操作,观察生成的INSERT语句是否包含id列。如果看到类似INSERT INTO my_object (id, ...) VALUES (?, ...)的语句,说明配置生效了。
内容的提问来源于stack exchange,提问作者laure

