-1

When I call the below method twice it results in "javax.persistence.TransactionRequiredException: Executing an update/delete query" error. I confirm that the first-time error is not there only when the method call is complete i'm calling this method.

the import used is "org.springframework.transaction.annotation.Transactional;" For the first time this method "TransactionSynchronizationManager.isActualTransactionActive()" return true and the second time it returns false.

I have followed all the approaches present in "https://stackoverflow.com/questions/25821579/transactionrequiredexception-executing-an-update-delete-query" but none helped.

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void upgradeToSuperUser(UserBO userToBeMadeSuperUser, UserBO loggedInUser) {
System.out.println("Transactional Message  "+TransactionSynchronizationManager.isActualTransactionActive());
    
        javax.persistence.Query query = entityManager
                .createNativeQuery("Update M_USERS SET ROLE='SUPERUSER' where ID=:newSuperUserId");
        query.setParameter("newSuperUserId", userToBeMadeSuperUser.getId());
        query.executeUpdate();

        javax.persistence.Query query0 = entityManager
                .createNativeQuery("Update M_USERS SET ROLE='TEACHER' where ID=:oldSuperUserId");
        query0.setParameter("oldSuperUserId", loggedInUser.getId());
        query0.executeUpdate();

        javax.persistence.Query query1 = entityManager
                .createNativeQuery("Update M_SCH_USERS SET USER_ID=:oldSuperUserId where USER_ID=:newSuperUserId");
        query1.setParameter("oldSuperUserId", loggedInUser.getId());
        query1.setParameter("newSuperUserId", userToBeMadeSuperUser.getId());
        query1.executeUpdate();

        javax.persistence.Query query2 = entityManager.createNativeQuery(
                "Update M_SCH_USERS SET SUPERUSER_ID=:newSuperUserId where SUPERUSER_ID=:oldSuperUserId");
        query2.setParameter("oldSuperUserId", loggedInUser.getId());
        query2.setParameter("newSuperUserId", userToBeMadeSuperUser.getId());
        query2.executeUpdate();

        javax.persistence.Query query3 = entityManager
                .createNativeQuery("Update M_TEACHERS set ID = :oldSuperUserId where ID=:newSuperUserId");
        query3.setParameter("oldSuperUserId", loggedInUser.getId());
        query3.setParameter("newSuperUserId", userToBeMadeSuperUser.getId());
        query3.executeUpdate();

        javax.persistence.Query query4 = entityManager
                .createNativeQuery("Update M_TEACHERS set IS_MANAGE_USERS = 0 where ID= :oldSuperUserId");
        query4.setParameter("oldSuperUserId", loggedInUser.getId());
        query4.executeUpdate();
    }

edit 1:- From where its called this method is written in action class

public String upgradeToSuperUser() {
        UserBO userToBeMadeSuperUser = userManager.getUserByRefId(userRefID);
        UserBO currentSuperUser = userManager
                .findSuperUserForLoggedInUser(userToBeMadeSuperUser
                        .getSchoolBO().getId());
        if (Role.getValue(currentSuperUser.getRole()).equals(
                Role.getValue(Role.SUPERUSER))
                && Role.getValue(userToBeMadeSuperUser.getRole()).equals(
                        Role.getValue(Role.TEACHER))) {
            userManager.upgradeToSuperUser(userToBeMadeSuperUser,
                    currentSuperUser);

EDIT 2:- I'm upgrading my spring 3 to 5, hibernate 3 to 5 with aspectj version v1.8.10.

<aspectj.version>1.8.10</aspectj.version>
<plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjrt</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <outxml>true</outxml>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <source>1.8</source>
                    <target>1.8</target>
                    <complianceLevel>1.8</complianceLevel>
                </configuration>
            </plugin>

and my applicationContext.xml for transactions looks like

<bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory"
            ref="entityManagerFactory" />
    </bean>
<tx:annotation-driven mode="aspectj"
        transaction-manager="transactionManager" proxy-target-class="true" />

EDIT 3:- entity manager in applicationContext.xml

<bean id="entityManager"
  class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
            <property name="entityManagerFactory"
                ref="entityManagerFactory" />
        </bean>
rob
  • 17
  • 9
  • Can you please tell if you need to call the method twice immediately? Or just that you are calling the method multiple times? – hermit Aug 12 '23 at 00:02
  • @hermit I'm calling the method multiple times – rob Aug 15 '23 at 03:04
  • @hermit can you please have a look – rob Aug 16 '23 at 09:28
  • 3
    @Rod Could you post the code that calls this method? – Joan Aug 17 '23 at 07:55
  • @Joan i have added the code don't think it will be much help as its a simple method call – rob Aug 17 '23 at 08:59
  • 3
    @Rob, your question is not clear if you don't also put the 2nd invocation to `userManager.upgradeToSuperUser(...)` – Adrian Aug 17 '23 at 11:59
  • @Adrian I'm manually calling this method twice; suppose there are multiple users and I'm calling to make the users upgrade to superuser one by one. The same error occurs when I delete multiple users. Also, after restarting the server the error goes away once and then occurs again when called a second time. I think the transaction are not able to create or destroy, i'm upgrading my application from hibernate 3 to 5, spring 3 to 5 and and earlier it was working fine – rob Aug 18 '23 at 03:39
  • I am still not sure if "calling twice" means in one thread sequentially, or in multiple threads in parallel (e.g. originated from multiple calls of a web service endpoint). The meaning of "manually calling this method twice" is very cryptic without the code shown. – Honza Zidek Aug 18 '23 at 07:53
  • 1
    @HonzaZidek, they are sequential threads, for example suppose on the web i clicked a hyperlink that calls the method once, and when the execution is completed and i tried ti click on the hyperlink again then this error occurs. Please let me know if anything else is needed – rob Aug 18 '23 at 09:56
  • If the action is triggered from web by clicking on a hyperlink, then almost for sure it is running in another thread and as such it is not strictly sequential. Have you checked if my answer is applicable to your case? – Honza Zidek Aug 18 '23 at 10:20
  • @HonzaZidek, i checked your answer but its not applicable please check the edit 2 in the original post – rob Aug 18 '23 at 11:22
  • How are you creating the entity manager? @Rob. Is the entity manager application managed or container managed? – hermit Aug 20 '23 at 04:21
  • @hermit, its container-managed, added edit 3 – rob Aug 21 '23 at 03:48
  • Can you try autowiring the entity manager directly if you are creating itfrom from xml configurations. something this: @PersistenceContext private final EntityManager entityManager; – hermit Aug 21 '23 at 05:25
  • yes already autowired with @PersistenceContext private EntityManager entityManager; – rob Aug 21 '23 at 06:37
  • @hermit i just found that in one class i'm using import org.springframework.transaction.annotation.Transactional and in another i'm using javax.transaction.Transactional can a project have both the imports in different classes – rob Aug 21 '23 at 11:46
  • removing the additional javax.transaction.Transactionaj also didn't resolve the issue – rob Aug 21 '23 at 12:18

1 Answers1

1

You didn't show properly how you call the incriminated upgradeToSuperUser() transactional method. However as it is the most typical error, I strongly suspect that you are calling it within the same object as it is defined.

In this case, the @Transactional annotation is not effective. The Spring default is Spring AOP, which causes that the Spring-generated proxy objects call its own methods internally without the proxy code, so the @Transactional decoration is ignored.

You will find more detailed description e.g. here: Spring @Transaction method call by the method within the same class, does not work?

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118