JPA学习笔记(5)——EntityManager相关

Persistence

在之前的JPA学习笔记(2)——创建JPA项目,有使用到Persistence来创建EntityManagerFactory实例

String persistenceUnitName = "jpa"; 
EntityManagerFactory factory = Persistence.createEntityManagerFactory(persistenceUnitName);

其实它还有一个重载方法可用

Map<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.format_sql", false);
EntityManagerFactory factory= Persistence.createEntityManagerFactory(persistenceUnitName,properties);

这里的properties,和配置文件persistence.xml中的属性是一样的。

这里写图片描述

EntityManagerFactory

EntityManagerFactory 接口主要用来创建 EntityManager 实例。该接口约定了如下4个方法:

  1. createEntityManager():用于创建实体管理器对象实例。

  2. createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。

  3. isOpen():检查 EntityManagerFactory 是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。

  4. close():关闭 EntityManagerFactory 。 EntityManagerFactory 关闭后将释放所有资源,isOpen()方法测试将返回 false,其它方法将不能调用,否则将导致IllegalStateException异常。

EntityManager

以下代码省略了entityManager,entityManagerFactory,transaction的创建,关闭等过程

find方法

//查询ID为1的Order
Order order = entityManager.find(Order.class, 1);

getReference方法

Order order = entityManager.getReference(Order.class, 1);
System.out.println("-------------------------------------");
System.out.println(order);

这个方法的使用和find()一样,但是有一些区别,看下方运行结果截图:

这里写图片描述

在代码中,我先调用getReference,然后打印“- - - - - - ”,最后打印order对象

但是从截图看,是先打印“- - - - -”,然后才查询order,接着打印order。

原因:调用getReference()方法,返回的其实并不是order对象,而是一个代理。当你要使用order时,才会真正的调用查询语句来查询order对象

persist方法

Order order = new Order();
order.setOrderName("hehe");
entityManager.persist(order);
System.out.println("id="+order.getId());

执行insert操作,相当于hibernate的save()方法

从上面代码中可以看到,我们并没有给order一个id,但是在执行persist方法之后,没有从数据库查询,order.getId()也可以获取到值。这也是persist方法的一个功能:使对象由临时状态变为持久化状态。

结果截图:
这里写图片描述

但是和hibernate的save()方法有些不同:如果对象有id,则不能执行insert操作,会抛出异常

remove方法

相当于hibernate的delete()方法,但是有些不同:

remove()方法不能移除游离对象,只能移除持久化对象,什么意思呢?对比下面两段代码:

Order order = new Order();
order.setId(140);
entityManager.remove(order);

上面这段代码会抛出异常,因为order是我们自己创建的对象,也就是游离对象

必须这样写:

Order order = new Order();
order = entityManager.find(Order.class, 140);
entityManager.remove(order);

这段代码中的order是从数据库中获取的,也就是持久化对象

hibernate的delete()方法,只要对象有Id,就可以删除

merge方法

情况1:传入的对象没有id

Order order = new Order();
order.setOrderName("hehe");
Order order2 = entityManager.merge(order);
System.out.println("order2#id:"+order2.getId());

这里写图片描述

结论:在这种情况下,调用merge方法,将返回一个新的对象(有id),并对这个新的对象执行insert操作。

情况2:传入的对象有id,entityManager的缓存中没有该对象,数据库中没有该记录

Order order = new Order();
order.setId(1000);
order.setOrderName("hehe");
Order order2 = entityManager.merge(order);
System.out.println("order#id:"+order.getId());
System.out.println("order2#id:"+order2.getId());

这里写图片描述

结论:在这种情况下,调用merge方法,将返回一个新的对象,并对该对象执行insert操作。新对象的id是数据库中这条记录的id(比如自增长的id),而不是我们自己传入的id。(其实和情况1的结果是一样的)

情况3:传入的对象有id,entityManager的缓存没有该对象,数据库中有该记录

Order order = new Order();
order.setId(170);
order.setOrderName("wahahahahah");
Order order2 = entityManager.merge(order);
System.out.println("order:"+order);
System.out.println("order2:"+order2);

调用前数据库表:

这里写图片描述

调用后结果:

这里写图片描述

这里写图片描述

结论:在这种情况下,调用merge方法,将会从数据库中查询对应的记录,生成新的对象,然后将我们传入的对象复制到新的对象,最后执行update操作。 简单来说,就是更新操作

情况4:传入的对象有id,entityManager的缓存有该对象

Order order = new Order();
order.setId(170);
order.setOrderName("xixixixi");
//通过find来将对象读入entityManager缓存
Order order3 = entityManager.find(Order.class, 170);
Order order2 = entityManager.merge(order);
System.out.println("order:"+order);
System.out.println("order2:"+order2);

结果和情况3一样,就不截图了。

结论:在这种情况下,调用merge方法,JPA会把传入的对象赋值到entityManager的缓存中的对象,然后对entityManager缓存中的对象执行update操作。(和情况3的结果一样)

flush方法

先查看数据库,有一条记录如下:

这里写图片描述

然后执行以下代码

Order order= entityManager.find(Order.class, 170);
System.out.println("order:"+order);
order.setOrderName("bbb");
//5. 提交事务
transaction.commit();

查看结果:
这里写图片描述

这里写图片描述

结果发现,JPA居然执行了update操作,把aaa改成了bbb,但是在代码中我们并没有执行update操作啊。

原因:order是通过find方法查询出来的,因此它是持久化对象,也就是说它缓存在entityManager中,当事务提交时,缓存将会被更新到数据库。

而flush方法,可以强制将缓存更新到数据库

entityManager.flush();

与之相关:

  • setFlushMode (FlushModeType flushMode):设置持久上下文环境的Flush模式。参数可以取2个枚举

    • FlushModeType.AUTO 为自动更新数据库实体,
    • FlushModeType.COMMIT 为直到提交事务时才更新数据库记录。
  • getFlushMode ():获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。

refresh方法

Order order= entityManager.find(Order.class, 170);
order= entityManager.find(Order.class, 170);

运行以上代码,发现调用了两次find,但是只执行了一次select语句,这是缓存导致的。

这里写图片描述

再看下面的代码:

Order order= entityManager.find(Order.class, 170);
entityManager.refresh(order);

只调用了一次find方法,却执行了两次select语句,这是因为refresh方法会去查看缓存中的数据状态和数据库中是否一致,因此又执行了一次select语句

这里写图片描述

clear ()

清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。

contains (Object entity):

判断一个实例是否属于当前持久上下文环境管理的实体。

isOpen ()

判断当前的实体管理器是否是打开状态。

getTransaction ()

返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。

close ()

关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出 IllegalstateException 异常,除了getTransaction 和 isOpen方法(返回 false)。不过,当与实体管理器关联的事务处于活动状态时,调用 close 方法后持久上下文将仍处于被管理状态,直到事务完成。

createQuery (String qlString)

创建一个查询对象。

createNamedQuery (String name)

根据命名的查询语句块创建查询对象。参数为命名的查询语句。

createNativeQuery (String sqlString)

使用标准 SQL语句创建查询对象。参数为标准SQL语句字符串。

createNativeQuery (String sqls, String resultSetMapping)

使用标准SQL语句创建查询对象,并指定返回结果集 Map的 名称。

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值