128

I am using hibernate JPA with spring and mongodb and I am running my application on Glassfish-4.0.

My service class is:

@Component
public class Test {
    @PersistenceContext
    EntityManager em;
    EntityManagerFactory emf;
         
    @Transactional
    public String persist(Details details) {
        details.getUsername();
        details.getPassword();

        Query query = em.createNativeQuery("db.details.find(username="+details.getUsername()+"&password="+details.getPassword());

        em.getTransaction().begin();
        em.persist(details);
        em.getTransaction().commit();
        em.flush();
        em.clear();
        em.close();
        query.executeUpdate();
        System.out.println("Sucessful!");
        return "persist";        
    }
}

And my spring-context.xml is :

<?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:p="http://www.springframework.org/schema/p"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="com.javapapers.spring.mvc" />
    <context:annotation-config />
    <mvc:annotation-driven />
    <tx:annotation-driven transaction-manager="txManager" />
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="ogmTest"/>
    </bean>
    <bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    </bean>
</beans>

I am getting "TransactionRequiredException Executing an update/delete query"

How can this error be resolved?

starball
  • 20,030
  • 7
  • 43
  • 238
user41498
  • 1,421
  • 3
  • 10
  • 9
  • Try to remove `em.getTransaction().begin();em.getTransaction().commit();em.flush();em.clear();em.close();` it should be up to spring to manage your transaction – kamil Sep 13 '14 at 09:15
  • Thanks for the response i have tried with what you have suggested but their is no change. – user41498 Sep 13 '14 at 10:45
  • Hibernate JPA(Spring Data JPA) with mongo?I dont think it will work - Mongo being NoSQL doesnt comply with ACID properties. spring-data-mongodb is something which you should be using. – balboa_21 Apr 13 '18 at 07:21

30 Answers30

118

I am not sure if this will help your situation (that is if it stills exists), however, after scouring the web for a similar issue.

I was creating a native query from a persistence EntityManager to perform an update.

Query query = entityManager.createNativeQuery(queryString);

I was receiving the following error:

caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query

Many solutions suggest adding @Transactional to your method. Just doing this did not change the error.

Some solutions suggest asking the EntityManager for a EntityTransaction so that you can call begin and commit yourself. This throws another error:

caused by: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead

I then tried a method which most sites say is for use application managed entity managers and not container managed (which I believe Spring is) and that was joinTransaction().

Having @Transactional decorating the method and then calling joinTransaction() on EntityManager object just prior to calling query.executeUpdate() and my native query update worked.

starball
  • 20,030
  • 7
  • 43
  • 238
Drew Corbin
  • 1,181
  • 1
  • 7
  • 3
  • 6
    For those reading this, to call joinTransaction you do em.joinTransaction(); (where em is your EntityManager object) (also, one of the spellings of the function in the answer above is bad, which is why you'll get the red squigglies in Eclipse if you just copy/paste. Instead, you can copy/paste the code in this comment here.) – Michael Tontchev Apr 09 '15 at 15:29
  • 3
    with third solution i get this error: org.springframework.dao.InvalidDataAccessApiUsageException: No local transaction to join; nested exception is javax.persistence.TransactionRequiredException: No local transaction to join – Shilan Mar 26 '19 at 13:51
  • 1
    I used the factory instead and in each and every methoda I get the entityManager and handle the transaction manually with transaction.begin and commit() EntityManager entityManager = entityManagerFactory.createEntityManager(); – Shilan Mar 26 '19 at 13:57
  • This should be accepted as answer when when you are playing with native queries, you will need to do `entityManager.joinTransaction();` – Danyal Sandeelo Jan 26 '20 at 12:18
  • 1
    I was so blind! Thanks for this advice ... I just forgot the @Transactional annotation – HerTesla Feb 04 '20 at 14:00
  • Does not help for me - The only result is: java.lang.IllegalStateException: Not allowed to join transaction on shared EntityManager - use Spring transactions or EJB CMT instead. (I HAVE the Spring transaction) – Gangnus Dec 06 '20 at 16:53
  • I am learning spring boot I have the same error but I don't know where you implement this solution below is my query. *@Modifying @Query(nativeQuery = true, value = "update loan_application set transaction_status = :transaction_status where id =:id") void updateLoanApplicationStatus(@Param("transaction_status") int transaction_status,@Param("id") BigInteger id);* – lewis machilika Aug 04 '21 at 13:34
98

In my case, I had the wrong @Transactional imported.

The correct one is:

import org.springframework.transaction.annotation.Transactional;

and not

import javax.transaction.Transactional;
Abraham
  • 8,525
  • 5
  • 47
  • 53
User-8017771
  • 1,512
  • 1
  • 11
  • 17
64

I have also faced same issue when I work with Hibernate and Spring Jpa Data Repository. I forgot to place @Transactional on spring data repository method.

Its working for me after annotating with @Transactional.

Satya P
  • 747
  • 6
  • 8
  • 19
    This helped me ... I needed both "@Transactional" and "@Modifying" on the JPA repository method. Just having this on my service method (which calls the JPA repository) did not seem to be enough. – Mark Miller May 18 '17 at 15:40
  • 4
    THIS HELPED ME. @Transactional was required on the JPA DAO Repository method too! Unbelievable! You are a lifesaver, Satya P!! – gene b. Dec 16 '17 at 20:23
  • 2
    Agreed, this is required if using @Modifing queries. – sinedsem Sep 23 '18 at 10:50
51

as form the configuration xml it is clear that you are going to use spring based transaction. Please make sure that the import which you are using for @Transactional is "org.springframework.transaction.annotation.Transactional"

in your case it might be "javax.transaction.Transactional"

Gaurav Jeswani
  • 4,410
  • 6
  • 26
  • 47
Chetan Verma
  • 735
  • 5
  • 10
17

I received this exception when trying to run a bulk UPDATE query in a non-JTA (i.e. resource-local) entity manager in Java SE. I had simply forgotten to wrap my JPQL code in

em.getTransaction().begin();

and

em.getTransaction().commit();
JL_SO
  • 1,742
  • 1
  • 25
  • 38
15

I Got the same error.

I just added the @Transactional annotation of javax.transaction.Transactional on the method.

Update:

I would recommend using Spring's @Transactional annotation from org.springframework.transaction.annotation.Transactional;

Akshay Pethani
  • 2,390
  • 2
  • 29
  • 42
13

Using @Modifying and @Transaction fixed me

  1. @Modifying @Query(value="DELETE FROM lock WHERE user_id = ?1" ,nativeQuery=true) void deleteByUserId(Long userId);

  2. @Service @Transactional

Shahid Hussain Abbasi
  • 2,508
  • 16
  • 10
9

How about moving @Transactional from method to class level? Worked for me in similar case, though I'm not 100% certain why.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
mvmn
  • 3,717
  • 27
  • 30
  • 2
    This works . import `import org.springframework.transaction.annotation.Transactional;` and add @Transactional to class level . – sapy Apr 09 '19 at 02:18
  • I don't know why either, I've tried to add '@Transactional' to all different methods, no luck, but once moved it to class level, the magic happens... – Fisher Coder Feb 21 '20 at 16:42
  • have you add them to private methods? If so, @Transactional has no effect on them. In that case adding on class might help. – michal.jakubeczy Aug 02 '21 at 07:40
8

Just add @Transactional on method level or class level. When you are updating or deleting record/s you have to maintain persistence state of Transaction and @Transactional manages this.

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

Deva
  • 1,851
  • 21
  • 22
4

You need not to worry about begin and end transaction. You have already apply @Transactional annotation, which internally open transaction when your method starts and ends when your method ends. So only required this is to persist your object in database.

 @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})

         public String persist(Details details){
             details.getUsername();
             details.getPassword();
             Query query = em.createNativeQuery("db.details.find(username= "+details.getUsername()+"& password= "+details.getPassword());

             em.persist(details);
             System.out.println("Sucessful!");
            return "persist";        
     }

EDIT : The problem seems to be with your configuration file. If you are using JPA then your configuration file should have below configuration

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
    p:entityManagerFactory-ref="entityManagerFactory" />
<bean id="jpaAdapter"
    class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
    p:database="ORACLE" p:showSql="true" />
<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:persistenceUnitName="YourProjectPU"
    p:persistenceXmlLocation="classpath*:persistence.xml"
    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
    <property name="loadTimeWeaver">
        <bean
            class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
    </property>
    <property name="persistenceProvider" ref="interceptorPersistenceProvider" />

</bean>
DeepInJava
  • 1,871
  • 3
  • 16
  • 31
  • Hi @sanket thanks for the response i have tried your suggestion i am geting the same error. – user41498 Sep 13 '14 at 10:46
  • i have edited my solution. See above. Problem seems to be with your configuration file. – DeepInJava Sep 13 '14 at 11:58
  • It worked without jpa Adapter by adding @Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class}) but it is not going to database. collection is not created at database – user41498 Sep 16 '14 at 08:58
  • 1
    i have missed bean **"entityManagerFactory** in my solution.i have edited my solution – DeepInJava Sep 16 '14 at 09:47
  • If i use Jpa vendor adapter it show some errors so can you please specify me without jpa vendor adapter. Because here i am using mongodb – user41498 Sep 16 '14 at 10:10
  • You can refer this link http://www.datanucleus.org/products/datanucleus/jpa/guides/tutorial_mongodb.html – DeepInJava Sep 16 '14 at 10:22
3

Nothing seemed to work for me until I realized that my method was declared as public final instead of just public. The error was being caused by the final keyword. Removing it made the error go away.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
3xCh1_23
  • 1,491
  • 1
  • 20
  • 39
  • 2
    The edit did not add or improve the solution and therefore was not necessary. Thank you for (what you consider) an improved grammar. I would have preferred a more productive approach. – 3xCh1_23 Aug 20 '17 at 19:06
  • 2
    Another thing to take note of is that package level visibility does not work on methods marked @Transactional. It must be public. As per this article: http://www.baeldung.com/transaction-configuration-with-jpa-and-spring, "Another caveat of using proxies is that only public methods should be annotated with Transactional – methods of any other visibilities will simply ignore the annotation silently as these are not proxied." – Software Prophets Jul 26 '18 at 14:55
3

Faced the same problem, I simply forgot to activate the transaction management with the @EnableTransactionManagement annotation.

Ref:

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/EnableTransactionManagement.html

4b0
  • 21,981
  • 30
  • 95
  • 142
3

Using @PersistenceContext with @Modifying as below fixes error while using createNativeQuery

    import org.springframework.data.jpa.repository.Modifying;
    import org.springframework.transaction.annotation.Transactional;

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

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    @Transactional
    @Modifying
    public <S extends T> S save(S entity) {
         Query q = entityManager.createNativeQuery(...);
         q.setParameter...
         q.executeUpdate();
         return entity;
    }
fortm
  • 4,066
  • 5
  • 49
  • 79
3

incase if you have more than one datasource and more than transaction manager, or you have customized your PlatformTransactionManager like I did in this example , then: you have to put your transaction manager name in the

@Transactional("wptransactionManager")

here was my DB1 Datasource1 class ( have 2 transaction managers and 2 datasources etc ..


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "wpentityManagerFactory", basePackages = {
        "xxx.xxx.xxx.wp.repository" })
public class WpDBConfigAhmedYousri {

    @Bean(name = "wpdataSource")
    @ConfigurationProperties(prefix = "spring.user.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "wpentityManagerFactory")
    public LocalContainerEntityManagerFactoryBean wpentityManagerFactory(EntityManagerFactoryBuilder builder,
            @Qualifier("wpdataSource") DataSource dataSource) {
        HashMap<String, Object> properties = new HashMap<>();
        properties.put("hibernate.hbm2ddl.auto", "none");
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
        return builder.dataSource(dataSource).properties(properties)
                .packages("xxx.xxx.xxx.wp.models").persistenceUnit("User").build();
    }

 -----> @Bean(name = "wptransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("wpentityManagerFactory") EntityManagerFactory wpentityManagerFactory) {
        return new JpaTransactionManager(wpentityManagerFactory);
    }
}

My Repository:


@Repository
public interface WpCommenntsRepository extends JpaRepository<WpComments, Long> {



    @Modifying
    @Query(value = "insert into WpComments (comment_author) VALUES (:comment_author)", nativeQuery = true)
 ----->   @Transactional("wptransactionManager")
    public int insertNewComment(@Param("comment_author")String comment_author);

}

user1609897
  • 31
  • 1
  • 2
2

Error message while running the code:

javax.persistence.TransactionRequiredException: Executing an update/delete query

Begin the entityManager transaction -> createNativeQuery -> execute update -> entityManager transaction commit to save it in your database. It is working fine for me with Hibernate and postgresql.

Code

entityManager.getTransaction().begin();
Query query = entityManager.createNativeQuery("UPDATE tunable_property SET tunable_property_value = :tunable_property_value WHERE tunable_property_name = :tunable_property_name");
query.setParameter("tunable_property_name", tunablePropertyEnum.eEnableJobManager.getName());
query.setParameter("tunable_property_value", tunable_property_value);
query.executeUpdate();
entityManager.getTransaction().commit();
Jitesh Prajapati
  • 2,533
  • 4
  • 29
  • 51
Gourab Paul
  • 575
  • 7
  • 14
1

After integrating Spring 4 with Hibernate 5 in my project and experiencing this problem, I found that I could prevent the error from appearing by changing the way of getting the session from sessionFactory.openSession() to sessionFactory.getCurrentSession(). the proper way to work out this bug may be keep using the same session for the binding transaction.opensession will always create a new session which doesnt like the former one holding a transaction configed.using getCurrentSession and adding additional property <property name="current_session_context_class">org.springframework.orm.hibernate5.SpringSessionContext</property> works fine for me.

何德福
  • 81
  • 3
1

The same exception occurred to me in a somewhat different situation. Since I've been searching here for an answer, maybe it'll help somebody.

I my case the exception has been happening because I called the (properly annotated) @Transactional method from a SERVICE CONSTRUCTOR... Since my idea was simply to make this method run at the start, I annotated it as following, and stopped calling in a wrong way. Exception is gone, and code is better :)

@EventListener(ContextRefreshedEvent.class)
@Transactional
public void methodName() {...}

@Transactional import: import org.springframework.transaction.annotation.Transactional;

devaga
  • 326
  • 2
  • 15
1

I had the same error, just annotated with @Transactional and it worked

juan pablo
  • 46
  • 1
0

I faced the same exception "TransactionRequiredException Executing an update/delete query" but for me the reason was that I've created another bean in the spring applicationContext.xml file with the name "transactionManager" refering to "org.springframework.jms.connection.JmsTransactionManager" however there was another bean with the same name "transactionManager" refering to "org.springframework.orm.jpa.JpaTransactionManager". So the JPA bean is overriten by the JMS bean.

After renaming the bean name of the Jms, issue is resolved.

Abdullah
  • 401
  • 2
  • 7
  • 15
0

I was facing the same error inspite of adding @Transactional annotation at class level and importing org.springframework.transaction.annotation.Transactional.

Then I realized that since I was using hibernate query, I had imported javax.persistence.Query instead of import org.hibernate.query.Query. Therefore adding import org.hibernate.query.Query solved the issue for me.

I hope this idea helps someone.

Michu93
  • 5,058
  • 7
  • 47
  • 80
Smitha
  • 21
  • 2
0

I was also getting this issue in springboot project and added @Transactional in my class and it is working.

import org.springframework.transaction.annotation.Transactional;
@Transactional
public class SearchRepo {
---
}
alok
  • 2,718
  • 21
  • 17
0

Following advice from Baeldung JPA Transaction Required Exception

Basically wrap your commit code in

Transaction transaction = session.beginTransaction();
....update or save or delete here
transaction.commit();
0

I faced the same exception and Loop through save entity like:

relationships.stream().parallel().forEach

modify as:

  relationships.forEach

now it was working。

Procrastinator
  • 2,526
  • 30
  • 27
  • 36
jack
  • 1
0

I had same issue this is the solution that worked for me:

  1. add @Transactional at the class level (org.springframework.transaction.annotation.Transactional)
  2. Autowire the entity manager.

then:

Session session = (Session) entityManager.getDelegate();
session=session.getSessionFactory().openSession();
session.getTransaction().begin();
Query q=session.createNativeQuery("update/delete here");
q.executeUpdate();
session.getTransaction().commit();
User01
  • 45
  • 7
0

In my case: I was using @Trasectional on function from package javax.transaction.Transactional.

But I was calling function from another function of the same repository and was not using @Trasectional with caller function which was causing this error.

When I used Trasectional with both the caller and callee function, The error was fixed.

Muzammal Hussain
  • 121
  • 1
  • 11
0

The culprit in my configuration was a DataSourceTransactionManager, when I replaced it with a JpaTransactionManager everything started to work as expected.

changed

@Bean(name = "db1-tm")
JpaTransactionManager db1TransactionManager(
        @Qualifier("db1EM") EntityManagerFactory datasource) {
    return new JpaTransactionManager(datasource);
}

instead of

    @Bean(name = "db1-tm")
    @Primary
    DataSourceTransactionManager db1TransactionManager(
            @Qualifier("db1") DataSource datasource) {
        DataSourceTransactionManager txm =
                new DataSourceTransactionManager(datasource);
        return txm;
    }
0

I see it's too late, however I only see generic answers.
Use

@Transactional

and which one to use it depends to your usage or Framework. if using JPA

jakarta.transaction.Transactional

or

javax.transaction.Transactional

We have updated the package structure, so please take care of it.

Also, if using spring then use.

org.springframework.transaction.annotation.Transactional
Pratik Gaurav
  • 661
  • 7
  • 8
-1

my example of update query thas working after adding @Transactional

    @Modifying
    @Query("UPDATE UserInfo AS u SET u.failedAttempt = :failedAttempt WHERE u.email =:email")
    @Transactional
    @Modifying
    public void updateFailedAttempts(@Param("failedAttempt") int failedAttempts, @Param("email") String email);
Procrastinator
  • 2,526
  • 30
  • 27
  • 36
-2

If the previous answers fail, make sure you use @Service stereotype for the class where you call the update method on your repository. I originally used @Component instead and it was not working, the simple change to @Service made it work.

Georgee
  • 17
  • 2
-4
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;


    @Transactional
    public int changepassword(String password, long mobile) {
        // TODO Auto-generated method stub
        session = factory.getCurrentSession();
        Query query = session.createQuery("update User u set u.password='" + password + "' where u.mobile=" + mobile);
        int result = query.executeUpdate();

        return result;
    }
add this code 200% it will work... might scenario is diff but write like this:)
  • 7
    This is an awful answer, you should be using prepared statemens for this. this code is vulnerable to injection attacks. – Cheloide Dec 13 '18 at 18:33