Entity Bean (2) : EntityManager [转]
Session bean or MD bean对Entity bean的操作(包括所有的query, insert, update, delete操作)都是通过EntityManager实例来完成的。EntityManager是由EJB 容器自动地管理和配置的,不需要用户自己创建。 那么Session bean or MD bean如何获得EntityManager实例呢??非常
·
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
的访问。
更多推荐
已为社区贡献1条内容
所有评论(0)