如何使用回调方法
上面我们学习了将 Java 代码和实体事件结合起来的一些注释和它们的适用情况,下面我们学习如何在企业应用中使用这些注释从而实现实体生命周期事件的回调。
首先我们学习如何使用回调方法来处理实体生命周期事件的回调,回调方法都是在实体内中直接定义的 Java 方法,这些回调方法可以是任何没有参数的方法。OpenJPA 中,一个 Java 方法可以同时支持多个注释,这样它可以处理实体生命周期中多个阶段的回调,比如我们在实体中定义一个 Java 方法 printHistory,我们可以同时使用 javax.persistence.PrePersist 和 javax.persistence.PostPersist 注释它,这样 printHistory 方法在实体被持久化之前和之后都会被调用。
下面我们结合简单的例子来解释如何使用回调方法处理实体生命周期事件的回调,假设存在这样的业务需求,对于实体 Animal,它有两个属性 id 和 name,我们需要在企业应用运行中跟踪 Animal 全部生命周期过程中的状态变化,并且将这种变化的过程打印在控制台上。
我们需要为实体类额外定义 7 个 Java 方法,他们分别处理实体生命周期的 7 个事件,然后通过上一节中提到的 7 个注释将它们和实体生命周期联系起来,完整的 Animal 实体类的代码如下:
清单 1. Animal 实体类的代码
2. package org.vivianj.openjpa.beans;
3.
4. import javax.persistence.Entity;
5. import javax.persistence.Id;
6. import javax.persistence.PostLoad;
7. import javax.persistence.PostPersist;
8. import javax.persistence.PostRemove;
9. import javax.persistence.PostUpdate;
10. import javax.persistence.PrePersist;
11. import javax.persistence.PreRemove;
12. import javax.persistence.PreUpdate;
13.
14. @Entity
15. public class Animal {
16. @Id
17. private long id;
18.
19. private String name;
20.
21. public long getId() {
22. return id;
23. }
24.
25. public void setId(long id) {
26. this.id = id;
27. }
28.
29. public String getName() {
30. return name;
31. }
32.
33. public void setName(String name) {
34. this.name = name;
35. }
36.
37. /**
38. * logPrePersist 方法处理实体生命周期中的 PrePersist[实体被持久化之前]事件
39. */
40. @PrePersist
41. public void logPrePersist() {
42. System.out.println("Animal[" + id + "," + name + "] 将被持久化到数据库中。");
43. }
44.
45. /**
46. * logPostPersist方法处理实体生命周期中的PostPersist[实体可以被持久化]事件
47. */
48. @PostPersist
49. public void logPostPersist() {
50. System.out.println("Animal[" + id + "," + name + "] 可以被持久化到数据库中了。");
51. }
52.
53. /**
54. * logPostLoad方法处理实体生命周期中的PostLoad[实体被加载到之后]事件
55. */
56. @PostLoad
57. public void logPostLoad() {
58. System.out.println("Animal[" + id + "," + name + "] 已经加载到内存中。");
59. }
60.
61. /**
62. * logPreUpdate方法处理实体生命周期中的PreUpdate[实体状态写入数据库之前]事件
63. */
64. @PreUpdate
65. public void logPreUpdate() {
66. System.out.println("Animal[" + id + "," + name + "] 将很快被持久化到数据库中。");
67. }
68.
69. /**
70. * logPostUpdate方法处理实体生命周期中的PostUpdate[实体状态写入数据库之后]事件
71. */
72. @PostUpdate
73. public void logPostUpdate() {
74. System.out.println("Animal[" + id + "," + name + "] 已经被持久化到数据库中。");
75. }
76.
77. /**
78. * logPreRemove方法处理实体生命周期中的PreRemove[实体被删除之前]事件
79. */
80. @PreRemove
81. public void logPreRemove() {
82. System.out.println("Animal[" + id + "," + name + "] 将从数据库中删除。");
83. }
84.
85. /**
86. * logPostRemove 方法处理实体生命周期中的 PostRemove [实体被删除之后]事件
87. */
88. @PostRemove
89. public void logPostRemove() {
90. System.out.println("Animal[" + id + "," + name + "] 已经从数据库中删除。");
91. }
我们可以使用下面的客户端代码完成实体的增加、查找、修改、删除工作:
清单 2. 实现实体的增加、查找、修改、删除的代码
2. EntityManagerFactory factory = Persistence.createEntityManagerFactory(
3. "jpa-unit", System.getProperties());
4.
5. // 从EntityManagerFactory中创建EntityManager
6. EntityManager em = factory.createEntityManager();
7.
8. // 开始持久化实体的事务
9. em.getTransaction().begin();
10.
11. /* 创建新的Animal对象 */
12. Animal animal = new Animal();
13. /* 设置对象属性 */
14. animal.setId(1);
15. animal.setName("小狗");
16.
17. /* 持久化Animal对象 */
18. em.persist(animal);
19.
20. // 提交持久化实体的事务
21. em.getTransaction().commit();
22.
23. // 关闭EntityManager
24. em.close();
25.
26. // 创建新的EntityManager
27. EntityManager em2 = factory.createEntityManager();
28. em2.getTransaction().begin();
29. // 查找Animal对象
30. Animal animal1 = em2.find(Animal.class, 1);
31. // 修改实体信息
32. animal1.setName("小猫");
33. // 保存更新后的实体
34. em2.merge(animal1);
35. em2.getTransaction().commit();
36. // 关闭EntityManager和EntityManagerFactory
37. em2.close();
38.
39. // 创建新的EntityManager
40. EntityManager em3 = factory.createEntityManager();
41. em3.getTransaction().begin();
42. // 查找Animal对象
43. Animal animal2 = em3.find(Animal.class, 1);
44.
45. // 删除Animal对象
46. em3.remove(animal2);
47. em3.getTransaction().commit();
48. // 关闭EntityManager和EntityManagerFactory
49. em3.close();
50.
51. factory.close();
下面的信息是执行上面的客户端后控制台打印出的信息,通过这些信息的先后顺序,我们可以了解到这些事件的具体时机和先后顺序:
清单 3. 客户端后控制台打印出的信息
2 2. Animal[1,小狗] 可以被持久化到数据库中了。
3 3. Animal[1,小狗] 将很快被持久化到数据库中。
4 4. Animal[1,小狗] 已经被持久化到数据库中。
5 5.
6 6. Animal[1,小狗] 已经加载到内存中。
7 7. Animal[1,小猫] 将很快被持久化到数据库中。
8 8. Animal[1,小猫] 已经被持久化到数据库中。
9 9.
10 10. Animal[1,小猫] 已经加载到内存中。
11 11. Animal[1,小猫] 将从数据库中删除。
12 12. Animal[1,小猫] 已经从数据库中删除。
13
OpenJPA 中还可以将一个 Java 方法注册到两个实体生命周期事件上,比如我们可以用下面的这段代码,将 Animal 实体 log 方法注册到 PrePersist 和 PostPersiste 这两个实体生命周期事件上。
清单 4. 将方法注册到两个实体生命周期事件上
2 2.
3 3. …
4 4.
5 5. @PrePersist
6 6. @PostPersist
7 7. public void log(){
8 8. System.out.println("Entity is Persisted.");
9 9. }
10 10. }
11