Search code examples
javajakarta-eeejbentitymanagerjta

A JTA EntityManager cannot use getTransaction() in stored procedure call


I want to do an asynchronous transactional action in a ejb method by calling a stored procedure. When I call the methot I give below error:

java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()

Bean

@Stateless
public class FileSearchDAO {
    private static Logger logger = LoggerFactory.getLogger(FileSearchDAO.class);

    @PersistenceContext(unitName = "FileSearchPU")
    private EntityManager entityManager;

    @Asynchronous
    public Future<String> saveFile(String fileNo, List<String> runningFiles) {
        try {
            entityManager.getTransaction().begin();
            entityManager.createNativeQuery(
                    " BEGIN prc_save_file (:fileNo); END;")
                    .setParameter("fileNo", fileNo).executeUpdate();
            entityManager.getTransaction().commit();
            runningFiles.remove(fileNo);
            return new AsyncResult<>(fileNo);
        } catch (Exception ex) {
            ex.printStackTrace();
            return new AsyncResult<>(ex.getMessage());
        }
    }

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="FileSearchPU" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <jta-data-source>jdbc/FileSearchDS</jta-data-source>
        <properties>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.transaction.jta.platform"
                      value="${hibernate.transaction.jta.platform}"/>
        </properties>
    </persistence-unit>
</persistence>

I haven't any Entity class. I just want to call the stored procedure which updates some table.


Solution

  • In a JTA managed datasource container handles transactions in a distributed way so also handling concurrency outside your application for example.

    EntityManagers transaction can not be used because it is local transaction so something that is then not handled outside your application. Read also this post for more information.

    If you need transaction you should use UserTransaction

    @Resource
    UserTransaction utx;
    

    To use it your annotate your bean

    @TransactionManagement(TransactionManagementType.BEAN)
    

    and use transaction like

    utx.begin();
       ...
    utx.commit(); // utx.rollback();