在之前的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 接口主要用来创建 EntityManager 实例。该接口约定了如下4个方法:
createEntityManager():用于创建实体管理器对象实例。
createEntityManager(Map map):用于创建实体管理器对象实例的重载方法,Map 参数用于提供 EntityManager 的属性。
isOpen():检查 EntityManagerFactory 是否处于打开状态。实体管理器工厂创建后一直处于打开状态,除非调用close()方法将其关闭。
close():关闭 EntityManagerFactory 。 EntityManagerFactory 关闭后将释放所有资源,isOpen()方法测试将返回 false,其它方法将不能调用,否则将导致IllegalStateException异常。
以下代码省略了entityManager,entityManagerFactory,transaction的创建,关闭等过程
//查询ID为1的Order
Order order = entityManager.find(Order.class, 1);
Order order = entityManager.getReference(Order.class, 1);
System.out.println("-------------------------------------");
System.out.println(order);
这个方法的使用和find()一样,但是有一些区别,看下方运行结果截图:
在代码中,我先调用getReference,然后打印“- - - - - - ”,最后打印order对象
但是从截图看,是先打印“- - - - -”,然后才查询order,接着打印order。
原因:调用getReference()方法,返回的其实并不是order对象,而是一个代理。当你要使用order时,才会真正的调用查询语句来查询order对象
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操作,会抛出异常
相当于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,就可以删除
Order order = new Order();
order.setOrderName("hehe");
Order order2 = entityManager.merge(order);
System.out.println("order2#id:"+order2.getId());
结论:在这种情况下,调用merge方法,将返回一个新的对象(有id),并对这个新的对象执行insert操作。
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的结果是一样的)
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操作。 简单来说,就是更新操作
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的结果一样)
先查看数据库,有一条记录如下:
然后执行以下代码
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个枚举
getFlushMode ():获取持久上下文环境的Flush模式。返回FlushModeType类的枚举值。
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语句
清除持久上下文环境,断开所有关联的实体。如果这时还有未提交的更新则会被撤消。
判断一个实例是否属于当前持久上下文环境管理的实体。
判断当前的实体管理器是否是打开状态。
返回资源层的事务对象。EntityTransaction实例可以用于开始和提交多个事务。
关闭实体管理器。之后若调用实体管理器实例的方法或其派生的查询对象的方法都将抛出 IllegalstateException 异常,除了getTransaction 和 isOpen方法(返回 false)。不过,当与实体管理器关联的事务处于活动状态时,调用 close 方法后持久上下文将仍处于被管理状态,直到事务完成。
创建一个查询对象。
根据命名的查询语句块创建查询对象。参数为命名的查询语句。
使用标准 SQL语句创建查询对象。参数为标准SQL语句字符串。
使用标准SQL语句创建查询对象,并指定返回结果集 Map的 名称。