背景,目前在作的項目有孩子跟家長兩個表,一孩子對多家長的關係。主鍵id都是自增java
若是須要給已經存在的孩子添加一個新家長的時候,會出現org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.kids.pt.entity.Kid;mysql
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.kids.pt.entity.Kidspring
異常信息就是你須要保存一個kid,save()方法調用的時候id不爲null,由於手動配置了id以後保存的時候數據庫又是自增主鍵,因此會出錯。sql
而後項目dao裏面一頓找沒有找到saveOrUpadate()之類的可用,而後一直百度發現原來jpa裏面的persist()方法跟merge()方法就是相似於save()跟saveOrUpadate()的關係數據庫
/*如下內容來自百度*////////////////////////////////////////////////////////////////////////////////////////////////////////spa
persist(),是保存,跟save()方法同樣,知識jpa官方說叫persist比較好一些,更接近持久化的含義。而merge()是合併的意思,就是當你保存的實體,根據主鍵id劃分,若是已存在,那麼就是更新操做,若是不存在,就是新增操做。
persist會把傳進去的實體放到持久化上下文中,此時若是持久化上下文中有了這個實體,就會拋出javax.persistence.EntityExistsException,沒有的話事務提交的時候把那個對象加進數據庫中,若是數據庫中已經存在了那個對象(那一行),就會拋出com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
而merge會在持久化上下文中生成傳進去的實體的受管版本,若是已經有了受管版本,那也不會拋出異常,而後把那個受管的實體返回出來,事務提交的時候若是數據庫中不存在那個對象(那一行),就把把那個受管的加進去,存在的話就替換掉原來的數據。merge是若是持久化上下文中有了受管版本,那就更新,沒有就複製一份,返回受管的。
再次總結persist(①,②-③,④-⑤):
(這裏說的拋出的異常都是指對象(或者數據庫中的行)重複的異常)
① 若是persist的是一個受管實體(即已經在上下文中),就不會拋出異常。
②若是persist的是一個遊離實體(即上下文中沒有它),而上下文中又沒有它的受管版本,數據庫中也沒有,也不會拋出異常,而會把這個實體寫進數據庫中。
③若是persist的是一個遊離實體(即上下文中沒有),而上下文中又沒有它的受管版本,數據庫卻有這個實體,那麼EntityManager在persist它的時候不會拋出異常,可是事務提交的時候就會拋出異常:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '7' for key 1;
④若是persist的是一個遊離實體(即上下文中沒有),而上下文中卻有它的受管版本,數據庫中又沒有這個實體,那麼仍是不會拋出異常,而是把它的受管版本加進去(不是那個遊離的,是那個受管的!)(即,這種狀況persist和沒persist是同樣的!)。
⑤若是persist的是一個遊離實體(即上下文中沒有),而上下文中卻有它的受管版本,數據庫中也有了這個實體,那麼EntityManager在persist它的時候就會拋出異常:javax.persistence.EntityExistsException
而merge就不會拋出什麼對象重複的異常的了。。
hibernate