JPA 实体管理器不保存数据,刷新引发"no transaction in progres"异常



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

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

一开始,我还在存储库类中使用了EntityManagerFactory,但基于不同的注释,我将其迁移为使用带有@PersistenceContext注释的EntityManager

如有任何帮助,我将不胜感激。

这是我的代码:

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

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

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

我也抛出了同样的异常。我的简单解决方案是不调用flush方法。之后,我可以保存到sqlserver数据库中。不是理想的解决方案。进一步的信息将在彻底研究后提供

相关内容

最新更新