4

我的 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/>

在 appname-servlet.xml 中:

但是当我禁用 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>

如果您能指出有关将 EclipseLink 集成到 Spring 3 和 Tomcat 中的指南或教程,我将不胜感激。

4

3 回答 3

5

谢谢,詹姆斯。

遵循http://static.springsource.org/spring/docs/3.0.0.M4/reference/html/ch13s05.html上的Springsource 指南,Tomcat 6 可以进行编织。指南中提到并在此处复制的步骤:

Step1.将spring-tomcat-weaver.jar复制到$CATALINA_HOME/lib中,其中$CATALINA_HOME代表Tomcat安装的根目录)

第2步。通过修改 context.xml 告诉 Tomcat 使用自定义类加载器:

<Context path="/myWebApp" docBase="/my/webApp/location">
    <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
        useSystemClassLoaderAsParent="false"/>
</Context>

我没有在 $CATALINA_HOME/conf/context.xml 中指定路径和 docBase 属性

第三步。将 loadTimeWeaver 属性打开到 LocalContainerEntityManagerFactoryBean

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="loadTimeWeaver">
    <bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
  </property>
</bean> 

然后,我再次启动 Tomcat 6,启动过程变得干净。但是,数据仍然无法持久化到数据库中。错误如下:

不允许在共享 EntityManager 上创建事务 - 改用 Spring 事务或 EJB CMT

在这一点上,我的同事通过指出 Spring 事务处理使用 @Transactional 并且不使用实体管理器上的事务来避免上述问题来拯救了我。然后我注释掉了 em.getTransaction().begin() 和 em.getTransaction().commit(),只留下了 em.persist(todo)。todo 是这里的实体。它立即起作用。在这里,开发者应该知道 JPA 事务和 Spring 事务的区别。事实上,当 EclipseLink/JPA 与 Spring 事务管理一起工作时,这是一个令人困惑的部分。

我还尝试了 Tomcat 7,因为我认为它可能与 Tomcat 有关。其实这个问题与Tomcat版本无关。

启用 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> 

下面是我的 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()>>>");
    }   

}   

TodoService 类用@Transactional 注解声明Spring Transaction,启用LoadTimeWeaver 后@Autowired 也起作用:

@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);
    }
}   
于 2012-05-03T22:14:25.680 回答
0

当您尝试坚持时,您会遇到什么错误?

LoadTimeWeaver 应该可以工作,但这不是必需的。您可以改用静态编织。

于 2012-05-03T14:12:59.597 回答
0

作为@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());
    }

}
于 2017-03-05T09:28:40.383 回答