//实体A
obj_table{
`id` bigint(20) NOT NULL,
`name` varchar(48) NOT NULL,
...
PRIMARY KEY (`id`)
}
//实体B
obj_childObj_table{
`id` bigint(20) NOT NULL,
`index` int(11) NOT NULL COMMENT '下标,如1,2,..',
...
PRIMARY KEY (`id`,`index`)
}
B.id = A.id
场景:
A1 A1_B
A2 A2_B
实体对象A1被A2替换,更新所有信息后,需要更新子对象B的信息(A1_B被A2_B替换,但A1_B.id不变)
做法是:直接更新A2_B的id为A1.id A2_B.setId(A1.id);
结果:
Hibernate抛出异常
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
原因分析:
B.id和B.index构成联合主键,但是在更新A的子对象B时,重新设置了主键B.id 然后updateModel(A2_B);
hibernate不能直接用实体去修改主键,所以抛出异常
可能原因:
a. 网上查到其他可能造成此异常的原因:
当执行更新或删除数据库时,数据库中已不存在这条数据。
b. 此外,之前还猜测是Session一级缓存与数据库不一致造成,更新前使用Session.flush()清除一级缓存 也可以
session.Clear() 是把一级缓存里面的东西清除掉(保留session)
session.Flush(让缓存和数据库当中做到一致)
但是修改后运行结果异常偶现,涉及Hibernate更新实体原理,学完再来补
解决办法:
正确做法应该是新建一个B对象,拷贝A2_B对象属性,设置id为A1.id;
(旧的A1_B可以删掉或者忽略不管)
B newB = new B();
PropertyUtils.copyProperties(newB, A2_B);
newB.setId(A1.id);
saveModel(newB);