Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
Document using jOOQ with Spring for transaction support #1836
As suggested by Adam Gent:
... and reblogged on the jOOQ blog:
... another suggestion by Sergey Epik:
I don't think that most of the glue code in the original gist is required:
See https://gist.github.com/3903290 for minimal code sample.
After digging into the Spring JDBC exception code a little further, it appears that SQLErrorCodesFactory will ask the DataSource for a Connection in order to initialize its error codes. In theory, this could cause the connection pool to block if the pool is at its limit. Releasing the connection which caused the exception could prevent this problem.
Releasing the connection manually ends up closing the connection due to Connection.equals not being implemented by the DataSource provider (in this case c3p0). Will debug DataSourceUtils.connectionEquals a bit more.
Follow-up: what c3p0 wants passed to DataSourceUtils.releaseConnection() is the underlying delegate (e.g. ctx.getConnection().getDelegate()). However because the implementation class is package-private, the only way to do that from outside jOOQ is through reflection.
But once the delegate is passed through, then the underlying connection is not closed.
I have worked around one issue by using
Guessing I will need to create a
Latest attempt at https://gist.github.com/azell/5655888.
I have added some examples to the manual's "Using jOOQ with Spring and DBCP" tutorial section. It includes a Spring configuration similar to Sergey's:
This configuration operates on
Any further feedback is very welcome, of course!
How does the current example handle tearing when outside of a transactional context? By using a connection pool and making complex operations, jooq returning and checking out the connection will result in race condition bugs.
Because I couldn't ensure that all developers used transactions and didn't want to use one per request, I had to write an ExecutionListener that is transaction aware. This built on a similar configuration as the accepted answer, after I verified the problem in a test. Alternatively a listener could have failed fast by asserting a transactional context. Either way, a naive developer won't accidentally check in code that breaks under a real workload.
Couple of notes:
This proxy allows data access code to work with the plain JDBC API and still participate in Spring-managed transactions, similar to JDBC code in a J2EE/JTA environment. However, if possible, use Spring's DataSourceUtils, JdbcTemplate or JDBC operation objects to get transaction participation even without a proxy for the target DataSource, avoiding the need to define such a proxy in the first place.
That may be due to the heavy use of reflection in the implementation, which may or may not cause a performance degradation.
Also, it is not clear to me that using
Exception handling: While SQL uses the checked java.sql.SQLException, jOOQ wraps all exceptions in an unchecked org.jooq.exception.DataAccessException
If this is true, then integration will still require a exception mapping from jOOQ DataAccessException to SQLException to Spring DataAccessException.
@ben-manes: That would be a useful addition to Sergey's solution.
@azell: That slipped by me. Funny, why would such a general disclaimer be there? I understand the reflection argument, but still, given that this proxy was introduced mainly to to be "Similar to a transactional JNDI DataSource as provided by a J2EE server.". Being used to J2EE, I find the idea compelling of being able to access a contextual data source that "knows" I'm in a transaction by accessing some context.
@azell: I don't know Spring well enough, but I would imagine that you could still correctly handle failures (and thus, rollbacks) in your transaction management code, even if you're confronted with a jOOQ DataAccessException?
Anyway, you guys have more experience with Spring. I think I will create another example in the manual, more along the lines of what you have been doing.