Session bean or MD bean 对Entity bean的操作(包括所有的query, insert, update, delete操作)都是通过 EntityManager 实例来完成的。 EntityManager 是由 EJB 容器自动地管理和配置的,不需要用户自己创建。
 
那么 Session bean or MD bean 如何获得 EntityManager 实例呢??
非常简单,就是通过下列代码进行依赖注入:
Public class sessionbean1{
@PersistenceContext
EntityManager em;
  。。。
}
 
注意:如果 persistence.xml 文件中配置了多个 <persistence-unit> 。那么在注入 EntityManager 对象时 必须指定持久化名称 ,通过 @PersistenceContext 注释的 unitName 属性 进行指定,例:
 
@PersistenceContext( unitName="foshanshop" )
EntityManager em;
 
如果只有一个 <persistence-unit> ,不需要明确指定。
 
 
请注意:Entity Bean EntityManager 管理时, EntityManager 跟踪他的状态改变,在任何决定更新实体 Bean 的时候便会把发生改变的值同步到数据库中(跟hibernate一样)。但是如果entity Bean EntityManager 分离后,他是不受管理的, EntityManager 无法跟踪他的任何状态改变
 
 
EntityManager 一些 常用的 API (包含 query, insert, update, delete 操作)
 
1) get entity —— find() or getReference()
Person person = em.find(Person.class,1);
/*
try {
Person person = em.getReference (Person.class, 1);
} catch (EntityNotFoundException notFound) {
// 找不到记录 ...
}
*/
当在数据库中 没有找到记录时, getReference() find() 是有区别的 find() 方法会返回 null ,而 getReference() 方法会抛出 javax.persistence.EntityNotFoundException 例外 另外 getReference() 方法不保证entity Bean 已被初始化 。如果传递进 getReference() find() 方法的参数不是实体 Bean ,都会引发 IllegalArgumentException 例外
 
2) insert —— persist()
Person person = new Person();
person.setName(name);
// 把数据保存进数据库中
em.persist(person) ;
 
如果传递进 persist() 方法的参数不是实体 Bean ,会引发 IllegalArgumentException
 
3) update —— 分2种情况
情况1:当实体正在被容器管理时 ,你可以调用实体的 set 方法对数据进行修改,在容器决定 flush 这个由container自行判断),更新的数据才会同步到数据库,而不是在调用了set方法对数据进行修改后马上同步到数据库如果你希望修改后的数据马上同步到数据库,你可以调用 EntityManager.flush() 方法
public void updatePerson() {
try {
Person person = em.find(Person.class, 1);
person.setName("lihuoming"); // 方法执行完后即可更新数据
} catch (Exception e) {
e.printStackTrace();
}
}
 
 
    情况2:在实体 Bean 已经脱离了 EntityManager 的管理时 ,你调用实体的 set 方法对数据进行修改是无法同步更改到数据库的。你必须调用EntityManager.merge()方法。调用之后,在容器决定 flush 这个由container自行判断),更新的数据才会同步到数据库如果你希望修改后的数据马上同步到数据库,你可以调用 EntityManager.flush() 方法
   
public boolean updatePerson(Person person) {
try {
em.merge(person);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
 
下面的代码会调用上面的方法。因为下面的第二行代码把实体 Bean 返回到了客户端,这时的实体 Bean 已经脱离了容器的管理 ,在客户端对实体 Bean 进行修改,最后把他返回给 EJB 容器进行更新操作:
 
PersonDAO persondao = (PersonDAO) ctx.lookup("PersonDAOBean/remote");
Person person = persondao.getPersonByID(1); // 此时的 person 已经脱离容器的管理
person.setName(" 张小艳 ");
persondao.updatePerson(person);
 
执行 em.merge(person) 方法时,容器的工作规则
1>     如果此时容器中已经存在一个受容器管理的具有相同 ID person 实例,容器将会把参数 person 的内容拷贝进这个受管理的实例, merge() 方法返回受管理的实例,但参数 person 仍然是分离的不受管理的。容器在决定 Flush 时把实例同步到数据库中。
 
2> 容器中不存在具有相同 ID person 实例。容器根据传进的 person 参数 Copy 出一个受容器管理的 person 实例,同时 merge() 方法会返回出这个受管理的实例,但参数 person 仍然是分离的不受管理的。容器在决定 Flush 时把实例同步到数据库中。
 
如果传递进 merge () 方法的参数不是实体 Bean ,会引发一个 IllegalArgumentException
 
 
4) Delete —— Remove()
Person person = em.find(Person.class, 2);
// 如果级联关系 cascade=CascadeType.ALL ,在删除 person 时候,也会把级联对象删除。
// cascade 属性设为 cascade=CascadeType.REMOVE 有同样的效果。
em.remove (person);
 
如果传递进 remove () 方法的参数不是实体 Bean ,会引发一个 IllegalArgumentException
 
 
5) HPQL query —— createQuery()
 
除了使用 find() getReference() 方法来获得 Entity Bean 之外,你还可以通过 JPQL 得到实体 Bean
 
要执行 JPQL 语句 ,你必须通过 EntityManager createQuery() createNamedQuery() 方法创建一个 Query 对象
 
Query query = em.createQuery ("select p from Person p where p. name=’ 黎明 ’");
List result = query.getResultList();
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
// 处理 Person
}
// 执行更新语句
Query query = em.createQuery (" update Person as p set p.name =?1 where p. personid=?2");
query.setParameter (1, “ 黎明 ”);
query.setParameter(2, new Integer(1) );
int result = query.executeUpdate() ; // 影响的记录数
// 执行更新语句
Query query = em.createQuery(" delete from Person ");
int result = query.executeUpdate() ; // 影响的记录数
 
 
6) SQL query —— createNaiveQuery()
注意:该方法是针对SQL语句,而不是HPQL语句
 
// 我们可以让 EJB3 Persistence 运行环境将列值直接填充入一个 Entity 的实例,
// 并将实例作为结果返回 .
Query query = em.createNativeQuery ( "select * from person", Person.class );
List result = query.getResultList() ;
if (result!=null){
Iterator iterator = result.iterator();
while( iterator.hasNext() ){
Person person= (Person)iterator.next();
… ..
}
}
// 直接通过 SQL 执行更新语句
Query query = em.createNativeQuery ( "update person set age=age+2" );
query.executeUpdate();
 
 
7) Refresh entity —— refresh()
如果你怀疑当前被管理的实体已经不是数据库中最新的数据,你可以通过 refresh() 方法刷新 实体,容器会把数据库中的新值重写进实体。这种情况一般发生在你获取了实体之后,有人更新了数据库中的记录,这时你需要得到最新的数据当然你再次调用 find() getReference() 方法也可以得到最新数据,但这种做法并不优雅
 
Person person = em.find(Person.class, 2);
// 如果此时 person 对应的记录在数据库中已经发生了改变,
// 可以通过 refresh() 方法得到最新数据。
em.refresh (person);
 
 
8) Check entity 是否在EntityManager管理当中 —— contains()
contains() 方法使用一个实体作为参数, 如果这个实体对象当前正被持久化内容管理,返回值为 true ,否则为 false 。如果传递的参数不是实体 Bean ,将会引发一个 IllegalArgumentException.
 
Person person = em.find(Person.class, 2);
。。。
if ( em.contains(person) ){
// 正在被持久化内容管理
}else{
// 已经不受持久化内容管理
}
 
 
9) 分离所有当前正在被管理的实体 —— clear()
在处理大量实体的时候,如果你不把已经处理过的实体从 EntityManager 中分离出来,将会消耗你大量的内存 调用 EntityManager clear() 方法后,所有正在被管理的实体将会从持久化内容中分离出来 。有一点需要说明下, 在事务没有提交前 事务默认在调用堆栈的最后提交,如:方法的返回 ), 如果调用 clear() 方法,之前对实体所作的任何改变将会掉失,所以建议你在调用 clear() 方法之前先调用 flush() 方法保存更改
 
 
10)             将实体的改变立刻刷新到数据库中 —— flush()
EntityManager 对象在一个 session bean 中使用时,它 是和服务器的事务上下文绑定的。EntityManager在服务器的事务提交时提交并且同步它的内容 。在一个 session bean 中, 服务器的事务默认地会在调用堆栈的最后提交(如:方法的返回)
 
例子1:在方法返回时才提交事务
public void updatePerson(Person person) {
try {
Person person = em.find(Person.class, 2);
person.setName("lihuoming");
em.merge(person);
// 后面还有众多修改操作
} catch (Exception e) {
e.printStackTrace();
}
// 更新将会在这个方法的末尾被提交和刷新到数据库中
}
 
为了只在当事务提交时才将改变更新到数据库中,容器将所有数据库操作集中到一个批处理中,这样就减少了代价昂贵的与数据库的交互。当你调用 persist( ), merge( ) remove( ) 这些方法时,更新并不会立刻同步到数据库中,直到容器决定刷新到数据库中时才会执行 默认情况下,容器决定刷新是在“相关查询”执行前或事务提交时发生,当然“相关查询”除 find() getreference() 之外,这两个方法是不会引起容器触发刷新动作的 默认的刷新模式是可以改变的,具体请
考参下节
 
如果你需要在事务提交之前将更新刷新到数据库中,你可以直接地调用 EntityManager.flush() 方法 。这种情况下,你可以手工地来刷新数据库以获得对数据库操作的最大控制。
public void updatePerson(Person person) {
try {
Person person = em.find(Person.class, 2);
person.setName("lihuoming");
em.merge(person);
em.flush(); // 手动将更新立刻刷新进数据库
 
// 后面还有众多修改操作
} catch (Exception e) {
e.printStackTrace();
}
}
 
 
11)             改变实体管理器的Flush模式 —— setFlushMode()
 
Flush 模式 有2种类型:AUTO and COMMIT。AUTO为缺省模式。 你可以改变他的值,如下:
entityManager.setFlushMode(FlushModeType.COMMIT);
 
FlushModeType.AUTO 刷新在查询语句执行前 ( 除了 find() getreference() 查询 ) 或事务提交时才发生,使用场合:在大量更新数据的过程中没有任何查询语句 ( 除了 find() getreference() 查询 ) 的执行。
 
FlushModeType.COMMIT 刷新只有在事务提交时才发生,使用场合:在大量更新数据的过程中存在查询语句 ( 除了 find() getreference() 查询 ) 的执行。
 
其实上面两种模式最终反映的结果是: JDBC 驱动跟数据库交互的次数 JDBC 性能最大的增进是减少 JDBC 驱动与数据库之间的网络通讯 FlushModeType.COMMIT 模式使更新只在一次的网络交互中完成,而 FlushModeType.AUTO 模式可能需要多次交互(触发了多少次 Flush 就产生了多少次网络交互)
 
12)             获取持久化实现者的引用 —— getDelegate()
 
用过 getDelegate() 方法,你可以获取 EntityManager 持久化实现者的引用 ,如 Jboss EJB3 的持久化产品采用 Hibernate ,可以通过 getDelegate() 方法获取对他的访问,如:
HibernateEntityManager manager = (HibernateEntityManager)em.getDelegate();
 
获得对 Hibernate 的引用后,可以直接面对 Hibernate 进行编码 不过这种方法并不可取,强烈建议不要使用。在 Weblogic 中,你也可以通过此方法获取对 Kodo 的访问。
 
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐