3

I cannot solve following issue. My Spring + JPA + hibernate + Oracle DB application properly reads data from the database, but doesn't save them. I found similar issues searching the Internet (also this forum) but unfortunately was not able to fix it in my code.

One of the idea is to add entityManager.flush() after calling the persist() method but then I am getting an Exception javax.persistence.TransactionRequiredException: no transaction is in progress.

On the beginnig I also used EntityManagerFactory in my repository class, but based on different comments I've migrated it to use EntityManager with @PersistenceContext annotation.

I will be appreciate for any help.

Here is my code:

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

Output from console:

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
kpater87
  • 1,190
  • 12
  • 31
  • 1
    Finally an answer from this question http://stackoverflow.com/questions/5372859/no-transaction-starts-within-spring-transactional-method solved my issue. – kpater87 Jul 21 '16 at 05:26

1 Answers1

1

I had the same exception thrown. My simple solution to it was to not call the flush method. After that, I could save to the sqlserver database. Not the ideal resolution. Further information will provided after thoroughly researching

ramirez
  • 11
  • 2
  • Check this question: http://stackoverflow.com/questions/5372859/no-transaction-starts-within-spring-transactional-method. I found a solution for my problem there. – kpater87 Mar 22 '17 at 18:20