持久化API(JPA)系列(四)管理器EntityManager--执行数据库更新


        EntityManager是应用访问持久化上下文中的实体的接口,用来对实体Bean进行操作。我们可以使用它来创建、删除、修改持久化的实体,以体现到数据库中;也可以从数据库中查询得到实体或实体列表。所有的这些操作都是通过实体管理器进行的。
本文将首先讲解EntityManager对象的引用方式,然后讲解使用EntityManager的操作函数实现数据库的各种操作,包括以下内容。

持久化实体persist():往数据表中插入数据。

删除实体remove():从数据表中删除记录。

更新实体merge():更新数据表记录。

刷新实体到数据库flush()。

设置Flush刷新模式setFlushMode()。

刷新实体refresh():从数据表中更新。

按主键查询实体find():从数据表中查询记录。

检测实体是否被管理contains()。

分离管理的实体clear()。

技术分享

=============================================================================
1、 EntityManager对象的引用方式
根据实体管理器应用的场景不同,可以将它分为两种类型。
1)容器托管的EntityManager
容器托管的EntityManager对象必须在EJB容器中运行,而不能在Web容器和Java SE环境中运行。前一节的实例中的EntityManager对象就是通过注入@PersistenceContext注释从容器中获得的,这种获得EntityManager对象的方式就是容器托管。这种方式使用起来最简单,开发人员不需要考虑EntityManager对象的创建、事务等复杂问题,所有这些都交给容器去管理。取得该对象的方式如下:
@PersistenceContext(unitName="demo")  
EntityManager em; 
2)应用托管的EntityManager
应用托管的EntityManager对象可以在EJB容器中运行,也可以脱离EJB容器,而与任何的Java环境集成,比如说Web容器、Java SE环境等。它需要开发人员手动地控制它的创建、释放、事务等,这些操作都比较复杂。取得该对象的方式如下:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("demo");  
EntityManager em = emf.getEntityManager(); 


因为我们公司的项目是运行在JBoss这个EJB容器中的,因此采用第一种方式来使用它。


==特点:更新并不会立刻同步到数据库=====================================================

1、持久化实体persist()--往数据表中插入数据
DAO层主要的工作就是将EntityManager管理的实体持久化到数据库中保存起来,即将内存中的实体对象写入到数据表中,在表中反应的是新增了一行记录。
持久化的方法是:
em.persist(obj); 
类似于执行了以下SQL语句:
insert into student(name, sex, age, birthday, telephone, address) values(‘刘中兵‘, 1, 25, ‘1981-05-04‘, ‘12345678‘, ‘北京‘); 

2、删除实体remove()--从数据表中删除记录
当需要删除一个已经被持久化到数据库中的实体对象时
Object obj = em.find(clazz, id);  
em.remove(obj); 
例如:
    Student student = em.find(Student.class, 1);  
    em.remove(student);  
类似于执行了以下SQL语句:
delete from student where id=1; 

3、更新实体merge()--更新数据表记录
更新一个已经被持久化的实体对象
Object updatedObj = em.merge(obj); 
例如: 
    Student student = em.find(Student.class, 1);  
    student.setName("liuzhongbing");  
    em.merge(student);  
类似于执行了以下SQL语句:
update student set name="liuzhongbing" where id=1; 

当执行em.merge(student)方法时,有如下两个执行规则:
    如果此时容器中已经存在一个受容器管理的具有相同id的student实例,则容器将会把参数student的内容复制进这个受管理的实例,merge()方法返回受管理的实例,但参数student仍然是分离的、不受管理的。容器在决定Flush时把实例同步到数据库中。
    容器中不存在具有相同id的student实例。容器根据传进的student参数复制出一个受容器管理的student实例,同时merge()方法会返回出这个受管理的实例,但参数student仍然是分离的、不受管理的。容器在决定Flush时把实例同步到数据库中。


==特点:刷新实体同步到数据库=========================================================
1、刷新实体到数据库flush()
当调用persist()、merge()和remove()这些方法时,更新并不会立刻同步到数据库中,直到容器决定刷新到数据库中时才会执行。在默认情况下,容器决定刷新是在"相关查询"执行前或事务提交时发生的,当然"相关查询"除find()和getReference()之外,这两个方法是不会引起容器触发刷新动作的,如果你需要在事务提交之前将更新刷新到数据库中,你可以直接调用EntityManager.flush()方法。在这种情况下,你可以手动来刷新数据库以获得对数据库操作的最大控制。


当实体正在被容器管理时,你可以调用实体的setXXX()方法对数据进行修改,在容器决定Flush时,更新的数据才会同步到数据库中。如果你希望修改后的数据即时同步到数据库中,则可以执行flush()方法:
em. flush(obj); 
该函数将会做两件事:
提交更改的字段到数据库。
刷新数据库中的字段到该实体中。
例如:
    Student student = em.find(Student.class, 1);  
    student.setName("liuzhongbing");  
    em.flush(student);  

这与上面执行merge()的区别如下。
    提交的对象不同:flush()是将容器管理的对象提交到数据库,而merge()不仅可以提交容器管理的对象,而且可以提交没有被容器管理的对象。
    提交的时机不同:flush()会立即同步到数据库,而merge()只会在容器需要Flush时执行同步。

2、设置Flush刷新模式setFlushMode()
上面的flush()函数是手动调用的,如果不手动调用,则只能依赖于容器的自动刷新。在默认情况下容器是自动刷新的,这是因为它对应了刷新了的AUTO值:
public enum FlushModeType {  
    AUTO,  
    COMMIT  

我们可以调用下面的方法改变刷新模式:
em.setFlushMode(FlushModeType.COMMIT); 
这两种模式的区别如下。
AUTO:刷新在查询语句执行前(除了find()和getreference()查询)或事务提交时才发生,适用于在大量更新数据的过程中没有任何查询语句(除了find()和getreference()查询)时执行。
COMMIT:刷新只有在事务提交时才发生,适用于在大量更新数据的过程中存在查询语句(除了find()和getreference()查询)时执行。
这两种模式的区别体现在数据库底层SQL的执行上,即JDBC驱动跟数据库交互的次数。COMMIT模式使更新只在一次网络交互中完成,而AUTO模式可能需要多次交互,它触发了多少次Flush就产生了多少次网络交互。

==特点:获取数据库最新数据,并同步到实体=================================================
1、刷新实体refresh()--从数据表中更新
如果当前被管理的实体已经不是数据库中最新的数据,则可以通过refresh()方法刷新实体,容器会把数据库中的新值重写进实体:
em. refresh(obj); 
例如: 
    Student student = em.find(Student.class, 1);  
    //如果此时student对应的记录在数据库中已经发生了改变,则可以通过refresh()方法得到最新数据:
    em. refresh(student);  


==特点:从实体中查询数据=========================================================
1、按主键查询实体find()--从数据表中查询记录
一旦将对象持久化到数据库中,它就会产生一个主键,我们可以通过这个主键来查询它。查询的方法很简单,只需要指定要查询的id和查询后对象的实体类,就可以取得该记录的实例。
Object obj = em.find(clazz, id); 
其中clazz为实体Bean的类名。
还有一个方法getReference(),用法与find()方法相同,不同的是当数据库中没有找到记录时,该方法将会抛出异常不同。
例如:
Student student = em.find(Student.class, 1);  
类似于执行了以下SQL语句:
select * from student where id=1; 

==特点:查看、分离被容器管理的实体====================================================
1、检测实体是否被管理contains()
前文中的flush()和merge()分别针对实体是否被容器所管理进行了区分,所谓的被管理,就是实体管理器管理中的实体,没有被管理,就是不在实体管理器容器范围内,即没有经过实体管理器的各种操作函数进行持久化。
实体管理器提供了一个方法contains(),用来检查实体是否被管理。形式如下:
boolean b = em.contains(obj); 
contains()方法使用一个实体作为参数,如果这个实体对象当前正被持久化内容管理,则返回值为true,否则为false。
例如:
    Student student = em.find(Student.class, 1);  
    if (em.contains(person)){  
           //正在被持久化内容管理  
    }else{  
        //已经不受持久化内容管理  
    }  

2、分离管理的实体clear()
当处理了大量的实体后,这些实体都会存在于实体管理器中,这将会消耗大量的内存,使程序运行变慢。如果要减少消耗,则可以使用clear()方法,将正在被管理的实体从持久化内容中分离出来。如下所示:
    em.clear();  
如果调用clear()方法,则之前对实体所做的任何改变都将会被丢失,所以在调用clear()方法之前先调用flush()方法保存更改。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。