Search code examples
javaweblogicpersistencecommitopenjpa

org.apache.openjpa.persistence.PersistenceException: Cannot set auto-commit mode when using distributed transactions


I setup simple java ee project and using jta transaction and using OpenJpa 2.4.2 as Jpa provider, maven 3.3, eclipse 2020-06, jdk 8U2002, weblogic 12.4.2 and java ee 6 and get this exception:

javax.ejb.EJBException: EJB Exception: : <openjpa-2.4.2-r422266:1777108 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: Cannot set auto-commit mode when using distributed transactions
    at org.apache.openjpa.jdbc.meta.MappingTool.record(MappingTool.java:571)
    at org.apache.openjpa.jdbc.meta.MappingTool.record(MappingTool.java:467)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:160)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)
    at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:122)

and this is my persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
            http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
            version="2.0">
            
            <persistence-unit name="batch" transaction-type="JTA" > 
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl </provider>
    <jta-data-source>jdbc/new</jta-data-source>
    <class>com.smartsoft.persistence.Person</class>
    <validation-mode>NONE</validation-mode>
      <properties>
<property name="openjpa.DynamicEnhancementAgent"  value="false"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="unsupported"/>
    <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
      <property name="openjpa.Log" value="DefaultLevel=TRACE"/>
    </properties>
  </persistence-unit>
</persistence>

I have a simple Entity class that has firstName and lastName and age fields and setter getter methods. and an Stateless Ejb class that injects EntityManager with @PersistenceContext annotation and has save method that calls em.persist(Person) Then I inject this dao in a servlet and pass a person class to it.

This is my Weblogic.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
                      <wls:context-root>persistence</wls:context-root>
                      <wls:container-descriptor>
<wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>                      
                      </wls:container-descriptor>
</wls:weblogic-web-app>

This is my dao class:

@Stateless
public class PersonEjb {

    @PersistenceContext
    private EntityManager entityManager;
    private static final Logger logger =Logger.getLogger("PersonEjb");
    public void save(Person person) {
        entityManager.persist(person);
        logger.info("persisted");
    }
}

and This is servlet:

@WebServlet("/Serv1")
public class Serv1 extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @EJB
    private PersonEjb pe;
    public Serv1() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Person p = new Person();
        p.setAge(25);
        p.setFirstName("hamidreza");
        p.setLastName("abroshan");
        pe.save(p);
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }
}

You can download this project at github.


Solution

  • as OpenJpa documentation Section 2, “ Integrating with the Transaction Manager ” says, I should add <property name="openjpa.TransactionMode" value="managed"/> to persistence.xml.
    By this property, OpenJpa understands that should uses container's managed transaction.
    In case of weblogic, I do not need to configure "openjpa.ManagedRuntime " property.
    and according to Section 2.1, “ Managed and XA DataSources ”. "When using a managed DataSource, you should also configure a second unmanaged DataSource that OpenJPA can use to perform tasks that are independent of the global transaction. The most common of these tasks is updating the sequence table OpenJPA uses to generate unique primary key values for your datastore identity objects. "
    Note: If you do not set AutoStrategy id generation, and you created your database's schema and sequence before, and remove

    <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> 
    

    from your persistence.xml, You do not need to second none jta dataSource.

    So, this is my persistence.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
                version="2.0">
                
                <persistence-unit name="batch" transaction-type="JTA" > 
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl </provider>
        <jta-data-source>jdbc/new</jta-data-source>
        <class>com.smartsoft.persistence.Person</class>
        <validation-mode>NONE</validation-mode>
          <properties>
        <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
          <property name="openjpa.Log" value="DefaultLevel=TRACE"/>
          <property name="openjpa.TransactionMode" value="managed"/>
          <property name="openjpa.ConnectionFactoryMode " value="managed"/>
         <property name="openjpa.Connection2UserName" value="app"/>
        <property name="openjpa.Connection2Password" value="app"/>
        <property name="openjpa.Connection2URL" value="jdbc:derby://localhost:1527/testdb;create=false"/>
        <property name="openjpa.Connection2DriverName" value="org.apache.derby.jdbc.ClientDriver"/>
        </properties>
      </persistence-unit>
    </persistence>