现在需要下载Hibernate。Hibernate的 站点整洁、内容丰富,而且下载过程没有一点儿延迟。两个单独的下载包括Hibernate Core version 3.2和一个称为Hibernate EntityManager vers的JPA覆盖。
<target name="install-hibernate">
<property name="domain.lib" value="C:/bea/wlserver_10.0/samples/domains/wl_server/lib"/>
<property name="hibernate.core.dir" value="D:/hibernate/core-3.2"/>
<property name="hibernate.core.dir" value="D:/hibernate/entitymanager-3.3.1"/>
<copy todir="${domain.lib}" overwrite="false">
<fileset dir="${hibernate.core.dir}">
<include name="hibernate*.jar"/>
</fileset>
<fileset dir="${hibernate.core.dir}/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${hibernate.jpa.dir}">
<include name="hibernate*.jar"/>
</fileset>
<fileset dir="${hibernate.jpa.dir}/lib">
<include name="*.jar"/>
</fileset>
</copy>
</target>
如何告知Weblogic Server关于Hibernate类库的信息?但重要的是我们需要哪个类库?在Hibernate Core中,我发现了39个库,而它的 JPA覆盖有6个之多。我采用了省事的方式。在这个简单的 Ant任务的帮助下,将所有的45个库放入了Weblogic Server实例域的共享库(即${bea.home}/wlserver_10.0/samples/domains/wl_server/lib)中。
当然,有些库应该更容易区分,应该除去那些明显的诸如jta.jar或junit-3.8.1.jar的库。现在这些库中许多是Weblogic Server 10.0集成的一部分。实际上,已经在${bea.home}/modules目录中发现了140个jar。要知道有很多关于Weblogic中的antlr库与Hibernate中的antlr库之间发生冲突的恐怖故事,不过我还未遇到过。
关于在共享空间放置Hibernate库的重点是它们没有与应用程序封装在一起。在相同的域中部署的任何应用程序现在都可以使用Hibernate。当有许多依赖于不同Hibernate版本的应用程序时,很明显这种方式不再适用了。否则,在共享库中的这种放置方式可以避免其他的问题(产生问题的bug还没有投下阴影)。
部署和运行
现在,已经安装了Hibernate,编写了Java源,配置文件和构建脚本也已经绪。下一步要对应用程序进行编译、封装和部署。我正是这样做的。
$ ant -Dprovider=hibernate deploy
在服务器端,我得到一个堆栈跟踪:(
weblogic.application.ModuleException: Exception preparing module: EJBModule(hibernate-ejb.jar)
at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:399)
at weblogic.application.internal.flow.ModuleListenerInvoker.prepare(ModuleListenerInvoker.java:93)
at weblogic.application.internal.flow.DeploymentCallbackFlow$1.next(DeploymentCallbackFlow.java:360)
at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:26)
at weblogic.application.internal.flow.DeploymentCallbackFlow.prepare(DeploymentCallbackFlow.java:56)
Truncated. see log file for complete stacktrace
org.hibernate.HibernateException: The chosen transaction strategy requires access to the JTA TransactionManager
at org.hibernate.impl.SessionFactoryImpl.(SessionFactoryImpl.java:329)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:915)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:730)
at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:127)
这个错误消息是有意义的。persistence.xml的配置没有指定事务类型。容器环境中默认的事务类型是JTA。当未将它被告知Weblogic Server的事务管理器的信息时,Hibernate会有所抱怨。配置Hibernate使之明确使用本地事务怎么样?我编辑了persistence.xml
<persistence-unit name="test"
transaction-type="RESOURCE_LOCAL">
然后再次运行构建脚本,它将部署并运行JUnit测试,
$ ant -Dprovider=hibernate
让我惊喜的是,这次部署的应用程序没有出错。但是测试没有成功。
[echo] Running JUnit Test: junit.TestJPAService ...
[junit] Logical Persistence Provider is [hibernate]
[junit] Actual Persistence Provider is [org.hibernate.impl.SessionImpl]
[junit] Test junit.TestJPAService FAILED
[echo] *** ERROR: There are test failures. Output is shown below
[concat] Testsuite: junit.TestJPAService
[concat] Tests run: 2, Failures: 1, Errors: 0, Time elapsed: 2.934 sec
[concat]
[concat] ------------- Standard Output ---------------
[concat] Contacting server t3://localhost:7001 as weblogic for JPAService
[concat] ------------- ---------------- ---------------
[concat] ------------- Standard Error -----------------
[concat] Logical Persistence Provider is [hibernate]
[concat] Actual Persistence Provider is [org.hibernate.impl.SessionImpl]
[concat] ------------- ---------------- ---------------
[concat] Testcase: testLog(junit.TestJPAService): FAILED
[concat] Message is not assigned any identifier
[concat] junit.framework.AssertionFailedError: Message is not assigned any identifier
[concat] at junit.TestJPAService.testLog(Unknown Source)
通过了一个测试。用org.hibernate.impl.SessionImpl,确切地说,是它的代理对这个bean进行了注入。
但是,为什么向 Message实例分配标识符没有成功?
这只不过因为我们设计bean使用容器管理事务,而现在却配置为使用本地事务。所以我们的bean代码和容器都没有提交事务,而且因为标识值指定为由提供者赋值(见Message.java中的@Id注释)并且由Hibernate利用数据库列的自动增量特性为标识赋值——所以也没有提交表示没有标识值赋值。
当然,我们能够在JPAServiceBean.log()方法中添加明确的事务分界;但这不是解决方案。在容器环境中,我们倾向于使用容器管理的事务,倾向于配置持久性单元使用JTA。
如何告知Hibernate使用Weblogic事务管理器并将它的事务与容器事务结合起来?我通过Google进行了几分钟的搜索找到了答案。向persistence.xml添加以下属性。