persist()方法和save()方法对detached态对象的支持

来源:互联网 发布:pure codec for mac 编辑:程序博客网 时间:2024/06/06 00:44
persist()方法不支持detached对象
  • 不管是detached形式一(session close造成),还是detached形式二(new对象 ,setId造成),
  • 不管是在同一事务中(显然同一事务,只支持形式二),还是不同事务中(不同事务支持形式一和二)


同一事务中的操作:

1.Many对象和One对象操作在同一事务中时,
One 对象为持久化对象,
Many对象可正常通过persist()存储入库
        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope71");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");

                DvdType tType = (DvdType) session1.get(DvdType.class, 15);
                QualityType qType =(QualityType) session1.get(QualityType.class, 15);

                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();
            
mysql> select * from DvdTable1;
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
| id | datetime            | description | diskvolume | name        | photo | dvdType_id | qualityType_id |
| 13 | 2010-06-11 21:43:28 | no          |         27 | rope71      | no    |         15 |             15 |
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
11 rows in set (0.00 sec)

2.Many对象和One对象操作在同一事务中时,
One 对象为Transicent对象
Many对象可正常通过persist()存储入库,(同时One对象存储入库)
        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope72");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");

                DvdType tType = new DvdType();
                QualityType qType = new QualityType();
                
                tType.setName("new1");
                qType.setName("new1");
                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();

mysql> select * from DvdTable1;
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
| id | datetime            | description | diskvolume | name        | photo | dvdType_id | qualityType_id |
| 15 | 2010-06-11 21:49:39 | no          |         27 | rope72      | no    |         18 |             18 |
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
13 rows in set (0.01 sec)

mysql> select * from QualityType;
+----+---------------+
| id | name          |
+----+---------------+
| 18 | new1          |
+----+---------------+
17 rows in set (0.00 sec)

mysql> select * from DvdType;
+----+------------+
| id | name       |
+----+------------+
| 18 | new1       |
+----+------------+
17 rows in set (0.00 sec)
3.Many对象和One对象操作在同一事务中时,
One 对象为new对象,但有转成persist对象的资格(其id值对应库表中的存在id),即其符合第二种detached态,它不是trancient 态.
Many对象通过persist()存储入库时,抛出detached entity passed to persist异常

        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope73");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");
                
                DvdType tType = new DvdType();
                tType.setId(2);

                QualityType qType = new QualityType();
                qType.setId(2);
                
                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();

org.hibernate.PersistentObjectException: detached entity passed to persist: com.machome.model.DvdType



不同事务中的操作:

4.Many对象和One对象操作在不同事务中时,
One 对象为Trancient对象
Many对象可通过persist()存储入库

        DvdType tType = new DvdType();
        tType.setName("typetemp 6");

        QualityType qType = new QualityType();
        qType.setName("qualitytemp 6");
            
        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope74");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");

                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();

mysql> select * from DvdTable1;
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
| id | datetime            | description | diskvolume | name        | photo | dvdType_id | qualityType_id |
| 16 | 2010-06-11 22:07:09 | no          |         27 | rope74      | no    |         19 |             19 |
+----+---------------------+-------------+------------+-------------+-------+------------+----------------+
14 rows in set (0.00 sec)


mysql> select * from DvdType;
| 19 | typetemp 6 |


mysql> select * from QualityType;
| 19 | qualitytemp 6 |

5.Many对象和One对象操作在不同事务中时,
One 对象为Persist对象转为detected对象(事务结束)
Many对象通过persist()存储入库时,抛出detached entity passed to persist异常


        Session session = sf.getCurrentSession();
        Transaction tran = session.beginTransaction();
        
        DvdType tType = (DvdType) session.get(DvdType.class, 15);
        QualityType qType =(QualityType) session.get(QualityType.class, 15);
        
        tran.commit();  事务结束
        
        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope73");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");

                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();


org.hibernate.PersistentObjectException: detached entity passed to persist: com.machome.model.DvdType
 
6.Many对象和One对象操作在不同事务中时,
One 对象为new对象,但有转成persist对象的资格(其id值对应库表中的存在id),即其符合第二种detached态,它不是trancient 态.
Many对象通过persist()存储入库时,抛出detached entity passed to persist异常

        DvdType tType = new DvdType();
        tType.setId(2);

        QualityType qType = new QualityType();
        qType.setId(2);
    
        Session session1 = sf.getCurrentSession();
            Transaction tran1 = session1.beginTransaction();
            
                DvdTable1 dvd = new DvdTable1();
                dvd.setName("rope74");
                dvd.setDiskvolume(27);
                dvd.setDatetime(new Date());
                dvd.setDescription("no");
                dvd.setPhoto("no");

                dvd.setDvdType(tType);
                dvd.setQualityType(qType);

                session1.persist(dvd);
                                
            tran1.commit();

org.hibernate.PersistentObjectException: detached entity passed to persist: com.machome.model.DvdType

结论:
对于Many2One One2Many里,对象里包含另一个对象的属性的情况
persist()限制较大,这"另一个对象"必须和当前对象在同一事务中,而且不能符合detached第二种形式(即id不能和数据库中有匹配,即必须是一个新对象)


既然persist()这么多限制,为什么很多场合还要用它而不是save()?
  • 1.persist() 方法更标准,是JPA的标准CRUD方法,可移植性高
比如你在hibernate,JPA,EJB都可采用JPA的标准Annotation, 对persist()方法的支持就比save(),saveOrUpdate()要好.

  • 2.persist()在数据安全性上更可靠
标准文档有如下描述:
persist() also guarantees that it will not execute an INSERT statement if it is
called outside of transaction boundaries. This is useful in long-running conversations
with an extended Session/persistence context.A method like persist() is required.
persist()保证当它在一个transaction外部被调用的时候并不触发一个Sql Insert,这个功能是很有用的,
当我们通过继承Session/persistence context来封装一个长会话流程的时候,一个persist这样的函数是需要的。

比如一个长会话长事务,有可能触发事务的timeout(通常设为几十秒),这样save()很可能发生前事务已经结束(假设没设事务timeout 回滚的话),而这时save()仍然能执行,而这时persist()就无法执行,相对更安全
阅读全文
0 0
原创粉丝点击