在ORM世界中,打包始终是一项手动操作。在Hibernate中,您必须通过配置API或通过hibernate.cfg.xml文件列出映射的实体。长期以来,JBoss AS已经引入了.hار的概念,基本上是一个由部署者扫描以发现Hibernate配置及其中的hbm.xml文件的存档。
在EJB3容器内进行打包
EJB3专家小组在EJB3公共草案中引入了相同的概念。PAR存档基本上是一个具有.par扩展名的jar文件。您所要做的就是将所有注解实体放入存档中,容器有责任扫描它并找到所有注解实体。PAR存档是一个持久化单元定义,将用于创建EntityManagerFactory(在Hibernate世界中称为SessionFactory)。然后您将能够使用您的持久化单元(通过查找或注入一个EntityManager或一个EntityManagerFactory),其名称为PAR文件名(不含扩展名)(即mypersistenceunit.par将被引用为mypersistenceunit)。
由于您可能想自定义持久化单元配置,可以在META-INF目录中添加一个persistence.xml文件。
<?xml version="1.0" encoding="UTF-8"?> <entity-manager> <name>FinancialPU</name> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>jdbc/MyDB</jta-data-source> <class>com.acme.MyClass</class> <jar-file>externalEntities.jar</jar-file> <properties> <property name="hibernate.max_fetch_depth" value="4"/> </properties> </entity-manager>
让我们分析这个小型但全面的示例。
的名称元素允许您覆盖持久化单元名称(默认为PAR文件名,不带.par后缀)。
的提供者元素允许您表达您想为此持久化单元使用的实体管理器实现。如果没有指定,默认值为Hibernate实体管理器。这是一个有趣的选择,这基本上意味着您可以在同一应用程序中使用多个实体管理器实现,或者以标准方式使用Hibernate实体管理器实现来替代您的供应商EJB3持久化实现!
的jta-data-source与non-jta-data-source允许您指定持久化单元将工作的数据源。
的类元素允许您显式添加一些要映射的实体。这些实体通常位于PAR存档之外,实体管理器将在EAR类路径中搜索它们。这在多个持久化单元之间共享相同的实体定义特别方便。
的jar-file元素允许您请求实体管理器实现添加特定JAR文件中包含的所有实体并将它们包含在配置中。在Hibernate实体管理器的情况下,它还会查看hbm.xml文件。这在多个持久化单元之间共享一定数量的实体定义特别方便。
还有一个mapping-file元素目前在Hibernate实体管理器实现中尚不支持。
的properties元素是一种为您的实体管理器提供特定实现属性的方法。在Hibernate的情况下,您可以添加大多数hibernate.*属性。您还可以使用hibernate.ejb.classcache.*和hibernate.ejb.collectioncache.*来定义二级缓存信息,请参阅参考文档以获取更多信息。
这对JBoss用户来说是个好消息,.har存档现在是标准化的。在J2EE中一直是一个强大概念的打包现在以一种非常易于使用的方式扩展到ORM世界。
J2SE环境中的打包
一个全新的观点是,PAR打包的简单性在J2SE世界中以完全相同的方式工作。唯一的不同之处在于,您需要通过jta-data-source元素而不是经典的hibernate.*连接属性来定义数据源。PAR存档仍然会被扫描以查找其包含的实体和hbm.xml文件。为了让Hibernate实体管理器发现PAR文件,它们需要在META-INF目录中有一个persistence.xml文件(Hibernate实体管理器基本上请求任何名为META-INF/persistence.xml
的资源,并从中推断PAR存档位置)。
让我们想象以下acmedomainmodel.par存档结构
com/acme/model/Animal.class (an @Entity annotated class) com/acme/model/Dog.class (an @Entity annotated class) com/acme/model/Cat.class (an @Entity annotated class) com/acme/model/Customer.class (a non annotated POJO) com/acme/model/Customer.hbm.xml (the metadata definitions of Customer) META-INF/persistence.xml
其中persistence.xml是
<?xml version="1.0" encoding="UTF-8"?> <entity-manager> <properties> <property name="hibernate.max_fetch_depth" value="4"/> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.connection.username" value="emmanuel"/> <property name="hibernate.connection.password" value="secret"/> <property name="hibernate.connection.url" value="[=>jdbc:mysql:///test]"/> <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/> </properties> </entity-manager>
我的持久化单元名为acmedomainmodel将自动包含Animal, Dog, Cat, Customer。请注意,这些Customer类实际上不必在PAR存档中,只要它们的hbm.xml定义本身在PAR存档中即可。
请注意,您可以通过hibernate.ejb.autodetection来调整发现机制。可能的值有none(无自动检测),类(自动检测注解实体),hbm(自动检测hbm文件)和class,hbm(自动检测注解实体和hbm文件)。
然后您可以使用一个简单的ant任务创建一个包含自动持久化域模型的PAR存档。无需再手动将映射实体添加到hibernate.cfg.xml文件中。
我的应用程序中有多个持久化单元
当然,您可以在应用程序中使用多个PAR存档。将根据您提供的名称处理适当的PAR存档。
//create a keep the emf for later entity manager creations EntityManagerFactory emf = Persistence.createEntityManagerFactory("acmedomainmodel"); ... EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(customer); wolfy = em.find(Dog.class, wolfyId); em.getTransaction().commit(); em.close();
请注意,如果您的类路径中只有一个PAR存档,则无需传递名称到createEntityManagerFactory()方法,但是这样做被认为是良好实践。
PAR存档机制提供了一种非常方便和标准的方式来打包您的ORM持久化单元。通过其自动发现机制,打包设置以非常优雅的方式扩展。