Hibernate persist方法报错:无法修改列,疑与数据库触发器有关
这个问题的核心矛盾点在于:手动写INSERT能成功,但Hibernate的persist操作却触发了计算列不可修改的错误,结合你给出的信息,我给你拆解下可能的原因和解决办法:
1. Hibernate生成的INSERT语句包含了计算列TABLE_FIELD
这是最常见的原因。你手动执行INSERT时,肯定没有把TABLE_FIELD这个计算列写到INSERT语句里,所以SQL Server不会去修改它;但Hibernate默认会把实体类中所有映射的字段都包含到INSERT语句中——哪怕你给这个字段传的是NULL,它还是会生成类似INSERT INTO table (...) VALUES (... , NULL, ...)的语句,而SQL Server明确禁止修改计算列,哪怕赋值NULL也不行。
验证方式:
开启Hibernate的SQL日志,把org.hibernate.SQL的日志级别设为DEBUG,这样就能看到Hibernate实际生成的INSERT语句,对比你手动执行的SQL,就能确认是不是多了TABLE_FIELD这一列。
解决办法:
在实体类中对应TABLE_FIELD的字段上添加注解:
@Column(name = "TABLE_FIELD", insertable = false, updatable = false) private String tableField;
insertable = false告诉Hibernate插入时不要把这个列包含到INSERT语句里,updatable = false则是更新时也忽略它,完全交给数据库维护这个计算列。
2. 触发器导致的异常(你猜测的方向是对的)
如果上面的方法没用,那大概率是表上的触发器在搞事情。比如触发器可能在插入操作后,试图去更新TABLE_FIELD这个计算列,或者触发器的逻辑里错误地把这个列包含进了UPDATE语句中,导致SQL Server抛出错误。
验证方式:
临时禁用该表上的所有触发器,然后再用Hibernate执行persist操作,如果不报错了,就坐实是触发器的问题。禁用触发器的SQL是:
DISABLE TRIGGER ALL ON [你的表名];
测试完记得重新启用:
ENABLE TRIGGER ALL ON [你的表名];
解决办法:
检查触发器的代码,找到其中试图修改TABLE_FIELD的逻辑,把这部分操作删掉——因为计算列是数据库自动计算的,不需要触发器去修改它。
3. 额外补充:为什么传NULL没触发预期的NULL错误?
因为Hibernate生成的INSERT语句先触发了“计算列不可修改”的错误,这个错误优先级比NULL约束更高,所以SQL Server先抛出了这个错误,你就看不到预期的NULL报错了。
内容的提问来源于stack exchange,提问作者iv18

