EntityManager的find()与getReference()的区别

juint中:

static EntityManager em=null;
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        EntityManagerFactory emf=Persistence.createEntityManagerFactory("jpaPU");
        em=emf.createEntityManager();
    }

1.两种方法:

Person person=em.find(Person.class, 1);
已经经过泛型处理。find方法相当于Hibernate里面的get方法。如果没有找到相应数据,就返回null.

Person person=em.getReference(Person.class,2);
如果这条记录不存在,单单这句话执行不会出错(返回代理)。但当使用person.getName()时会报实体不存在的异常。   相当于Hibernate里面的load方法。而且这种方法是延迟加载的。只有当实际访问实体属性时才到数据库中去执行查询。

Person person=em.getReference(Person.class,1);
    em.close();
    System.out.println(person.getName());
   

此句话会报错,因为person的属性其实没有加载出来。

Person person=em.find(Person.class, 1);

em.close();
System.out.println(person.getName());

而这段可以正确执行,因为person在find的时候就已经获取了相应的属性。

2.更新:

先看JPA里面的实体的状态:

新建、托管、游离、删除

处于托管状态下的实体发生的任何改变当实体管理器关闭的时候都会自动更新到数据库。

注意要更新必须要开启事务

em.getTransaction().begin();

Person person=em.find(Person.class, 1);
em.close();
person.setName("tazi00");

以上是不能成功更新的。以下可以修改。

em.getTransaction().begin();
        Person person=em.find(Person.class, 1);
        person.setName("tazi00");
       em.getTransaction().commit();
        em.close();

 

em.getTransaction().begin();
        Person person=em.find(Person.class, 1);
        em.clear(); //把实体管理器中的所有的实体都变成游离状态
        person.setName("tazi22");
        em.merge(person);
        em.getTransaction().commit();
        em.close();

em.getTransaction().begin();
        Person person=em.find(Person.class, 1);
        em.remove(person); //操作的也必须是持久化状态,或者托管状态的对象
        em.getTransaction().commit();
        em.close();

以下代码会报错

em.getTransaction().begin();
        Person person=new Person();
        person.setId(1);
        em.remove(person);
        em.getTransaction().commit();
        em.close();

java.lang.IllegalArgumentException: Removing a detached instance com.tazi.domin.Person#1

 

 

 

 

 

 

 

 

 

 

 

 

EntityManager的find()与getReference()的区别

 分类:EJB

先说相同点

    这两个方法都接受实体的 class和代表实体主键的对象作为参数。由于它们使用了Java泛型方法,无需任何显示的类型转换即可获得特定类型的实体对象。其中,在primaryKey上面普遍使用了java5的autoboxing(自动装箱)的特性。

    再者,就是两者都会在EntityManager关闭的情况下抛出IllegalStateException - if this EntityManager has been closed. 在传入的第一个参数不是实体或者第二个参数不是一个有效的主键的情况下抛出

IlegalArgumentException - if the first argument does not denote an entity type or the second argument is not a valid type for that entity's primary key

 

 

不同点:

    find()返回指定OID的实体,如果这个实体存在于当前的persistence context中,那么返回值是被缓存的对象;否则会创建一个新的实体,并从数据库中加载相关的持久状态。如果数据库不存在指定的OID的记录,那么find()方法返回null。

    getReference()方法和find()相似。不同的是:如果缓存中没有指定的实体,EntityManager会创建一个新的实体,但是不会立即访问数据库来加载持久状态,而是在第一次访问某个属性的时候才加载。此外,getReference()方法不返回null,如果数据库找不到相应的实体,这个方法会抛出javax.persistence.EntityNotFoundException。

EntityNotFoundException - if the entity state cannot be accessed

某些场合下使用getReference()方法可以避免从数据库加载持久状态的性能开销。

 

   这里要着重提出的是两句话:

   如果缓存中没有指定的实体,EntityManager会创建一个新的实体,但是不会立即访问数据库来加载持久状态,而是在第一次访问某个属性的时候才加载。

   比如,em.find()返回的实体,我们就可以对它进行各种操作,而若对em.getReference()返回的实体,由于不会立即访问数据库来加载持久状态,对它进行的操作很可能就会出现Exception,比如在对它返回的实体做getter操作时,由于EntityManager对此采用延时加载,就会抛出org.hibernate.lazyinitializationexception could not initialize proxy no session

   因此将一个新的实体传递给事务的时候通常使用find()方法,而当不连接数据库,不使用getter方法,即使用setter方法改变状态时才使用getReference()方法。(这是由于getReference返回是一个Proxy实体,即没有加载持久状态)

 

   某些场合下使用getReference()方法可以避免从数据库加载持久状态的性能开销。

    这也完全是由于getReference返回是一个Proxy实体.

    比如一个简单的update操作,先使用find()获取实体,而后使用实体的setter方法;或者是getReference()方法,而后使用实体的setter方法。

    对于前者JPA调用的SQL:select ****,而后才是update ****

    对于后者:仅为update *****

 

又如:

操作                                                                            执行的SQL

em.remove(em.getReference(Person.class,1))         delete from Person where personid = 1

em.remove(em.find(Person.class,1))                 select * from Person where personid =1

                                                   delete from Person where personid =1

 

   由此可以看出,find()做了一次select的操作,而getReference并没有做有关数据库的操作,而是返回一个代理,这样它就减少了连接数据库和从数据库加载持久状态的开销。

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值