📄 openjpa.htm
字号:
<BR>88. @PostRemove <BR>89. public void logPostRemove() {
<BR>90. System.out.println("Animal[" + id + "," + name + "]
已经从数据库中删除。"); <BR>91. }
<BR><BR><BR>我们可以使用下面的客户端代码完成实体的增加、查找、修改、删除工作: <BR><BR>清单 2.
实现实体的增加、查找、修改、删除的代码 <BR><BR><BR>1. //
通过Persistence创建EntityManagerFactory <BR>2.
EntityManagerFactory factory =
Persistence.createEntityManagerFactory( <BR>3. "jpa-unit",
System.getProperties()); <BR>4. <BR>5. //
从EntityManagerFactory中创建EntityManager <BR>6. EntityManager em
= factory.createEntityManager(); <BR>7. <BR>8. // 开始持久化实体的事务
<BR>9. em.getTransaction().begin(); <BR>10. <BR>11. /*
创建新的Animal对象 */ <BR>12. Animal animal = new Animal(); <BR>13.
/* 设置对象属性 */ <BR>14. animal.setId(1); <BR>15.
animal.setName("小狗"); <BR>16. <BR>17. /* 持久化Animal对象 */
<BR>18. em.persist(animal); <BR>19. <BR>20. // 提交持久化实体的事务
<BR>21. em.getTransaction().commit(); <BR>22. <BR>23. //
关闭EntityManager <BR>24. em.close(); <BR>25. <BR>26. //
创建新的EntityManager <BR>27. EntityManager em2 =
factory.createEntityManager(); <BR>28.
em2.getTransaction().begin(); <BR>29. // 查找Animal对象 <BR>30.
Animal animal1 = em2.find(Animal.class, 1); <BR>31. // 修改实体信息
<BR>32. animal1.setName("小猫"); <BR>33. // 保存更新后的实体 <BR>34.
em2.merge(animal1); <BR>35. em2.getTransaction().commit();
<BR>36. // 关闭EntityManager和EntityManagerFactory <BR>37.
em2.close(); <BR>38. <BR>39. // 创建新的EntityManager <BR>40.
EntityManager em3 = factory.createEntityManager(); <BR>41.
em3.getTransaction().begin(); <BR>42. // 查找Animal对象 <BR>43.
Animal animal2 = em3.find(Animal.class, 1); <BR>44. <BR>45. //
删除Animal对象 <BR>46. em3.remove(animal2); <BR>47.
em3.getTransaction().commit(); <BR>48. //
关闭EntityManager和EntityManagerFactory <BR>49. em3.close();
<BR>50. <BR>51. factory.close();
<BR><BR><BR>下面的信息是执行上面的客户端后控制台打印出的信息,通过这些信息的先后顺序,我们可以了解到这些事件的具体时机和先后顺序:
<BR><BR>清单 3. 客户端后控制台打印出的信息 <BR><BR><BR>1. Animal[1,小狗]
将被持久化到数据库中。 <BR>2. Animal[1,小狗] 可以被持久化到数据库中了。 <BR>3.
Animal[1,小狗] 将很快被持久化到数据库中。 <BR>4. Animal[1,小狗] 已经被持久化到数据库中。
<BR>5. <BR>6. Animal[1,小狗] 已经加载到内存中。 <BR>7. Animal[1,小猫]
将很快被持久化到数据库中。 <BR>8. Animal[1,小猫] 已经被持久化到数据库中。 <BR>9. <BR>10.
Animal[1,小猫] 已经加载到内存中。 <BR>11. Animal[1,小猫] 将从数据库中删除。 <BR>12.
Animal[1,小猫] 已经从数据库中删除。 <BR><BR><BR>OpenJPA 中还可以将一个 Java
方法注册到两个实体生命周期事件上,比如我们可以用下面的这段代码,将 Animal 实体 log 方法注册到
PrePersist 和 PostPersiste 这两个实体生命周期事件上。 <BR><BR>清单 4.
将方法注册到两个实体生命周期事件上 <BR><BR><BR>1. public class Animal { <BR>2.
<BR>3. … <BR>4. <BR>5. @PrePersist <BR>6. @PostPersist <BR>7.
public void log(){ <BR>8. System.out.println("Entity is
Persisted."); <BR>9. } <BR>10. } <BR><BR><SPAN
style="FONT-SIZE: 18px; LINE-HEIGHT: normal"><B>如何使用实体监听器</B></SPAN>
<BR><BR>在实体类中同时提供处理实体生命周期回调方法的代码不是很优雅的编程方式,开发者通常考虑使用非持久的监听器类处理回调方法。OpenJPA
中支持使用实体监听器处理实体的回调方法 , 而不是直接在实体类中处理回调方法。 <BR><BR>在 OpenJPA
中,实体监听器类需要提供一个 public 的无参数构造器,其他要求和在实体类中定义回调方法一样 ,
一个监听器类同样可以处理多种回调,只需要为监听器中的方法提供回调方法对应的注释如
javax.persistence.PrePersist、javax.persistence.PostPersist
等。特别的是,监听器中的每一个回调方法必须有一个 java.lang.Object
类型的参数,该参数对应的对象代表了触发当前事件的实体对象。 <BR><BR>我们可以使用下面的代码创建一个实体监听器类。
<BR><BR>清单 5. 创建一个实体监听器类 <BR><BR><BR>1. public class
AnimalListener{ <BR>2. public AnimalListener(){ <BR>3. }
<BR>4. <BR>5. /** <BR>6. *
logPrePersist方法处理实体生命周期中的PrePersist[实体被持久化之前]事件 <BR>7. */
<BR>8. @PrePersist <BR>9. public void logPrePersist(Object
entity){ <BR>10. System.out.println("实体将会被持久化."); <BR>11. }
<BR>12. <BR>13. /** <BR>14. *
logPostPersist方法处理实体生命周期中的PostPersist[实体可以被持久化]事件 <BR>15. */
<BR>16. @PostPersist <BR>17. public void logPostPersist(Object
entity){ <BR>18. System.out.println("实体可以被持久化了."); <BR>19. }
<BR>20. <BR>21. … // 可以为实体监听器提供更多方法,处理实体的更多回调事件。 <BR>22.
<BR>23. } <BR><BR><BR>创建实体监听器后,开发者将实体监听器注册到需要被监听的实体中,使用
javax.persistence.EntityListeners
注释可以为实体注册监听器,这个注释支持同时为实体类设置多个监听器 ,
只需要在注释的属性中提供多个参数,各参数之间使用”,”隔开。我们可以使用下面的代码为实体注册一个或者多个监听器类。
<BR><BR>清单 6. 为实体注册一个或者多个监听器类 <BR><BR><BR>1. @EntityListeners
({ AnimalListener.class, ...}) <BR>2. public class Animal{
<BR>3. … <BR>4. } <BR><BR><SPAN
style="FONT-SIZE: 18px; LINE-HEIGHT: normal"><B>实体监听器继承层次</B></SPAN>
<BR><BR>由于 OpenJPA
中实体是支持继承的,实体之间的监听器也被实体的子类继承下来,这些实体监听器方法在被触发时的遵循下面的调用顺序:
<BR><BR>● 首先,默认的监听器首先被调用,默认的监听器是指在包注释中定义的监听器; <BR>● 接下来 ,
实体监听器按照继承层次顺序被调用 , 父类监听器在子类监听器之前被调用; <BR>● 最后 ,
如果一个实体的同一个回调事件要触发多个监听器的话 , 这些监听器按照声明的先后顺序被调用;
<BR><BR>开发者可以选择屏蔽在父类或者包中声明的监听器,只需要使用下面两个类级别的注释 : <BR><BR>●
javax.persistence.ExcludeSuperclassListeners 为实体类提供
javax.persistence.ExcludeSuperclassListeners
注释,可以屏蔽所有当前实体类的所有父类中声明的实体监听器。 <BR>●
javax.persistence.ExcludeDefaultListeners 为实体类提供
javax.persistence.ExcludeDefaultListeners
注释,可以屏蔽当前实体类和它所有子类的所有默认监听器。 <BR><BR><SPAN
style="FONT-SIZE: 18px; LINE-HEIGHT: normal"><B>总结</B></SPAN>
<BR><BR>企业应用中经常有一些特别的需求:在某一个数据被处理的时候,需要引发一连串的操作,OpenJPA
中提供实体生命周期事件回调机制为这种需求提供了更好的解决方案,OpenJPA
中实体生命周期能够支持实体被持久化之前、实体可以被持久化、实体状态写入数据库之前、实体状态写入数据库之后、实体被加载、实体被删除之前、实体被删除之后共
7 种事件,开发者可以根据需要选择为其中的一个或者多个事件编写回调方法。本文中结合简单的例子描述了如何通过 OpenJPA
提供简单的注释、结合 Java 方法就可以监听、处理实体生命周期事件回调的过程。</SPAN> <!-- Attachments --></TD></TR>
<TR>
<TD class=spacerow colSpan=2 height=1><IMG height=1 alt=""
src="文章发表人是%20openjpa_files/spacer.gif" width=1></TD></TR>
<TR>
<TD class=postInfo colSpan=2>
<TABLE width="100%">
<TBODY>
<TR>
<TD><SPAN class=gen><A
href="http://bbs.163jsp.com/forums/show/1.html;jsessionid=95B9B6452ADB2E164F4DC77CC375B6F5">JAVA技术</A>
» <A
href="http://bbs.163jsp.com/posts/list/777.html;jsessionid=95B9B6452ADB2E164F4DC77CC375B6F5">OpenJPA项目</A>
» <A
href="http://bbs.163jsp.com/posts/preList/777/1528.html;jsessionid=95B9B6452ADB2E164F4DC77CC375B6F5#1528">加入讨论</A>
</SPAN></TD>
<TD align=right>
<SCRIPT
type=text/javascript>writeStars(0, 1528);</SCRIPT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR><!-- Message -->
<TD class=row2 vAlign=top colSpan=2><SPAN class=postbody><FONT
color=red><SPAN
style="FONT-SIZE: 18px; LINE-HEIGHT: normal"><B>第 5 部分:
实体标识的自动生成</B></SPAN></FONT> <BR>JPA(Java Persistence API)是 EJB
3.0 新引入的数据持久化编程模型。JPA
充分利用了注释(Annotation)和对象/关系映射,为数据持久化提供了更简单、易用的编程方式。OpenJPA 是
Apache 组织提供的 JPA 标准实现。本文是 使用 Apache OpenJPA 开发 EJB 3.0 应用系列
的第五部分,介绍在 OpenJPA
中如何自动生成实体的唯一标识,包括使用容器自动生成实体标识,借助于数据库的自动编号、序列号、数据库表等技术自动生成实体标识等,并且通过简单的例子描述了这几种情况下的操作过程。
<BR><BR>数据的唯一性是所有应用程序非常基本的要求,由开发者或者用户来维护这种唯一性存在着较大的风险,因此,由系统自动产生唯一标识是一种常见的做法。OpenJPA
中支持四种不同的实体标识自动生成策略: <BR><BR> ● 容器自动生成的实体标识; <BR> ●
使用数据库的自动增长字段生成实体标识; <BR> ● 根据数据库序列号(Sequence)技术生成实体标识;
<BR> ● 使用数据库表的字段生成实体标识; <BR><BR>这四种方式各有优缺点,开发者可以根据实际情况进行选择。
<BR><BR><SPAN
style="FONT-SIZE: 18px; LINE-HEIGHT: normal"><B>可选择的注释</B></SPAN>
<BR><BR>要让容器和数据库结合管理实体标识的自动生成,根据实际情况的不同,开发者可以选择
javax.persistence.* 包下面的
GeneratedValue、SequenceGenerator、TableGenerator
三个注释来描述实体的标识字段。 <BR><BR><SPAN
style="FONT-SIZE: 15px; LINE-HEIGHT: normal"><B>@javax.persistence.GeneratedValue</B></SPAN>
<BR><BR>每一个需要自动生成实体标识的实体都需要为它的实体标识字段提供 GeneratedValue
注释和相应的参数,OpenJPA 框架会根据注释和参数来处理实体标识的自动生成。 <BR><BR>使用
GeneratedValue 注释自动生成的实体标识可以是数值类型字段如 byte、short、int、long
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -