异常1:org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
异常2:org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [prework.suzhou.pojos.Book#12]
@Test
public void test(){
Book book1 = new Book();
book1.setBookName("傲慢与偏见");
//book1.setBookId(12l);
Book book2 = new Book();
book2.setBookName("哈姆雷特");
//book2.setBookId(12l);
List books = new ArrayList();
books.add(book1);
books.add(book2);
ResourceEntity entity = new ResourceEntity();
entity.setResourceEntityName("外国文学");
entity.setBooks(books);
Session session = sf.getCurrentSession();
session.beginTransaction();
//session.save(book1); ……………………….1
//session.save(book2);………………………..2
session.save(entity);
session.flush();
session.getTransaction().commit();
}
在保存ResourceEntity时级联保存book1。如果级联保存,而book1,book2有一个或两个都设置了id,那么会报第一个异常。
如果book1,book2都设置了id且相等,那么就会报告著名的异常 a different object with the same identifier value was already associated with the session 。为什么说著名,因为这个异常对于初学者来说太常见了,而且很难解决。
网上有一些解决方法,比如merge(),session.clear()…….。其实这些方法并不是很好的解决方案,反而有点蒙蔽自己双眼的感觉。
用merge()是可以的,
Hibernate: insert into ResourceEntity (parentNodeId, resourceEntityName) values (?, ?)
Hibernate: select book0_.bookId as bookId0_0_, book0_.bookName as bookName0_0_ from Book book0_ where book0_.bookId=?
Hibernate: insert into Book (bookName) values (?)
Hibernate: select book0_.bookId as bookId0_0_, book0_.bookName as bookName0_0_ from Book book0_ where book0_.bookId=?
Hibernate: insert into Book (bookName) values (?)
Hibernate: insert into ResourceEntity_Book (ResourceEntity_resourceEntityId, books_bookId) values (?, ?)
Hibernate: insert into ResourceEntity_Book (ResourceEntity_resourceEntityId, books_bookId) values (?, ?)
但是Hibernate对于有疑问的book表会先去查,再插入(merge的时候,hibernate对于级联操作时,被级联的对象如果设置了id,会对其先做select操作)。
其实出现这个问题的原因就是两个book的id设置为一样的,而且又是级联插入!级联的save,两个book对象会同时纳入session管理,出现了相同的id,所以就报错了。
如果我一个一个save(),不级联,book1,book2的id不管怎么设置都无效,hibernate会根据你数据库分配的id分别重新设置book1,book2的id,所以它们的id是不会重的。
所以我们完全可以避开这个异常,对于要级联插入的实体,它们的id是数据库分配的。我们只要避免为它们分配id,就可以避免以上两个异常。如果不可避免的有id,那个在保存前setId(null)就不会出错了。
其实这个问题还是要归结到session的管理方式上~~