JPA entityManager不保存数据,flush抛出“无进程中的事务”异常

时间:2016-07-20 21:16:51

标签: spring hibernate jpa entitymanager transactional

我无法解决以下问题。我的Spring + JPA + hibernate + Oracle DB应用程序正确地从数据库中读取数据,但不保存它们。我在搜索互联网(也是这个论坛)时发现了类似的问题,但遗憾的是无法在我的代码中修复它。

其中一个想法是在调用entityManager.flush()方法后添加persist(),但之后我会收到异常javax.persistence.TransactionRequiredException: no transaction is in progress

在beginnig上,我还在我的存储库类中使用了EntityManagerFactory,但根据不同的注释,我已将其迁移到EntityManager并使用@PersistenceContext注释。

我将不胜感激任何帮助。

这是我的代码:

的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>hr_db</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>oralce_hr_hibernate</name>
    <description>Oracle HR database</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
        </dependency>        

<!-- http://stackoverflow.com/questions/9898499/oracle-jdbc-ojdbc6-jar-as-a-maven-dependency -->
<!-- mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.3 -Dpackaging=jar -Dfile=ojdbc6.jar -DgeneratePom=true -->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.4</version>
        </dependency>    

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
    </dependency>        

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-commons</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

Job.java:

package com.example.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "JOBS")
public class Job {
    @Id
    @Column(name = "JOB_ID")
    String jobId;

    @Column(name = "JOB_TITLE")
    String jobTitle;

    @Column(name = "min_salary")
    int minSalary;

    @Column(name = "max_salary")
    int maxSalary;

    public Job() {
    }

    public Job(String id) {
        jobId = id;
    }

    public String getJobId() {
        return jobId;
    }

    public void setJobId(String jobId) {
        this.jobId = jobId;
    }

    public String getJobTitle() {
        return jobTitle;
    }

    public void setJobTitle(String jobTitle) {
        this.jobTitle = jobTitle;
    }

    public int getMinSalary() {
        return minSalary;
    }

    public void setMinSalary(int minSalary) {
        this.minSalary = minSalary;
    }

    public int getMaxSalary() {
        return maxSalary;
    }

    public void setMaxSalary(int maxSalary) {
        this.maxSalary = maxSalary;
    }

}

JobRepository.java:

package com.example.repositories.interfaces;

import org.springframework.data.repository.Repository;

import com.example.entities.Job;

public interface JobRepository extends Repository<Job, String> {
    public Job findByJobId(String id);

    public void saveOrUpdate(Job job);

    public void delete(Job job);

    public void deleteByJobId(String jobId);

    public void persistJob(Job job);
}

JobRepositoryImpl.java:

package com.example.repositories;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.example.entities.Job;
import com.example.repositories.interfaces.JobRepository;

@Transactional(propagation = Propagation.REQUIRED)
public class JobRepositoryImpl implements JobRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public JobRepositoryImpl() {
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Job findByJobId(String id) {
        return (Job) entityManager.find(Job.class, id);
    }

    @Override
    public void saveOrUpdate(Job job) {
        entityManager.merge(job);
    }

    @Override
    public void delete(Job job) {
        entityManager.remove(job);
    }

    @Override
    public void deleteByJobId(String jobId) {
        entityManager.remove(findByJobId(jobId));
    }

    @Override
    public void persistJob(Job job) {
        entityManager.persist(job);
        // this is causing javax.persistence.TransactionRequiredException: no transaction is in progress
        // entityManager.flush(); 
    }
}

应用-config.xml中:

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <context:property-placeholder
        location="file:///${app.properties.dir}/db.properties" />

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

    <tx:annotation-driven />

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.example.entities" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.example.entities</value>
            </list>
        </property>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        <property name="persistenceUnitName" value="HR" />
    </bean>

    <bean id="jpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="database" value="ORACLE" />
        <property name="showSql" value="true" />
        <property name="generateDdl" value="false" />
        <property name="databasePlatform" value="org.hibernate.dialect.OracleDialect" />
    </bean>

    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource"
        destroy-method="close">
        <property name="URL" value="${test.oracle.url}" />
        <property name="user" value="${test.oracle.username}" />
        <property name="password" value="${test.oracle.password}" />
        <property name="connectionCachingEnabled" value="true" />
    </bean>

</beans>

库-IMPL-config.xml中:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="jobRepository" class="com.example.repositories.JobRepositoryImpl">
    </bean>

</beans>

JobRepositoryTest.java:

package com.example.repositories;

import static org.junit.Assert.assertEquals;

import java.util.logging.Logger;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.example.entities.Job;
import com.example.repositories.interfaces.JobRepository;

@Transactional(propagation = Propagation.REQUIRED)
public class JobRepositoryTest {

    private static final String TEST_JOB_ID = "TEST_JOB";

    JobRepository repository;

    ConfigurableApplicationContext context;

    Logger logger = Logger.getLogger(JobRepositoryTest.class.getName());

    @Before
    public void setUp() {
        // Create the test configuration for the application from two files
        context = new ClassPathXmlApplicationContext("classpath:/com/example/application-config.xml",
                "classpath:/com/example/repositories/repositories-impl-config.xml");
        // Get the bean to use to invoke the application
        repository = context.getBean(JobRepository.class);
    }

    // Test is passing
    @Test
    public void testFindById() {
        Job job = repository.findByJobId("AD_PRES");
        assertEquals("President", job.getJobTitle());
        assertEquals(20080, job.getMinSalary());
        assertEquals(40000, job.getMaxSalary());
    }

    // Doesn't save the job
    @Test
    @Rollback(false)
    public void testSaveOrUpdateJob() {
        Job job = createTestJob();

        logger.info("BEFORE");
        repository.persistJob(job);
        logger.info("AFTER");
    }


    private Job createTestJob() {
        Job testJob = new Job(TEST_JOB_ID);
        testJob.setJobTitle("Test job title");
        testJob.setMinSalary(0);
        testJob.setMaxSalary(9999);
        return testJob;
    }
}

来自控制台的输出:

INFO: BEFORE
23:13:04.579 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
23:13:04.581 [main] DEBUG org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'JobRepositoryImpl.persistJob' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
23:13:04.586 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
23:13:04.591 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Creating new transaction with name [com.example.repositories.JobRepositoryImpl.persistJob]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
23:13:04.652 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2add4d24 updates=org.hibernate.engine.spi.ExecutableList@3f93e4a8 deletions=org.hibernate.engine.spi.ExecutableList@12b5454f orphanRemovals=org.hibernate.engine.spi.ExecutableList@5445f5ba collectionCreations=org.hibernate.engine.spi.ExecutableList@1431267b collectionRemovals=org.hibernate.engine.spi.ExecutableList@342726f1 collectionUpdates=org.hibernate.engine.spi.ExecutableList@c808207 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@77134e08 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
23:13:04.653 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2add4d24 updates=org.hibernate.engine.spi.ExecutableList@3f93e4a8 deletions=org.hibernate.engine.spi.ExecutableList@12b5454f orphanRemovals=org.hibernate.engine.spi.ExecutableList@5445f5ba collectionCreations=org.hibernate.engine.spi.ExecutableList@1431267b collectionRemovals=org.hibernate.engine.spi.ExecutableList@342726f1 collectionUpdates=org.hibernate.engine.spi.ExecutableList@c808207 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@77134e08 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
23:13:04.653 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtaining JDBC connection
23:13:04.653 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtained JDBC connection
23:13:04.654 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - begin
23:13:04.655 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - initial autocommit status: true
23:13:04.655 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - disabling autocommit
23:13:04.656 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [oracle.jdbc.driver.LogicalConnection@2264e43c]
23:13:04.658 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Opening JPA EntityManager
23:13:04.686 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Registering transaction synchronization for JPA EntityManager
23:13:04.697 [main] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Generated identifier: TEST_JOB, using strategy: org.hibernate.id.Assigned
23:13:04.730 [main] DEBUG org.springframework.orm.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
23:13:04.732 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Initiating transaction commit
23:13:04.732 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2add4d24 updates=org.hibernate.engine.spi.ExecutableList@3f93e4a8 deletions=org.hibernate.engine.spi.ExecutableList@12b5454f orphanRemovals=org.hibernate.engine.spi.ExecutableList@5445f5ba collectionCreations=org.hibernate.engine.spi.ExecutableList@1431267b collectionRemovals=org.hibernate.engine.spi.ExecutableList@342726f1 collectionUpdates=org.hibernate.engine.spi.ExecutableList@c808207 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@77134e08 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
23:13:04.732 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - committing
23:13:04.734 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - committed JDBC Connection
23:13:04.734 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - re-enabling autocommit
23:13:04.735 [main] DEBUG org.springframework.orm.hibernate4.HibernateTransactionManager - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=org.hibernate.engine.spi.ExecutableList@2add4d24 updates=org.hibernate.engine.spi.ExecutableList@3f93e4a8 deletions=org.hibernate.engine.spi.ExecutableList@12b5454f orphanRemovals=org.hibernate.engine.spi.ExecutableList@5445f5ba collectionCreations=org.hibernate.engine.spi.ExecutableList@1431267b collectionRemovals=org.hibernate.engine.spi.ExecutableList@342726f1 collectionUpdates=org.hibernate.engine.spi.ExecutableList@c808207 collectionQueuedOps=org.hibernate.engine.spi.ExecutableList@77134e08 unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] after transaction
23:13:04.735 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Releasing JDBC connection
23:13:04.735 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Released JDBC connection
Jul 20, 2016 11:13:04 PM com.example.repositories.JobRepositoryTest testSaveOrUpdateJob
INFO: AFTER

1 个答案:

答案 0 :(得分:0)

我抛出了同样的异常。我的简单解决方案是不调用flush方法。之后,我可以保存到sqlserver数据库。不是理想的分辨率。经过深入研究后将提供进一步的信息