简体   繁体   中英

How to manually commit a managed transaction

I was given an "API" in the form of a JAR to do some external accounting operations from my Java-Seam-Hibernate appplication.

Internally, the API is an plain Hibernate application, using two independent data sources besides the one used from Seam itself.

The issue is that one of the "API" operations raises the following Exception when doing an internal .commit():

java.sql.SQLException: You cannot commit during a managed transaction!
    at org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:543)
    at org.jboss.resource.adapter.jdbc.WrappedConnection.commit(WrappedConnection.java:334)
    at org.hibernate.transaction.JDBCTransaction.commitAndResetAutoCommit(JDBCTransaction.java:139)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:115)
    at com.other.APIAccountingImpl.moneyMovement(APIAccountingImpl.java:261)
    at com.myapp.integration.ExternalApiIntegrator.storeAcountingData(ExternalApiIntegrator.java:125)
    at com.myapp.session.EmployeeAccounting.persistData(EmployeeAccounting.java:123)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at ...

The source code of the moneyMovement method looks like the standard Hibernate Session transaction idiom :

Session sess = factory.openSession();
Transaction tx;
try {
    tx = sess.beginTransaction();
    //do some work
    ...
    tx.commit();
}
catch (Exception e) {
    if (tx!=null) tx.rollback();
    throw e;
}
finally {
    sess.close();
}

I'm using Seam managed transactions with JTA. I'm also forced to use the custom API and I'm not allowed to alter the source code.

What are my alternatives? How can I isolate the Seam managed transactions from the "API" Hibernate Session? It is possible to configure a connection from a specific data source to not be a managed trx?

You are probably using JTA, which is a Java EE standard for transaction management. In this case, you are using a managed transaction. It means that the container (JBoss, it seems) is handling the transaction boundaries, and will use the JTA semantics to rollback the transaction in case you throw some exception. In this scenario, you don't deal with the transaction API directly. You just throw some exception in case something wrong happens, and it'll take care of rolling back the other parts of the transaction.

That said, I'd recommend you to confirm that this JAR you received is the JTA api. If it's not, then you'll certainly need the documentation for it. If it is, you can use the transaction API (and annotations) to use explicit demarcation of transactions. (some documentation is available here: http://download.oracle.com/javaee/5/tutorial/doc/bnciy.html#bnciz )

Overall, I would say that it's usually a good idea to let the container manage your transactions, as a transaction is usually in the context of a business method, which may involve two or more DAO calls, thus, existing beyond the transactions you'd have inside each DAO method.

If you want the 2 transactions to be linked, it might be possible to muck with the hibernate config so that the transaction instance is one which you control. you could therefore give the underlying hibernate code a dummy transaction which does nothing and let seam control the real transaction.

Alternately, if you don't want the 2 transactions linked, you could probably call the API from an ejb method with a transaction attribute "not supported" (not super clear on how Seam works, but assuming it's ejb under the hood). this would separate the API transaction from the current Seam transaction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM