我无法解决以下问题。我的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
答案 0 :(得分:0)
我抛出了同样的异常。我的简单解决方案是不调用flush方法。之后,我可以保存到sqlserver数据库。不是理想的分辨率。经过深入研究后将提供进一步的信息