【问题标题】:Spring3 JPA (Hibernate4) not persistingSpring3 JPA(Hibernate4)不持久
【发布时间】:2013-07-14 20:28:32
【问题描述】:

我有一个使用 Spring 3.2.3 和 Hibernate 4.2.1.Final 的应用程序。 我做了一些配置,应用在测试环境中运行良好,使用 HSQLDB 等。

但是当应用程序部署时,它几乎可以正常工作。实体已创建但从未持久化。 我可以看到 JPA 日志:

休眠: 选择 nextval ('TASK_SEQ')

但是插入永远不会出现=(

使用配置:

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd  
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <context:component-scan base-package="br.com.company" />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="spring_pu" />
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <context:annotation-config />
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

</beans>

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="spring_pu" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>br.com.company.core.entities.Task</class>
        <properties>
                <property name="hibernate.connection.autocommit" value="true" />
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.format_sql" value="true" />
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
        <property name="hibernate.hbm2ddl.auto" value="update" />

            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
            <property name="hibernate.connection.url" value="jdbc:postgresql://127.0.0.1:5432/companyDB" />
            <property name="hibernate.connection.user" value="postgres" />
            <property name="hibernate.connection.password" value="*****" />
        </properties>
    </persistence-unit>
</persistence> 

实体:

@Entity
@Table(name = "TASK")
public class Task implements Serializable {

    private static final long serialVersionUID = -6262731134419520342L;

    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "TASK_SEQ", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(sequenceName = "TASK_SEQ", name = "TASK_SEQ")
    private long id;

    @Column(name = "DESCRIPTION")
    private String description;

    @Column(name = "FINISHED")
    private boolean fininshed;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "FINISH_DATE")
    private Date finishDate;

//getters and setter below
}

最后是服务:

@Service
public class TaskService {

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional(propagation = Propagation.REQUIRED)
    public void createTask(Task task) {
    <b>//invoked method</b>
        entityManager.persist(task);
    }

正如我所说,没有抛出异常,但实体没有像在测试中那样持久化。 谢谢!

编辑:我也尝试将persistence.xml内容删除到spring数据源中,问题还是一样:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd  
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://127.0.0.1:5432/KCILDS" />
        <property name="username" value="postgres" />
        <property name="password" value="*****" />
    </bean>

    <context:component-scan base-package="br.com.company" />

    <bean id="myEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="br.com.company.core.entities" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="myEntityManagerFactory" />
    </bean>

    <context:annotation-config />
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

</beans>

解决方案:

我放弃了xml配置。似乎没有什么可以再使用它了。 阅读更多关于趋势和大量配置的信息,我最终成功地尝试了一个 java 配置,并进行了一些调整,这将非常适合。 见下文:

    @Configuration
    @EnableTransactionManagement
    @ComponentScan("br.com.company")
    public class PersistenceJPAConfig {

        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
            LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
            factoryBean.setDataSource(this.directDataSource());
            factoryBean.setPackagesToScan(new String[] { "br.com.company" });

            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setShowSql(true);

            factoryBean.setJpaVendorAdapter(vendorAdapter);
            factoryBean.setJpaProperties(this.additionlProperties());

            return factoryBean;
        }

        private Properties additionlProperties() {
            Properties properties = new Properties();
            properties.put("database", "POSTGRESQL");
            properties.put("databasePlatform", "org.hibernate.dialect.PostgreSQLDialect");
            properties.put(Environment.SHOW_SQL, true);
            properties.put(Environment.FORMAT_SQL, true);
            return properties;
        }

// now reasearch how to make it an environment configuration
    //  @Bean
    //  public DataSource dataSource() {
    //      JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
    //      jndiDataSourceLookup.setResourceRef(true);
    //      return jndiDataSourceLookup.getDataSource("jdbc/mybank");
    //  }

        @Bean
        public DataSource directDataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("org.postgresql.Driver");
            dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/MyBank");
            dataSource.setUsername("postgres");
            dataSource.setPassword("*******");
            return dataSource;
        }

        @Bean //still trying to make a JTA Transaction
        public PlatformTransactionManager transactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(this.entityManagerFactoryBean().getObject());
            return transactionManager;
        }

        @Bean
        public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
            return new PersistenceExceptionTranslationPostProcessor();
        }
    }

【问题讨论】:

  • 我想你在服务中错过了begin()(persist 之前)和commit()(persist 之后)方法 :),应该是这样的entityManager.begin(); entityManager.persist(task);entityManager.commit();
  • 我可以将 Spring 配置为自动进行这些事务调用(开始和提交)吗?顺便说一句,该建议导致异常:java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - 使用 Spring 事务或 EJB CMT 代替 org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java :199)
  • 将xml配置&lt;persistence-unit name="spring_pu" transaction-type="RESOURCE_LOCAL"&gt;这一行改成&lt;persistence-unit name="spring_pu" transaction-type="JTA"&gt;
  • 对于自动提交模式,将这个属性&lt;property name="hibernate.connection.autocommit" value="true" /&gt;也添加到persistence.xml中
  • 自动提交已设置。更改事务类型会导致几个异常。我相信这需要在 context.xml 中更改一些事务配置。

标签: java spring hibernate jpa


【解决方案1】:

首先,您应该启用PersistenceAnnotationBeanPostProcessor bean,如下所示:

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

Spring 3.1.x doc, section 14.5.2 中所述:

Spring 可以理解@PersistenceUnit 和@PersistenceContext 字段和方法级别的注释,如果 PersistenceAnnotationBeanPostProcessor 已启用。

另外,请确保您的TaskService 已被扫描。根据发布的 Spring 配置文件,仅扫描包 br.com.company,因此 TaskService 应该在该包下。

编辑

您应该将@Transactional 用于实现interfacepublic 方法。默认情况下,advice注解是Spring通过simple Java Proxy实现的,需要一个接口。

section 8.1.3 AOP Proxies 中所述:

Spring AOP 默认为 AOP 使用标准 J2SE 动态代理 代理。这使得任何接口(或一组接口)都可以 代理。

当然,这也意味着 TaskService 应该被其他 bean 单独通过该接口引用。

【讨论】:

  • 感谢您的回复。刚刚添加了 PersistenceAnnotationBeanPostProcessor 但仍然无法正常工作。还检查了扫描包,我的所有服务、存储库和组件都在 br.com.company 下。我在事务配置中遗漏了什么吗?
  • @Marcelo 看到我的新编辑,你应该为带注释的方法使用接口。
【解决方案2】:

我遇到了与上述类似的问题。 我发现错误使用@Transactional 表示法的问题,特别是我错误地使用了javax.transaction.Transactional 而不是org.springframework.transaction.annotation.Transactional

查看“@Service”的导入。

可以在javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional这里找到差异的详细描述

【讨论】:

    【解决方案3】:

    由于TaskService 被定义为服务,因此 Spring 容器不会为 CRUD 操作维护事务。您应该将 CRUD 操作委托给另一个 bean - 通常我使用 Managers 为它们添加后缀。

    所以这将是事务工作流的完整层次结构:

    1. 创建一个普通的bean。假设TaskManager
    2. 将新创建的类注入到TaskService中

    @Resource(name = "taskManager")

    任务管理器任务管理器;

    3 .在新创建的Manager类中注入EntityManager

    4 .将所有 CRUD 方法放在管理器类中

    5 .从 Service 调用这些方法

    调用层次结构:Service -> Manager -> DAO -> Entity Manager

    现在您应该能够持久化您的实体了。

    【讨论】:

    • 我在这里没有成功。刚刚创建了一个 TaskRepository 并注入了 EntityManager。然后在服务中使用此存储库。相同的结果 =(
    • 当你说 DAO 层时,它应该是什么样子?
    • @JSS 我相信这不是真的,@Service 非常适合声明式事务。
    【解决方案4】:

    我会首先仔细检查一些明显的东西:Task 类型是 br.com.company.Task,而不是其他 java api Task 吗?

    如果您仍然遇到同样的问题,则可能是您的事务管理有问题。坚持后尝试刷新 entityManager。通常 entityManager 应该在事务结束时自动刷新:

    @Transactional(propagation = Propagation.REQUIRED)
    public void createTask(Task task) {
      entityManager.persist(task);
      entityManager.flush(task);
    }
    

    如果您确实对事务管理器有问题,请尝试不要在 persistence.xml 中指定数据源,而是在 spring xml 上创建它并使用 JpaTransactionManager 的 dataSource 属性

    还设置以下 log4j 记录器以查看事务开始/结束和休眠发出的 SQL:

    log4j.logger.org.hibernate.SQL=DEBUG
    log4j.logger.org.hibernate.transaction=DEBUG
    

    【讨论】:

    • 你是对的,事务管理有问题。当我添加刷新时,弹出此异常:javax.persistence.TransactionRequiredException:没有正在进行的事务将原始帖子编辑到实际的 context.xml。感谢您的帮助。
    • 更新了我的答案,让您尝试移动数据源设置
    • 我已经尝试了建议的 teste,但问题仍然存在。我编辑了原始线程以添加信息。很明显,交易没有被正确激活。有什么提示吗?谢谢!
    • 尝试按照我上面的回答中指定的方式启用休眠日志记录,如果您看不到休眠打开/关闭事务,那么可能是 jdk 代理/aspectj 设置问题。为了证明这一点,请尝试创建一个使用程序化事务的方法
    猜你喜欢
    • 1970-01-01
    • 2012-05-28
    • 2021-08-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2014-09-29
    • 1970-01-01
    • 2011-09-22
    相关资源
    最近更新 更多