Atomikos + OpenJpa +DB2 XA standalone - setAutocommit(true) not allowed

797 views Asked by At

I have a spring batch project and am using Atomikos for transaction management.

Here is my datasource configuration and atomikos configuration.

  @Bean
  public DataSource dataSource() {
    Properties properties = new Properties();
    properties.setProperty("serverName", "localhost");
    properties.setProperty("databaseName", "somedb");
    properties.setProperty("portNumber", "9999");
    properties.setProperty("currentSchema", "sch");    
    properties.setProperty("user", "user");
    properties.setProperty("password", "pwd");
    properties.setProperty("driverType", "4");
    properties.setProperty("resultSetHoldability","2");


    AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
    atomikosDataSourceBean.setXaDataSourceClassName("com.ibm.db2.jcc.DB2XADataSource");
    atomikosDataSourceBean.setXaProperties(properties);
    atomikosDataSourceBean.setPoolSize(5);
    return atomikosDataSourceBean;
}


 @Bean(initMethod = "init", destroyMethod = "close")
public UserTransactionManager atomikosTransactionManager(){
    UserTransactionManager atomikosTransactionManager = new UserTransactionManager();
    atomikosTransactionManager.setForceShutdown(false);
    return atomikosTransactionManager;

}

@Bean 
public UserTransactionImp atomikosUserTransaction() throws SystemException{
    UserTransactionImp atomikosUserTransaction = new UserTransactionImp();
    atomikosUserTransaction.setTransactionTimeout(300);
    return atomikosUserTransaction;
}

@Bean
public JtaTransactionManager transactionManager(UserTransactionManager atomikosTransactionManager, UserTransactionImp atomikosUserTransaction) throws SystemException{
    JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
    jtaTransactionManager.setTransactionManager(atomikosTransactionManager);
    jtaTransactionManager.setUserTransaction(atomikosUserTransaction);
    jtaTransactionManager.setAllowCustomIsolationLevels(true);
    return jtaTransactionManager;
}

 @Bean
public LocalContainerEntityManagerFactoryBean  entityManagerFactory(DataSource dataSource) {
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setJtaDataSource(dataSource);
    em.setPackagesToScan("org.company.entity");
    em.setJpaVendorAdapter(new OpenJpaVendorAdapter());
    em.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
    em.setSharedCacheMode(SharedCacheMode.ALL);
    em.setJpaProperties(additionalProperties());

    return em;
}

final Properties additionalProperties() {
    final Properties openJpaProperties = new Properties();
    openJpaProperties.setProperty("javax.persistence.transactionType","jta");       
    openJpaProperties.setProperty("openjpa.TransactionMode", "local");
    openJpaProperties.setProperty("openjpa.ConnectionFactoryMode", "local");
    openJpaProperties.setProperty("openjpa.MetaDataRepository", "Preload=true");
    openJpaProperties.setProperty("openjpa.Compatibility", "QuotedNumbersInQueries=true");
    openJpaProperties .setProperty("openjpa.ConnectionFactoryProperties", "PrettyPrint=true, PrettyPrintLineLength=80, PrintParameters=true");
    return openJpaProperties;
}

When i call spring repository to update the database it throws me an error saying Invalid operation: setAutoCommit(true) is not allowed during Global Transaction. See stacktrace below. Any thoughts on this will be very helpful.

com.ibm.db2.jcc.am.SqlException: [jcc][t4][10126][10304][3.62.56] Invalid     operation: setAutoCommit(true) is not allowed during Global Transaction.     ERRORCODE=-4201, SQLSTATE=2D521
at com.ibm.db2.jcc.am.fd.a(fd.java:679)
at com.ibm.db2.jcc.am.fd.a(fd.java:60)
at com.ibm.db2.jcc.am.fd.a(fd.java:120)
at com.ibm.db2.jcc.am.jb.setAutoCommit(jb.java:960)
at com.ibm.db2.jcc.am.df.setAutoCommit(df.java:158)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at com.atomikos.jdbc.AtomikosConnectionProxy.invoke(AtomikosConnectionProxy.java:161)
at $Proxy38.setAutoCommit(Unknown Source)
at org.apache.openjpa.lib.jdbc.DelegatingConnection.setAutoCommit(DelegatingConnection.java:167)
1

There are 1 answers

0
Tanmoy Mandal On

I was able to fix it. The issue here is we need to tell openJpa to participate in Atomikos transactions. Here is a updated version of the additionalProperties() method:

@Bean
@DependsOn("transactionManager")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter,
                                                                   TransactionManager transactionManager) {
    final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource);
    em.setJtaDataSource(dataSource);
    em.setPackagesToScan("org.company.entity");
    em.setJpaVendorAdapter(jpaVendorAdapter);
    em.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
    em.setSharedCacheMode(SharedCacheMode.ALL);
    em.setJpaProperties(additionalProperties(dataSource, transactionManager));

    return em;
}


final Properties additionalProperties(DataSource dataSource, TransactionManager transactionManager) {
    final Properties openJpaProperties = new Properties();
    openJpaProperties.put("javax.persistence.transactionType", "JTA");
    openJpaProperties.put("openjpa.TransactionMode", "managed");
    openJpaProperties.put("openjpa.ConnectionFactoryMode", "managed");
    openJpaProperties.put("openjpa.ConnectionFactory", dataSource);
    openJpaProperties.put("openjpa.ManagedRuntime", "invocation(TransactionManagerMethod=com.atomikos.icatch.jta.TransactionManagerImp.getTransactionManager)");
    openJpaProperties.put("openjpa.MetaDataRepository", "Preload=true");
    openJpaProperties.put("openjpa.Compatibility", "QuotedNumbersInQueries=true");
    openJpaProperties.put("openjpa.ConnectionFactoryProperties", "PrettyPrint=true, PrettyPrintLineLength=80, PrintParameters=true");
    return openJpaProperties;
}