Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT
Asked Answered
F

5

64

This post is in continuation of JPA How to get the value from database after persist

When I execute the following I am getting following exception, how can I resolve this?

Not allowed to create transaction on shared EntityManager - use Spring 
transactions or EJB CMT

DAOImpl code

public void create(Project project) {
        entityManager.persist(project);
        entityManager.getTransaction().commit();
        project = entityManager.find(Project.class, project.getProjectId());
        entityManager.refresh(project);
        System.out.println("Id    -- " + project.getProjectId());
            System.out.println("no -- " + project.getProjectNo());
    }

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id="DataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="username" value="scott" />
        <property name="password" value="tiger" />
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@myserver:1521:ORCL" />
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="DataSource" />
        <property name="packagesToScan" value="test.entity" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="false" />
                <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
            </bean>
        </property>
    </bean>

    <context:component-scan base-package="test.net" />

    <tx:annotation-driven transaction-manager="transactionManager"/> 

     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>         

     <context:annotation-config/>

</beans>
Famed answered 25/7, 2013 at 14:21 Comment(0)
S
67

I guess the problem here is that although you have defined the bean for the transaction manager, you haven't annotated the create() method with @Transactional which enables spring transactions.

Also remove the entityManager.getTransaction().commit(); statement as now all the transaction management will be handled by spring, if you leave the statement as it is then you will get the same error again.

Stevenson answered 13/8, 2013 at 6:12 Comment(2)
when you autowire the entitymanager with @PersistenceContext i still get the same error even when i annotate the method with Transactional and remove the commit statementVinculum
Like maurice said, this doesnt resolve my issue. I get :javax.persistence.TransactionRequiredException: Executing an update/delete query" errorConcave
O
36

Injecting EntityManagerFactory instead of EntityManager and javax.transaction.Transactional annotation on method solved my issue as shown below.

//Autowire EntityManagerFactory
@PersistenceUnit(unitName = "readwrite.config")
private EntityManagerFactory entityManagerFactory;


//Use below code on create/update
EntityManager entityManager = entityManagerFactory.createEntityManager();

entityManager.getTransaction().begin();
if (!ObjectUtils.isEmpty(entity) && !entityManager.contains(entity)) {
   entityManager.persist(entity);
   entityManager.flush();
}
entityManager.getTransaction().commit();
Ollie answered 9/11, 2018 at 5:19 Comment(6)
This resolved my problem but my only question is if we can create entityManager from entityManagerFactory as a class member property and use it in different methods that I have forexample in my dao class?Penman
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'readwrite.config' availableReenareenforce
This solved my problem. But how why @Transactaional annotation not working instead of begin()??Kingsly
@geneb. you put 'default' instead 'readwrite.config'Procurable
It will work without mentioning (unitName = "readwrite.config") as well otherwise it will give errorAeroneurosis
This is great and all, but in my case the database is not updated when I call commit its not updating the database directly, well at least its not waiting on the current thread to do so and this is quite important seeing that the db has more than 100k records and the user needs to get notified once its done so that they can view the records on the web application. Does anyone have any suggestions for my use case?Negligible
P
9

You need to remove the statement entityManager.getTransaction().begin() and annotate the method using @Transactional? which enables transaction handling by Spring.

Paregmenon answered 16/2, 2020 at 9:27 Comment(0)
S
3

In my case inside Sping-boot this solution worked

@Transactional(propagation = Propagation.NEVER)
public void myMethod() {

    SessionImplementor sessionImp = (SessionImplementor) em.getDelegate();
    var transaction = sessionImp.getTransaction();
    for (MyClass cls : lst) {
        try {
            transaction.begin();
            //do my stuffs with em
            transaction.commit();
        } catch (Exception e) {
            transaction.rollback();
        }
    }
}
Soup answered 8/5, 2023 at 21:41 Comment(0)
C
0

For me this worked: I had declared EntityManager in a different file with the same name. So I just changed the name of EntityManager variable and it worked. The hint i used was, "shared instances".

File 1:

//Before: 
EntityManager entityManager;
//After: 
EntityManager entityManagerrr;

File 2:

//And in the other file it is:
EntityManager entityManager;
Coffer answered 23/5 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.