您的位置:首页 > 数据库

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

2015-07-22 16:24 441 查看
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()方法保存更改。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: