最后一U映类型,是实体与标量值的l合
@SqlResultSetMapping ( name="ReturnOrderListWithPartEntityPartScalarType", entities= { @EntityResult ( entityClass=entity.Order.class, fields= { @FieldResult(name="id",column="order_id"), @FieldResult(name="date",column="order_creation_date"), @FieldResult(name="desc",column="order_description"), @FieldResult(name="sum",column="order_sum_total") } ),
@EntityResult ( entityClass=entity.Customer.class, discriminatorColumn="customer_type", fields= { @FieldResult(name="id",column="customer_id"), @FieldResult(name="ctype",column="customer_type") } ) }, columns= { @ColumnResult(name="customer_name") } )
我们结果集中与订单有关的保存进Order EntityQ把?span style="color: black">Customer有关的,?span style="color: black">id?span style="color: black">customer type 保存q?span style="color: black">Customer EntityQ把customer name保存q标量?
l过q行试E序Q得?/span>
*****ReturnOrderListWithPartEntityPartScalarType***** entity.Order@48edb5 entity.GoldenCustomer@1ee2c2c John Smith entity.Order@1402d5a entity.GoldenCustomer@1ee2c2c John Smith entity.Order@1e13e07 entity.GoldenCustomer@1ee2c2c John Smith
lg所qͼ我们可以采取多种resultset映射机制来保存用本地查询得到的结果集Q具体采取哪U要看具体的情况Q要l箋了解q方面的知识?/p> |
JPA支持本地查询Q所谓本地查询,是使用原生?span style="color: rgb(0,0,0)">sql语句Q根据数据库的不同,?span style="color: rgb(0,0,0)">sql的语法或l构斚w可能有所区别Q进行查询数据库的操作?/span>
本地查询主要使用EntityManager接口里的Ҏ(gu)Q?/span> public interface EntityManager {
?span style="color: rgb(0,0,0)"> createNativeQueryҎ(gu)的三UŞ式,但用q个Ҏ(gu)的缺Ҏ(gu)Q要查询的sql语句?qing)返回结果集cd传递进厅R还有一U方法是使用createNamedQueryQ这样就可以避免在这里直接写?span style="color: rgb(0,0,0)">sql语句以及(qing)q回的结果集cd{参敎ͼ而可以在相关?span style="color: rgb(0,0,0)">Entityc里对这些信息进行配|?/span>
//q里只是传递进M?span style="color: rgb(153,153,153)">string?/span> Query q = em.createNamedQuery("ReturnOrderListWithFullScalarType"); //q里是设定在sql中所需的参?/p> q.setParameter(1, customer.getId()); //得到l果?/p> List orderList = q.getResultList();
q个查询主要是根据用L(fng)id 来获取他名下的所有订单。所以,在实体类 Order中,加入相关?span style="color: rgb(0,0,0)">native query annotation.
@NamedNativeQueries ( { @NamedNativeQuery( name="ReturnOrderListWithFullScalarType", query="select o.id as order_id,o.create_date as order_creation_date,o.description as order_description,o.sum_price as order_sum_total, c.name as customer_name,c.ctype as customer_type,c.id as customer_id from orders o join customer c on o.cust_id=c.id where o.cust_id=?1", resultSetMapping="ReturnOrderListWithFullScalarType"), 。。。。。。。。。。。。。可能还有更多的本地查询讄 } )
@NamedNativeQueries 如果在一个实体类中有多个NamedNativeQuery的话Q必M用该Ҏ(gu)Qƈ且将单个?span style="color: rgb(0,0,0)">NamedNativeQuery都作?span style="color: rgb(0,0,0)">NamedNativeQueries数组中的一个元素?/span> @NamedNativeQueryQ在q里讄关于该本地查询的信息?span style="color: rgb(0,0,255)">name表示传递进EntityManager.createNamedQuery(“name”)的参敎ͼquery表示实施本地查询?span style="color: rgb(0,0,0)">sql语句Q?span style="color: rgb(0,0,255)">resultSetMapping表示q回l果集的映射方式。它的意思就是结果集以哪种形式来保存?/span>
接着Q就要设|这个结果集的映方式了?/span>
@SqlResultSetMappings( { @SqlResultSetMapping ( name="ReturnOrderListWithFullScalarType", entities={}, columns= { @ColumnResult(name="order_id"), @ColumnResult(name="order_creation_date"), @ColumnResult(name="order_description"), @ColumnResult(name="order_sum_total"), @ColumnResult(name="customer_id"), @ColumnResult(name="customer_name") } ), 。。。。。。。。。。。。。可能还有更多的l果集映设|?/p> }) 针对每一个本地查询的q回|都有一个结果集和它映射。它可以q回 1. 实体Q包括不同类型的实体Q即多个实体Q?span style="color: rgb(0,0,0)"> Entity 2. 标量?span style="color: rgb(0,0,0)"> Scalar 3. 实体与标量值的l合 Entity+Scalar
默认情况下,JPA假设原生sql查询?span style="color: rgb(0,0,0)">select语句会(x)Q?/span> 1. q回一个实体类?/span> 2. 包含与返回的实体的所有字D|属性相对应的所有列Q即列名和实体属?span style="color: rgb(0,0,0)">/字段名一?/span> 3. 查询中没有用列名别名Q?span style="color: rgb(0,0,0)">column aliasQ即没有?span style="color: rgb(0,0,0)"> AS 指定别名
@SqlResultSetMappingsQ如果在一个实体类中有多个@NamedNativeQuery的话Q必然就有多个结果集映射@SqlResultSetMapping。在q种情况下,必须使用该批注,q且单个的SqlResultSetMapping都作?span style="color: rgb(0,0,0)">SqlResultSetMappings数组中的一个元素?/span> @SqlResultSetMappingQ关于结果集映射的详l信息?/span> name 表示该结果集映射的名字,?span style="color: rgb(0,0,0)">@NamedNativeQuery中的resultSetMapping="ReturnOrderListWithFullScalarType"的值相对应?/span> entities表示查询l果集会(x)被映进实体Q如果有p所有返回的实体一一列出Q这里我们将l果集全部映进标量Q所?span style="color: rgb(0,0,0)">entities属性是个空数组Q?/span> columns表示被映射q标量的l果集中的各个列?/span>
q里要说一下标量(ScalarQ这个概c在物理学上Q标量与矢量Q?span>VectorQ是怺对应的,矢量是既有方向又有大的量,而标量是只有大小的量。在此处Q?span>Scalar的含义与物理学上的定义差不多Q?span>Scalar可以认ؓ(f)是一个没有属?span>/Ҏ(gu)的单U的帔R(可以惌?span>java数据cd?span>primitive type)Q而与它相对的则是有方?span>/属性的对象(object type)。那么采用这U映机Ӟ我们从数据库取来的每一条记录的每一个字D,仅仅是被单纯的作Z个常量,保存在每一?span>columnResult中?/span>
@ ColumnResultQ就是指?span style="color: rgb(0,0,0)">sql语句中,哪些查询的列保存进来。每一?span style="color: rgb(0,0,0)">@ColumnResult对应一个列Q?/span>name="order_id" Q注意,如果?span style="color: rgb(0,0,0)">select的时候,?span style="color: rgb(0,0,0)">AS 制定了列的别名,“order_id” 则表C的是别名?/span>
q种映射方式比较单,我们可以推测Q得到的l果?span style="color: rgb(0,0,0)">List中,数据?x)是q样Q?/span> [ {“?span style="color: rgb(0,0,0)">1”, “?span style="color: rgb(0,0,0)">2”, “?span style="color: rgb(0,0,0)">3”, …}, {“?span style="color: rgb(0,0,0)">1”, “?span style="color: rgb(0,0,0)">2”, “?span style="color: rgb(0,0,0)">3”, …}, …… ]
l过q行试E序Q得C我们的推?/span>
*****ReturnOrderListWithFullScalarType***** 52 2009-05-27 00:00:00.0 This is an order creation example. 36817.0 39 John Smith 55 2009-05-27 00:00:00.0 This is an order creation example. 3347.0 39 John Smith ……
结果集全部映射q标量,是比较简单的一U做法,在SqlResultSetMapping |
OKQ现在对同一个查询,再把l果集全部映进实体对象?/span>
首先 @NamedNativeQueries ( { @NamedNativeQuery( name="ReturnOrderListWithFullEntityType", query="select o.id as order_id,o.create_date as order_creation_date,o.description as order_description,o.sum_price as order_sum_total, c.name as customer_name,c.ctype as customer_type,c.id as customer_id from orders o join customer c on o.cust_id=c.id where o.cust_id=?1", resultSetMapping="ReturnOrderListWithFullEntityType"), 。。。。。。。。。。。。。可能还有更多的本地查询讄 } ) 改变本地查询?span style="color: rgb(0,0,0)">resultSetMapping
@SqlResultSetMapping ( name="ReturnOrderListWithFullEntityType", entities= { @EntityResult ( entityClass=entity.Order.class, fields= { @FieldResult(name="id",column="order_id"), @FieldResult(name="date",column="order_creation_date"), @FieldResult(name="desc",column="order_description"), @FieldResult(name="sum",column="order_sum_total") } ),
@EntityResult ( entityClass=entity.Customer.class, discriminatorColumn="customer_type", fields= { @FieldResult(name="id",column="customer_id"), @FieldResult(name="name",column="customer_name") } ) }, columns={} )
entities属性是一个包含与q回l果集相映射的所有实体的一个数l。这条查询得C订单和用L(fng)信息Q所以,与结果集映射的实体,应该是Order?span style="color: rgb(0,0,0)">Customer?/span> 每一个映实体用@EntityResult表示Q?span style="color: rgb(0,0,255)">entityClass表示实体c,fields表示该实体类中的属性,与查询结果中的哪些个列相映射。而每一?#8220;属?span style="color: rgb(0,0,0)"><->?#8221;的映关p,又保存在@FieldResult里面?span style="color: rgb(0,0,255)">name是实体属性,column是查询列Q或列别名)
要注意的是,如果要将l果集映到实体对象Q则 1Q?span style="color: rgb(0,0,0)">Select 语句中必d含实体所映射的表中的PKQ也是 select o.id as order_id
2. 反过来,“属?span style="color: rgb(0,0,0)"><->?#8221;的映,也必d表的PK映射到实体类的用@Id annotationҎ(gu)的字D|属性上?/span>
否则Q?span style="color: rgb(0,0,0)">JPA׃(x)抛出一?span style="color: rgb(0,0,0)">exception oracle.toplink.essentials.exceptions.QueryException Exception Description: The primary key read from the row [DatabaseRecord( orders.ID => null orders.CREATE_DATE => 2009-05-27 00:00:00.0 orders.SUM_PRICE => 36817.0 orders.DESCRIPTION => This is an order creation example. orders.cust_id => null)] during the execution of the query was detected to be null. Primary keys must not contain null.
再看一下关?span style="color: rgb(0,0,0)">Customer实体的映,?span style="color: rgb(0,0,0)">Order不一L(fng)地方Q是discriminatorColumn="customer_type" (可能为列别名) 加上q个属性的原因是,CustomercL一个父c,以供其他子类l承Q?span style="color: rgb(0,0,0)">J PA的内在多态性机制将?x)获取?span style="color: rgb(0,0,0)">Customer的实际类型。根?span style="color: rgb(0,0,0)">J PA @InheritanceҎ(gu)Q得知,父类实体的表中必L一个字D(默认?span style="color: rgb(0,0,0)">DTYPEQ来表示各个子类的类型。所以当要将查询l果集保存ؓ(f)实体的时候,它必要知道你所保存的这?span style="color: rgb(0,0,0)">Customer实体到底是哪U类型?/span> 所以,你还必须?span style="color: rgb(0,0,0)">select子句中取得这?span style="color: rgb(0,0,0)">Discrimator Type的字Dc?/span> 否则又会(x)抛出异常Q?span style="color: rgb(0,0,0)"> oracle.toplink.essentials.exceptions.QueryException Exception Description: Custom SQL failed to provide descriminator column : , as defined in SQLResultSetMapping : ReturnOrderListWithFullEntityType. 或者:(x) oracle.toplink.essentials.exceptions.QueryException Exception Description: Custom SQL failed to provide descriminator column : customer_type, as defined in SQLResultSetMapping : ReturnOrderListWithPartEntityPartScalarType.
通过q种映射方式Q我们可以推,得到的结果集List中,数据?x)是q样Q?/span> [ {“Order对象1”, “Customer对象1”}, {“Order对象2”, “Customerr对象2”}, …… ]
l过q行试E序Q得C我们的推?/span>
*****ReturnOrderListWithFullEntityType***** entity.Order@48edb5 entity.GoldenCustomer@1ee2c2c entity.Order@1402d5a entity.GoldenCustomer@1ee2c2c entity.Order@1e13e07 entity.GoldenCustomer@1ee2c2c entity.Order@9cfec1 entity.GoldenCustomer@1ee2c2c entity.Order@747fa2 entity.GoldenCustomer@1ee2c2c …… 看来的确是保存了对象Q而且注意W二个对象不是Customer而是GoldenCustomerQ这说明QJPA自动数据映进了GoldenCustomer实体Q尽我们用的是Customer实体q行保存 “entityClass=entity.Customer.class”Q?/p> |
9.3.原生查询 9.3.1. 标量原生查询 9.3.2.单的实体原生查询 9.3.3.复杂的原生查?br />q个实体理Ҏ(gu)允许你有一个复杂的映射为原生SQL.你可以同时返回多个实体和标量?mappingName 参数参考@javax.persistence.SqlResultSetMapping定义.q个Ҏ(gu)用来定义一个怎能h询原生结果的钓子到O/R模型.如果q回的栏位名与批注映的属性不匚w,你可以提代一个字D到栏位的映ؓ(f)他们,使用@javax.persistence.FieldResult : public @interface SqlResultSetMapping { public @interface EntityResult { public @interface FieldResult { public @interface ColumnResult { 9.3.3.1. 使用多个实体的原生查?br />@Entity // execution code { FROM Cruise c LEFT JOIN Reservation ON c.id = Reservation.CRUISE_ID 9.4命名查询 @NamedQuery(name="findFullyPaidCruises", 9.4.1.命名原生查询 public @interface NamedNativeQuery { public @interface NamedNativeQueries { Phone实体中加?br />@NamedNativeQuery(name="NativePhone",
Named Native Query, implicit mapping at org.hibernate.impl.AbstractSessionImpl.getNamedQuery(AbstractSessionImpl.java:70)
加入@Table(name="CREDIT_CARD_TABLE") q在相应属性加入@ColumnҎ(gu) at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67) |
★ 提示 ★ 目前JBoss 4.2集成了的Tomcat版本?.5Q但Tomcat 6.0以后的版本中才支持用注释,所以如果将本例中Servletq行在JBoss 4.2中,q不能获得EntityManagerFactory对象Q但在符合J2EE 5.0的服务器中,q样q行是可以的?br /> 虽然在目前JBoss 4.2版本中不支持使用注释Q但可以通过另一U方式来获得应用托管的EntityManager对象。代码如下所C?br /> 1. public class TestServlet extends HttpServlet { 2. 3. private EntityManagerFactory emf; 4. 5. public TestServlet() { 6. 7. super(); 8. 9. } 10. 11. public void doGet(HttpServletRequest request, HttpServletResponse response) 12. 13. throws ServletException, IOException { 14. 15. doPost(request, response); 16. 17. } 18. 19. public void doPost(HttpServletRequest request, HttpServletResponse response) 20. 21. throws ServletException, IOException { 22. 23. response.setContentType("text/html"); 24. 25. PrintWriter out = response.getWriter(); 26. 27. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">"); 28. 29. out.println("<HTML>"); 30. 31. out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); 32. 33. out.println(" <BODY>"); 34. 35. if (emf != null) { 36. 37. /**创徏EntityManager 对象*/ 38. 39. EntityManager entityManager = emf.createEntityManager(); 40. 41. try { 42. 43. Query query = entityManager 44. 45. .createQuery("SELECT c FROM CustomerEO c"); 46. 47. List<CustomerEO> result = query.getResultList(); 48. 49. for (CustomerEO c : result) { 50. 51. System.out.println(c.getId() + "," + c.getName()); 52. 53. } 54. 55. } finally { 56. 57. /**关闭EntityManager*/ 58. 59. entityManager.close(); 60. 61. } 62. 63. } 64. 65. out.println(" </BODY>"); 66. 67. out.println("</HTML>"); 68. 69. out.flush(); 70. 71. out.close(); 72. 73. } 74. 75. /**Servlet初始化时Q创建EntityManagerFactory 对象*/ 76. 77. public void init() throws ServletException { 78. 79. if (emf == null) { 80. 81. emf = Persistence.createEntityManagerFactory("jpaUnit"); 82. 83. } 84. 85. } 86. 87. /**Servlet销毁时Q关闭EntityManagerFactory对象*/ 88. 89. public void destroy() { 90. 91. if (emf.isOpen()) 92. 93. emf.close(); 94. 95. } 96. 97. } public class TestServlet extends HttpServlet { private EntityManagerFactory emf; public TestServlet() { super(); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">"); out.println("<HTML>"); out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>"); out.println(" <BODY>"); if (emf != null) { /**创徏EntityManager 对象*/ EntityManager entityManager = emf.createEntityManager(); try { Query query = entityManager .createQuery("SELECT c FROM CustomerEO c"); List<CustomerEO> result = query.getResultList(); for (CustomerEO c : result) { System.out.println(c.getId() + "," + c.getName()); } } finally { /**关闭EntityManager*/ entityManager.close(); } } out.println(" </BODY>"); out.println("</HTML>"); out.flush(); out.close(); } /**Servlet初始化时Q创建EntityManagerFactory 对象*/ public void init() throws ServletException { if (emf == null) { emf = Persistence.createEntityManagerFactory("jpaUnit"); } } /**Servlet销毁时Q关闭EntityManagerFactory对象*/ public void destroy() { if (emf.isOpen()) emf.close(); } } 使用q种方式创徏EntityManagerFactory对象需要注意以下几个问题?br /> 可以看到Q这里的EntityManagerFactory对象不是通过注入获得的,而是通过PersistencecM的静态方法createEntityManagerFactory来创建的?br /> — 正因为EntityManagerFactory对象是手动创建的Q所以在不再使用Ӟ一定要调用close()Ҏ(gu)手动关闭?br /> 11.1.4.3 J2SE环境中获?br /> 在J2SE环境中,获得应用托管的EntityManager对象只能通过手动创徏的方式,而不能用注释的方式Q与Web容器中不使用注释的方法相同,都是通过PersistencecMcreateEntityManagerFactory来创建的?br /> 例如Q下面代码ؓ(f)J2SE环境中获得应用托EntityManager对象的方法?br /> 1. public class CustomerClient { 2. 3. public static void main(String[] args) { 4. 5. /** 创徏EntityManagerFactory对象 */ 6. 7. EntityManagerFactory emf = Persistence 8. 9. .createEntityManagerFactory("jpaUnit"); 10. 11. /** 创徏entityManager对象 */ 12. 13. EntityManager entityManager = emf.createEntityManager(); 14. 15. Query query = entityManager.createQuery("SELECT c FROM CustomerEO c"); 16. 17. List<CustomerEO> result = query.getResultList(); 18. 19. for (CustomerEO c : result) { 20. 21. System.out.println(c.getId() + "," + c.getName()); 22. 23. } 24. 25. /** 关闭entityManager对象 */ 26. 27. entityManager.close(); 28. 29. /** 关闭EntityManagerFactory对象 */ 30. 31. emf.close(); 32. 33. } 34. 35. } public class CustomerClient { public static void main(String[] args) { /** 创徏EntityManagerFactory对象 */ EntityManagerFactory emf = Persistence .createEntityManagerFactory("jpaUnit"); /** 创徏entityManager对象 */ EntityManager entityManager = emf.createEntityManager(); Query query = entityManager.createQuery("SELECT c FROM CustomerEO c"); List<CustomerEO> result = query.getResultList(); for (CustomerEO c : result) { System.out.println(c.getId() + "," + c.getName()); } /** 关闭entityManager对象 */ entityManager.close(); /** 关闭EntityManagerFactory对象 */ emf.close(); } } 但是Q在J2SE环境中用JPA需要将实现的JPA的第三方cd和数据库的驱动包Q设|到当前的运行环境下?br /> 例如Q在Eclipse中创Z个Java目Q需要将JPA实现者的cdQ这里以HibernateZQ和MySQL的数据库q接包添加到构徏路径中,如图11-2所C?br /> 11.1.5 ThreadLocal的?br /> 对于在Web容器中用EntityManager对象Q这里需要做一些改q,才能更安全。读者应该了解,Servlet是非U程安全的,所以需要改变获得EntityManager对象的方式,q里W者徏议用ThreadLocalcR?br /> ThreadLocal是为每一个用某变量的线E都提供一个该变量值的副本Q每一个线E都可以独立地改变自q副本Q而不?x)和其他U程的副本冲H。从U程的角度看Q就好像每一个线E都完全拥有一个该变量Q这p决了Servlet非线E安全的问题?br /> 首先~写一个EntityManagerHelperc,代码如下所C?br /> 1. public class EntityManagerHelper { 2. 3. 4. 5. private static final EntityManagerFactory emf; 6. 7. private static final ThreadLocal<EntityManager> threadLocal; 8. 9. 10. 11. /**初始?/ 12. 13. static { 14. 15. emf = Persistence.createEntityManagerFactory("jpaUnit"); 16. 17. threadLocal = new ThreadLocal<EntityManager>(); 18. 19. } 20. 21. 22. 23. /**通过threadLocal 获得EntityManager 对象*/ 24. 25. public static EntityManager getEntityManager() { 26. 27. EntityManager manager = threadLocal.get(); 28. 29. if (manager == null || !manager.isOpen()) { 30. 31. manager = emf.createEntityManager(); 32. 33. threadLocal.set(manager); 34. 35. } 36. 37. return manager; 38. 39. } 40. 41. 42. 43. /**关闭EntityManager 对象*/ 44. 45. public static void closeEntityManager() { 46. 47. EntityManager em = threadLocal.get(); 48. 49. threadLocal.set(null); 50. 51. if (em != null) em.close(); 52. 53. } 54. 55. 56. 57. public static void beginTransaction() { 58. 59. getEntityManager().getTransaction().begin(); 60. 61. } 62. 63. 64. 65. public static void commit() { 66. 67. getEntityManager().getTransaction().commit(); 68. 69. } 70. 71. 72. 73. public static Query createQuery(String query) { 74. 75. return getEntityManager().createQuery(query); 76. 77. } 78. 79. 80. 81. } public class EntityManagerHelper { private static final EntityManagerFactory emf; private static final ThreadLocal<EntityManager> threadLocal; /**初始?/ static { emf = Persistence.createEntityManagerFactory("jpaUnit"); threadLocal = new ThreadLocal<EntityManager>(); } /**通过threadLocal 获得EntityManager 对象*/ public static EntityManager getEntityManager() { EntityManager manager = threadLocal.get(); if (manager == null || !manager.isOpen()) { manager = emf.createEntityManager(); threadLocal.set(manager); } return manager; } /**关闭EntityManager 对象*/ public static void closeEntityManager() { EntityManager em = threadLocal.get(); threadLocal.set(null); if (em != null) em.close(); } public static void beginTransaction() { getEntityManager().getTransaction().begin(); } public static void commit() { getEntityManager().getTransaction().commit(); } public static Query createQuery(String query) { return getEntityManager().createQuery(query); } } q样l过改进后,在Servlet中创建EntityManager对象的方法修改ؓ(f)如下所C?br /> 1. public class TestServlet extends HttpServlet { 2. 3. public TestServlet() { 4. 5. super(); 6. 7. } 8. 9. public void doPost(HttpServletRequest request, HttpServletResponse response) 10. 11. throws ServletException, IOException { 12. 13. EntityManager entityManager = EntityManagerHelper.getEntityManager(); 14. 15. try { 16. 17. Query query = entityManager 18. 19. .createQuery("SELECT c FROM CustomerEO c"); 20. 21. List<CustomerEO> result = query.getResultList(); 22. 23. for (CustomerEO c : result) { 24. 25. System.out.println(c.getId() + "," + c.getName()); 26. 27. } 28. 29. } finally { 30. 31. /**关闭EntityManager*/ 32. 33. EntityManagerHelper.closeEntityManager(); 34. 35. } 36. 37. } 38. 39. } |
持久化上下文QPersistence ContextsQ的相关知识Q内容包括如何从Java EE容器中创建EntityManager对象、如何从Java SE中创建EntityManager对象、持久化上下文与事务QTransctionQ的关系Q以?qing)实体管理器工厂QEntity Manager FactoryQ的相关内容? 通过本章的学?fn),读者将深入掌握JPA中有x久化上下文、事务处理的相关知识Q从而能够更加深入地应用JPA? 11.1 获得EntityManager对象 那么如何获得EntityManager对象呢?q又是JPA中另外一个很重要的问题? 11.1.1 Java EE环境与J2SE环境 在详l讲qEntityManager对象之前Q读者首先要分清楚两个概念,即Java EE环境与J2SE环境。因为在本章后面的学?fn)中要经常提到这两个概念Q所以读者一定要先理解它们,Z后的学习(fn)打好基础? — Java EE环境Q包括EJB容器和W(xu)eb容器? Q?QWeb容器Q只q行W(xu)eb应用的容器,例如Tomcat是开源的Web容器Q它可以q行JSP、Servlet{? Q?QEJB容器Q运行在EJBlg的容器,提供EJBlg的状态管理、事务管理、线E管理、远E数据资源访问、连接管理和安全性管理等pȝU服务。例如JBoss为EJB容器和W(xu)eb容器QWeb容器是集成了TomcatQ结合? 部v在EJB容器中的JAR包都可以认ؓ(f)是运行在EJB容器中。但JBoss中的Web应用Q比如war包中的类׃是运行在EJB容器中,而是q行在Web容器中? — J2SE环境 最普通Javaq行环境Q例如一个HelloWorld的JavaE序是q行在J2SE的环境中Q通常使用main入口Ҏ(gu)作ؓ(f)E序启动的触发? 如图11-1所C,它说明了Java EE与J2SE环境的关pR? 11.1.2 两种cd的EntityManager对象 Ҏ(gu)EntityManager对象的管理方式,可以有以下两U类型? — 容器托管的(container-managedQEntityManager对象 容器托管的EntityManager对象最单,E序员不需要考虑EntityManagerq接的释放,以及(qing)事务{复杂的问题Q所有这些都?l容器去理。容器托的EntityManager对象必须在EJB容器中运行,而不能在Web容器和J2SE的环境中q行。本书前面讲q的 EntityManager对象都是通过注入 @PersistenceContext注释来获得的Q其实,q种获得EntityManager对象的方式就是容器托的? — 应用托管的(application-managedQEntityManager对象 应用托管的EntityManager对象Q程序员需要手动地控制它的释放和连接、手动地控制事务{。但q种获得应用托管?EntityManager对象的方式,不仅可以在EJB容器中应用,也可以 JPAqEJB容器Q而与M的Java环境集成Q比如说Web容器、J2SE环境{。所以从某种角度上来_(d)q种方式是JPA能够独立于EJB环境q?行的基础? 理想状态下Q最好是选用容器托管的EntityManager对象的方式,但在Ҏ(gu)的环境下Q还是需要用应用托的EntityManager对象q种方式? 正是因ؓ(f)应用托管的EntityManager对象的连接释放、事务控制比较复杂,所以在使用时涉?qing)的相关内容比较多,q些内容在本章后面部分详细讲述Q这里读者应对两U方式有一个大致的了解Q两UEntityManager对象cd的比较如?1-1所C? ?1-1 容器托管与应用托的EntityManager对象Ҏ(gu) 比较内容 容器托管的(container-managedQEntityManager对象 应用托管的(application-managedQEntityManager对象 获得方式 两种方式Q? @PersistenceContex注入 2 JNDI获得 EntityManagerFactory创徏 支持事务 JTA JTA、RESOURCE_LOCAL q行环境 EJB容器 EJB容器、Web容器、J2SE环境 11.1.3 容器托管的(container-managedQEntityManager对象 容器托管的EntityManager对象只能q行在EJB容器中。所以可以这L(fng)解,只有在EJB-JAR包中Q才可以获得容器托管的EntityManager对象Q否则只能获得应用托的EntityManager对象? 在EJB容器中获得EntityManager对象主要有两U方式,即@PersistenceContext注释注入和JNDI方式获得? 11.1.3.1 通过@PersistenceContext注释注入 q种方式获得EntityManager对象最为常用,例如下面代码所C?
在用此U方式创建EntityManager对象Ӟ需要注意以下几个问题? — @PersistenceContext注释中,其中unitName为persistence.xml文g?lt;persistence-unit>元素中的属?#8220;name”的|表示要初始化哪个持久化单元,如下所C?
— @PersistenceContext注释中还可以配置其他的设|,它的定义如下所C?
— 其中PersistenceContextType可以讄创徏EntityManager对象Ӟ持久化上下文的作用范_(d)它的意义在于Ҏ(gu)状态的BeanQStateless BeanQ可以跨事务操作实体。它主要有两U方式,定义如下所C?
默认情况下用TRANSACTIONQ有关TRANSACTION方式和EXTENDED方式创徏EntityManager对象的异同,在下文中详l讲qͼq里读者简单了解一下即可? 11.1.3.2 通过JNDI的方式获? 如果指定了@PersistenceContext注释中的name|则设|了持久化上下文的JNDI名称。通过SessionContext可以创徏EntityManager对象? 例如Q下面代码ؓ(f)通过JNDI方式获得EntityManager对象?
11.1.4 应用托管的(application-managedQEntityManager对象 应用托管的EntityManager对象Q不仅可以在Java EE环境中获得,也可以应用在J2SE的环境中。但无论是在什么情况下获得的EntityManager对象Q都是通过实体理器工?QEntityManagerFactoryQ对象创建的。所以如何获得应用托的EntityManager对象关键?EntityManagerFactory对象如何获得? 下面分别讲q在EJB容器、Web容器和J2SE环境中如何获得EntityManagerFactory对象? 11.1.4.1 EJB容器中获? 在EJB容器中,EntityManagerFactory对象可以通过使用注入@PersistenceUnit注释获得Q例如下面代码ؓ(f)在EJB容器中,获得应用托管的EntityManager对象的方法?
通过以上的EntityManager对象代码Q可以ȝZ下几个问题? — 应用托管的EntityManager对象Q要在代码中手动地创建和关闭Q例如下面代码所C? EntityManager em = emf.createEntityManager(); /**其他的业务逻辑*/ em.close(); q点正是与容器托的EntityManager对象的最大不同之处。事实上Q容器托的EntityManager对象Q它的创建和关闭是由容器负责理的,所以不需要编写代码来控制? — 应用托管的EntityManager对象Q都是通EntityManagerFactory对象来创建的。在容器中可以通过使用注入@PersistenceUnit注释的方法实玎ͼ它的定义如下所C?
其中Q属性unitName为persistence.xml文g?lt;persistence-unit>元素中的属?#8220;name”的|表示要初始化哪个持久化单元,与@PersistenceContext注释中unitName属性相同? 11.1.4.2 Web容器中获? 在Web容器中,EntityManagerFactory对象也可以通过使用注入@PersistenceUnit注释获得。例如,下面代码为在 Servlet中,获得应用托管的EntityManager对象的方法?/syntaxhighlighter/clipboard_new.swf">
|