简体   繁体   English

Spring3 JPA(Hibernate4)没有持久化

[英]Spring3 JPA (Hibernate4) not persisting

I have an application using Spring 3.2.3 and Hibernate 4.2.1.Final. 我有一个使用Spring 3.2.3和Hibernate 4.2.1.Final的应用程序。 I made some configurations and the app works pretty well on the test environment, using HSQLDB, etc. 我做了一些配置,应用程序在测试环境中运行得非常好,使用HSQLDB等。

But when the app is deployed it almost works fine. 但是当部署应用程序时,它几乎可以正常工作。 The entity is created but never persisted. 实体已创建但从未保留。 I can see the JPA logs: 我可以看到JPA日志:

Hibernate: select nextval ('TASK_SEQ') Hibernate:选择nextval('TASK_SEQ')

But an insert never appears =( 但是插件永远不会出现=(

Using the configuration: 使用配置:

 <?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 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> 

The entity: 实体:

@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
}

And finally the service: 最后服务:

@Service
public class TaskService {

    @PersistenceContext
    private EntityManager entityManager;

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

As I said, there are no exceptions being thrown but the entity is not persisted like it is at the tests. 正如我所说,没有异常被抛出,但实体并没有像测试那样持久存在。 Thank you! 谢谢!

Edit: I also tried to remove the persistence.xml content into a spring datasource and the problem is still the same: 编辑:我还尝试将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>

SOLUTION: 解:

I give up the xml configuration. 我放弃了xml配置。 Nothing seems to work with it anymore. 似乎没有任何东西可以用它了。 Reading more about the tendencies and a lot of configuration I ended up trying successfully a java config and with a few more adjustments will fit perfectly. 阅读更多有关趋势和大量配置的信息,我最终成功尝试了java配置并进行了一些调整,这非常适合。 See below: 见下文:

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

First, you should enable a PersistenceAnnotationBeanPostProcessor bean, like so: 首先,您应该启用PersistenceAnnotationBeanPostProcessor bean,如下所示:

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

As documented in Spring 3.1.x doc, section 14.5.2 : Spring 3.1.x doc,第14.5.2节中所述

Spring can understand @PersistenceUnit and @PersistenceContext annotations both at field and method level if a PersistenceAnnotationBeanPostProcessor is enabled. 如果启用了PersistenceAnnotationBeanPostProcessor,Spring可以在字段和方法级别理解@PersistenceUnit和@PersistenceContext注释。

Another thing, make sure your TaskService is scanned. 另一件事,确保您的TaskService被扫描。 According to the posted Spring configuration file, only the package br.com.company is scanned so TaskService should be under that package. 根据发布的Spring配置文件,只扫描包br.com.company ,因此TaskService应位于该包下。

EDIT 编辑

You should use @Transactional for public methods that implement an interface . 您应该将@Transactional用于实现interface public方法。 By default, advice annotation are implemented by Spring via simple Java Proxy , which requires an interface. 默认情况下,Spring通过简单的Java Proxy实现通知注释,这需要一个接口。

As documented in section 8.1.3 AOP Proxies : 第8.1.3节AOP代理中所述

Spring AOP defaults to using standard J2SE dynamic proxies for AOP proxies. Spring AOP默认使用AOP代理的标准J2SE动态代理。 This enables any interface (or set of interfaces) to be proxied. 这使得任何接口(或接口集)都可以被代理。

Of course, this also implies that TaskService should be referenced by other beans via that interface alone. 当然,这也意味着TaskService应该仅通过该接口由其他bean引用。

I've faced an issue similar to the one described. 我遇到了类似于描述的问题。 I found the problem in incorrect usage of @Transactional notation, in particular I've wrongly used javax.transaction.Transactional instead of org.springframework.transaction.annotation.Transactional 我发现@Transactional表示法的使用不正确的问题,特别是我错误地使用了javax.transaction.Transactional而不是org.springframework.transaction.annotation.Transactional

Take a look to the imports of your "@Service". 看一下“@Service”的导入。

A detailed description of the difference can be found here at javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional 有关差异的详细说明,请参见javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional

As TaskService is defined as a service therefore Spring container won't maintain transactions for CRUD operations. 由于TaskService被定义为服务,因此Spring容器不会维护CRUD操作的事务。 You should delegate CRUD operations to another bean -normally I suffix them with Managers. 您应该将CRUD操作委托给另一个bean - 通常我将它们与Managers后缀。

So this will be the full hierarchy of transaction workflow: 这将是事务工作流的完整层次结构:

  1. Create a normal bean. 创建一个普通的bean。 Let's say TaskManager 我们说TaskManager
  2. Inject newly created class into TaskService 将新创建的类注入TaskService

@Resource(name = "taskManager") @Resource(name =“taskManager”)

TaskManager taskManager; TaskManager taskManager;

3 . 3。 Inject EntityManager etc in newly created Manager class 在新创建的Manager类中注入EntityManager

4 . 4。 Put all CRUD methods in the manager class 将所有CRUD方法放在manager类中

5 . 5。 Call these methods from Service 从Service调用这些方法

Call hierarchy: Service -> Manager -> DAO -> Entity Manager 呼叫层次结构:服务 - >管理器 - > DAO - >实体管理器

Now you should be able to persist your entity. 现在你应该能够坚持你的实体了。

I would first doublecheck some obvious stuff: Was the Task type is of br.com.company.Task, not other java api Task ? 我首先要仔细检查一些明显的东西:Task类型是br.com.company.Task,而不是其他java api任务?

If you're still having the same problem, maybe something is wrong with your transaction management. 如果您仍然遇到同样的问题,那么您的交易管理可能出现问题。 Try flushing the entityManager after you persists. 保持后尝试刷新entityManager。 Typically entityManager should automatically flush at the end of transactions: 通常,entityManager应在事务结束时自动刷新:

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

If you do have a problem with transaction manager, try instead of specifying datasource inside persistence.xml, create it on spring xml and use dataSource property of JpaTransactionManager 如果您确实遇到了事务管理器的问题,请尝试而不是在persistence.xml中指定数据源,在spring xml上创建它并使用JpaTransactionManager的dataSource属性

Also set following log4j logger to see transaction start/end and SQL issued by hibernate: 还可以在log4j logger之后设置以查看hibernate发出的事务开始/结束和SQL:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM