JDBC distributed transaction and explicit rollback/commit - java

I'm working on an existing project that's configured for distributed transaction.
The project is using Hibernate but for some historical reasons, the part on which I'm working on uses JDBC and needs to stay that way.
To get a connection I have to call an API which gives me back the JDBC connection of the hibernate session.
I need to wrap up some updates/inserts in one transaction so here's what I'm doing :
Set autoCommit to false on my connection.
Do my inserts (prepare statements, execute query)
Call commit.
At commit, I get an SQLException because apparently it's not allowed to call commit/rollback explicitely with distributed transactions. I should state that changing the datasource configuration to non XA is not an option.
Any ideas how I might get around this ?
connexionDiff.setAutoCommit(false);
psInsertLiv = connexionDiff.prepareStatement(reqInsertLivraison);
psInsertLivHisto = connexionDiff.prepareStatement(reqInsertLivraisonHisto);
psSequence = connexionDiff.prepareStatement(reqCleLivraison);
ps = connexionDiff.prepareStatement(requeteRelivraison);
rs = ps.executeQuery();
while(rs.next()) {
rsSequence = psSequence.executeQuery();
while ( rsSequence.next() ) {
sequenceLivraison = rsSequence.getInt(1);
}
psInsertLiv.setInt(1, sequenceLivraison);
psInsertLiv.setInt(2, rs.getInt(1));
psInsertLiv.executeUpdate();
psInsertLivHisto.setInt(1, sequenceLivraison);
psInsertLivHisto.setInt(2, rs.getInt(1));
psInsertLivHisto.executeUpdate();
connexionDiff.commit();
}
} catch (SQLException ex) {
try{
connexionDiff.rollback();
}catch {
//......
}
} finally {
//.....
}
Thx

As you are using a XA connection, you surely are managing your transactions using JTA.
If it is a standalone JTA, get the UserTransaction and call begin and commit there. If it is inside an Application Server, use the transactional annotation or whatever the app server gives you to manage transactions. Look at this page to get an idea of how it is done in JavaEE 6.
If you are using Spring, you can also use the transactional annotation to wrap your code inside a transaction. Here is the relevant documentation.
The transaction management should be the same no matter if you are using Hibernate or plain JDBC. So check how it is done when it is using Hibernate in your project, and follow the same steps.

Related

How Propagation.REQUIRES_NEW works on jdbc level?

I've read the documentation and I understand how Propagation.REQUIRES_NEW works but
Create a new transaction, and suspend the current transaction if one exists. Analogous to the EJB transaction attribute of the same name.
NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager, which requires the javax.transaction.TransactionManager to be made available to it (which is server-specific in standard Java EE).
See Also:
org.springframework.transaction.jta.JtaTransactionManager.setTransactionManager
I can't understand how suspension could work.
For a single level transaction I suppose that spring creates the code like this:
Connection connection = DriverManager.getConnection(...);
try {
connection.setAutoCommit(false);
PreparedStatement firstStatement = connection.prepareStatement(...);
firstStatement.executeUpdate();
PreparedStatement secondStatement = connection.prepareStatement(...);
secondStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
connection.rollback();
}
Could you please provide an example for the Propagation.REQUIRES_NEW?
Is it done somehow via jdbc savepoint?
but I can't understand how suspension could work.
It mostly doesn't.
Is it done somehow via jdbc savepoint ?
JDBC doesn't support the notion of suspending transactions (it supports the notion of subtransactions, though - that's what savepoints are about. JDBC does, that is - many DB engines do not).
So how does it work?
By moving beyond the confines of JDBC. The database needs to support it, and the driver also needs to support it, outside of the JDBC API. So, via a non-JDBC-based DB interaction model, or by sending an SQL command.
For example, In WebLogic, there's the WebLogic TransactionManager. That's not open source, so I have no idea how it works, but the fact that it's a separate API (not JDBC) is rather telling.
It's also telling that the javadoc of JtaTransactionManager says that there are only 2 known implementations, and that these implementations steer quite close to the definitions in JTA.
Straight from that javadoc:
WebSphere-specific PlatformTransactionManager implementation that delegates to a UOWManager instance, obtained from WebSphere's JNDI environment.
So, JNDI then. "Voodoo skip JDBC talk directly to the database magic" indeed.

Do I need to close connection manually in spring boot data jpa + hibernate

I've developed an application using spring boot and I also use spring data jpa hibernate I also use hikaricp for connection pooling. I need to to know do I need to manually close the connection after every crud operation ?
there are three layers model , repository, service and controller
#Override
public void delete(int id) {
try {
notificationRepository.deleteById(id);
}
finally {
//This code not working this is for explanation purpose and I need to know if I need to
//manually close connection then how can I do it
notificationRepository.close();
}
}
Well nice to meet a SLIIT undergraduate , Answer to your question is closing the connection will handle automatically .If you close your connection after every operation then your application performance will be decrease heavily.Only thing you want to ensure is usage of #Transactional annoation in your business(Service) layer,apart from that you don't wan't do anything manually.

How can we sure Connection.close() is called

I am working on Spring MVC + Mysql using JDBC (Non Hibernate). In project we have many services which does the CRUD work. for each method we have to do some steps like
open Connection
Rollback on error
Close connection in finally
Many developers are working on the same project and its very hard to check if connection is closed in finally by every one or not.
So is their any way where after completion of method connection get closed. can i write any class which check if execution of current method is done then close the connection.
Update
Or can we develop some class from which each developer have to ask for Connection will do work on the connection object the at the finally every one have to pass that object to destroyer. If destroyer is not called the show compile time error on that method.
Something like:
someMethod()
{
Connection connection=null
try
{
Connection connection =icrudOperation.getConnection();
//do work with connection object like preparedStatement etc.
}
catch (Exception e)
{
//logging
}
finally
{
icrudOperation.destroy(connection); // if this is not written by any one then at compile time error will shown for this method.
}
}
You shouldn't be messing with the connection in the first place. Use a JdbcTemplate to do the querying. If you really want to do stuff with the connection use a ConnectionCallback. Complete this with springs declarative transaction management and you have 1 problem less to solve.
If you really want to work with the Connection and refuse to use use the common approach of the JdbcTemplate you could fix this with Springs declarative transaction management. Wrap the datasource in a TransactionAwareDataSourceProxy. Then configure Spring to manage the transaction, this will ensure that during the transaction a single connection will be used and spring will close the connection at the end of the transaction.
I would however strongly suggest to move to the usage of the JdbcTemplate as that will make your life a whole lot easier and allows you to solve the actual business problems
One other thing your service layer shouldn't be involved in JDBC coding that should be in a data access layer which is used by the service layer.
The following should work:
try{
Connecition.close();
}
finally{
System.err.println();
Connection.close();
}

JtaTransaction localStatus rolled back after creation

I'm creating a hibernate Session and try to start a new [Jta]Transaction. Though, the transaction cannot be started because the JtaTransaction that is used in the background seems to be rolled back.
Here is what I'm doing.
Session session = sessionFactory.openSession();
CustomSessionWrapper dpSession = new CustomSessionWrapper(session, this);
if (!session.isClosed() && !session.getTransaction().isActive()) {
session.beginTransaction();
}
Nevertheless the transaction is still not active after the beginTransaction is called. When I debug the beginTransaction method I come to the doBegin method of the JtaTransaction (I do not override this method, I'm just posting the original code of this method).
#Override
protected void doBegin() {
LOG.debug( "begin" );
userTransaction = locateUserTransaction();
try {
if ( userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION ) {
userTransaction.begin();
isInitiator = true;
LOG.debug( "Began a new JTA transaction" );
}
}
catch ( Exception e ) {
throw new TransactionException( "JTA transaction begin failed", e );
}
}
The userTransaction.getStatus() returns Status.STATUS_ROLLEDBACK and no transaction is started. Does anyone know how I can fix that?
UPDATE 1 (you can skip that since that was a mistake, see UPDATE 2)
I found out that there are two threads, one using the main session and another using smaller sessions for logging. The main session (and transaction) is open for a longer period of time, so basically until the operation is finished. It seems that locateUserTransaction always returns the same userTransaction. This means that the main session opens this userTransaction and one of the side transactions commit/rollback that transaction. Does anyone know what to do so that different transactions are retrieved?
UPDATE 2
I found out that I don't have two threads, it is only one threads that opens two sessions in parallel. Each session should then open their own transaction, though both get the same UserTransaction. How can I tell hibernate that each session should get its own [User]Transaction?
Hibernate abstracts both local as JTA transactions behind its own abstraction layer, so I don't see why you'd have to write such low level transaction handling code.
In Java EE you have the app server to manage transactions, in stand alone apps Bitronix + Spring do a job too.
Although you can manage to write your own transaction management logic, I always advice people to reuse what they have already available. Xa/JTA and Hibernate require extensive knowledge to work seamlessly.
Update 1
Two different threads shouldn't use the same user transaction, you should use different transactions for each thread.

How do I use Jackrabbit when it is part of a global transaction?

I am using Jackrabbit with datastore and a separate database for the rest of my data. I have deployed Jackrabbit JCA to JBoss 7.1.1. I have debugged the application and I see that the session instance is of type XASessionImpl.
I am currently getting a session like this:
final Credentials credentials = new SimpleCredentials("admin", "admin".toCharArray());
try {
final Session session = repository.login(credentials);
return session;
} catch (RepositoryException e) {
throw new RuntimeException(e);
}
I invoke session.save(); and then session.logout() when I am done each time I access it. Is this correct when it is part of a global transaction. I do not have much knowledge about distributed transactions etc so please correct me if I am wrong. I tried to throw a runtime exception inside one of my methods that is annotated with #Transactional (using Spring 3.2), but the data in the datastore is not removed. Is this correct? Doesn't data that is being added in the data store removed if the transaction is rolled back? My "testing" enviroment for this was: add content to Jackrabbit, then to database and then throw runtime exception. Or isn't Jackrabbit configured correctly?
Jackrabbit is probably running its own transaction, assuming the Spring-managed transaction is rolled back but the content in the datastore remains. How does your Spring/JBoss resource configuration look like?
Some quick Googling (with keywords JTA Jackrabbit Spring JBoss) reveals that setting up XA transactions with Jackrabbit and an XA JDBC DataSource might be easier said than done. Old mailing list entries report being able to use a JTA transaction manager called Jencks to do this, but Jencks' development appears since to have been discontinued.
Also have a look (though with a grain of salt) at section 1.2.3 in this JBoss community wiki page that states that "jackrabbit implements the XA protocol internally and requires a non-XA datasource underneath", which implies the behavior you're seeing.
Also, as an option to XA, have you considered emulating XA like this (mind the pseudo-code)?:
#Transactional
public void addContent() {
try {
storeContentInJcrRepo();
saveMetadataInDatabase();
catch (DataAccessException e) {
deleteNewlyStoredContentFromJcrRepo();
// Rethrow to ensure DB transaction is rolled back
throw e;
}
}

Categories