java 如何配置 EclipseLink 2.0 和 Spring 3.0.5 和 Tomcat 6?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10421829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure EclipseLink 2.0 and Spring 3.0.5 and Tomcat 6?
提问by jisun
My web application is using Tomcat 6.0.18 and Spring 3.0.5 and eclipselink 2.0.1 and javax.persistence 2.0.0, SQL Server Database. I could not figure out the configuration and also not able to find out a working example with such configurations. I tried to add property of loadTimeWeaver into entityManagerFacotory but it break AutoWired annotation in Spring 3, like below in applicationContext.xml:
我的 Web 应用程序使用 Tomcat 6.0.18 和 Spring 3.0.5 以及 eclipselink 2.0.1 和 javax.persistence 2.0.0,SQL Server 数据库。我无法弄清楚配置,也无法找到具有此类配置的工作示例。我试图将 loadTimeWeaver 的属性添加到 entityManagerFacotory 中,但它破坏了 Spring 3 中的 AutoWired 注释,如下面的 applicationContext.xml:
<context:load-time-weaver/>
in appname-servlet.xml:
在 appname-servlet.xml 中:
But when I disable LoadTimeWeaver, my application can create database from JPA code but could not persist data into database.
但是当我禁用 LoadTimeWeaver 时,我的应用程序可以从 JPA 代码创建数据库,但无法将数据保存到数据库中。
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="restfulPU" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.SQLServerPlatform"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Persistence.xml
<persistence-unit name="restfulPU" transaction-type="RESOURCE_LOCAL">
<class>com.generalform.eclipselink.model.Todo</class>
<properties>
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="database" />
</properties>
I will be thankful if you can point me to a guide or tutorial about integration of EclipseLink into Spring 3 plus Tomcat.
如果您能给我指点有关将 EclipseLink 集成到 Spring 3 和 Tomcat 的指南或教程,我将不胜感激。
回答by jisun
Thanks, James.
谢谢,詹姆斯。
Following Springsource guidance at http://static.springsource.org/spring/docs/3.0.0.M4/reference/html/ch13s05.html, Tomcat 6 works on the weaving. The steps as mentioned in the guidance and copied here:
按照http://static.springsource.org/spring/docs/3.0.0.M4/reference/html/ch13s05.html上的Springsource 指南,Tomcat 6 可以进行编织。指南中提到并在此处复制的步骤:
Step1.Copy spring-tomcat-weaver.jar into $CATALINA_HOME/lib, where $CATALINA_HOME represents the root of the Tomcat installation)
Step1.将spring-tomcat-weaver.jar复制到$CATALINA_HOME/lib中,其中$CATALINA_HOME代表Tomcat安装的根目录)
Step2. Tell Tomcat to use custom classloader by modifying context.xml:
第2步。通过修改 context.xml 告诉 Tomcat 使用自定义类加载器:
<Context path="/myWebApp" docBase="/my/webApp/location">
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false"/>
</Context>
I didn't specify on path and docBase attribute as I put in $CATALINA_HOME/conf/context.xml
当我放入 $CATALINA_HOME/conf/context.xml 时,我没有指定路径和 docBase 属性
Step3. Turn on loadTimeWeaver property to LocalContainerEntityManagerFactoryBean
第三步。将 loadTimeWeaver 属性打开到 LocalContainerEntityManagerFactoryBean
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
</property>
</bean>
then, I started Tomcat 6 again and start-up process becomes clean. However, data still could not be persisted into database. The error is like below:
然后,我再次启动了Tomcat 6,启动过程变得干净了。但是,数据仍然无法持久化到数据库中。错误如下:
Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
不允许在共享 EntityManager 上创建事务 - 改用 Spring 事务或 EJB CMT
My co-worker saved me at this point by pointing out that Spring transaction handling with @Transactional and not use transactions on the entity manager to avoid the issue above. then I commented out em.getTransaction().begin() and em.getTransaction().commit(), leaving em.persist(todo) only. todo is the entity here. It works immediately. Here, developer should be aware that the difference between JPA transaction and Spring transaction. In fact, it's a confused part when EclipseLink/JPA working with Spring Transaction Management.
我的同事在这一点上救了我,指出 Spring 事务处理使用 @Transactional 并且不在实体管理器上使用事务来避免上述问题。然后我注释掉了 em.getTransaction().begin() 和 em.getTransaction().commit(),只留下 em.persist(todo)。todo 是这里的实体。它立即起作用。在这里,开发者应该注意JPA 事务和Spring 事务的区别。实际上,EclipseLink/JPA 与 Spring Transaction Management 一起工作时,这是一个令人困惑的部分。
I also tried Tomcat 7 as I had thought it might be related to Tomcat. In fact, this issue is nothing to do with Tomcat version.
我还尝试了Tomcat 7,因为我认为它可能与Tomcat有关。其实这个问题与Tomcat版本无关。
With LoadTimeWeaver enabled, It works on data persistence. Here is the working version on the transactionManager configuration part in applicationname-servlet.xml:
启用 LoadTimeWeaver 后,它适用于数据持久性。这是 applicationname-servlet.xml 中 transactionManager 配置部分的工作版本:
<context:property-placeholder location="classpath:generalform.properties"/>
<context:component-scan base-package="com.generalform" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mysql.database.driver}" />
<property name="url" value="${mysql.database.url}" />
<property name="username" value="${mysql.database.user}" />
<property name="password" value="${mysql.database.password}" />
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="restfulPU" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" />
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
Below is my Dao class, in formal way, try/catch should be wrapped around the code inside the method:
下面是我的 Dao 类,以正式的方式,try/catch 应该包裹在方法内部的代码中:
@Repository("todoDao")
public class TodoDao {
@PersistenceContext
private EntityManager em;
public void saveTodo(Todo todo) {
System.out.println("TodoDao:saveTodo into DB >>>");
//em.getTransaction().begin();
em.persist(todo);
//em.getTransaction().commit();
em.close();
System.out.println("TodoDao: complete saveTodo into DB close()>>>");
}
}
The TodoService class declares Spring Transaction with @Transactional annotation, @Autowired is also working after enabling LoadTimeWeaver:
TodoService 类使用@Transactional 注解声明了 Spring Transaction,@Autowired 在启用 LoadTimeWeaver 后也工作:
@Service("todoService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class TodoService {
@Autowired
private TodoDao todoDao;
public TodoService() {
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void saveTodo(Todo todo) {
System.out.println("TodoService -> saveTodo is called!");
todoDao.saveTodo(todo);
}
}
回答by James
What error do you get when you try to persist?
当您尝试坚持时,您会遇到什么错误?
The LoadTimeWeaver should work, but it is not required. You could use static weaving instead.
LoadTimeWeaver 应该可以工作,但不是必需的。您可以改用静态编织。
回答by Sarkhan
As an additional way to @jisun's reply.I did it by annotation configuration and removed more properties such as username,password,driver etc.Because all of these parameters can be define in persistence.xml:
作为@jisun 回复的另一种方式。我是通过注解配置完成的,并删除了更多属性,例如用户名、密码、驱动程序等。因为所有这些参数都可以在persistence.xml 中定义:
package com.company.config;
import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.core.env.Environment;
import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver;
import org.springframework.orm.jpa.JpaTransactionManager;
@Configuration
@ComponentScan(basePackages = "com.company")
@EnableTransactionManagement
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Resource
private Environment env;
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setPersistenceXmlLocation("classpath:persistence.xml");
emf.setLoadTimeWeaver(new ReflectiveLoadTimeWeaver());
return emf;
}
@Bean
public JpaTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
}