Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

JOOQ Spring Transaction support.

View SpringExceptionTranslationExecuteListener.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
package com.snaphop.jooq;
 
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
 
import javax.sql.DataSource;
 
import org.jooq.ExecuteContext;
import org.jooq.impl.DefaultExecuteListener;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
 
 
public class SpringExceptionTranslationExecuteListener extends DefaultExecuteListener {
 
@Override
public void start(ExecuteContext ctx) {
DataSource dataSource = ctx.getDataSource();
Connection c = DataSourceUtils.getConnection(dataSource);
ctx.setConnection(c);
}
 
@Override
public void exception(ExecuteContext ctx) {
SQLException ex = ctx.sqlException();
Statement stmt = ctx.statement();
Connection con = ctx.getConnection();
DataSource dataSource = ctx.getDataSource();
// This note and code below comes from
// org.springframework.jdbc.core.JdbcTemplate.execute(StatementCallback<T>)
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, dataSource);
con = null;
ctx.exception(getExceptionTranslator(dataSource).translate("jOOQ", ctx.sql(), ex));
}
/**
* Return the exception translator for this instance.
* <p>Creates a default {@link SQLErrorCodeSQLExceptionTranslator}
* for the specified DataSource if none set, or a
* {@link SQLStateSQLExceptionTranslator} in case of no DataSource.
* @see #getDataSource()
*/
public synchronized SQLExceptionTranslator getExceptionTranslator(DataSource dataSource) {
//This method probably does not need to be synchronized but in Spring it was
//because of a mutable field on the JdbcTemplate.
//Also I have no idea how expensive it is to create a translator as one will
//get created on every exception.
final SQLExceptionTranslator exceptionTranslator;
if (dataSource != null) {
exceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource);
}
else {
exceptionTranslator = new SQLStateSQLExceptionTranslator();
}
return exceptionTranslator;
}
 
}

@agentgt: I'm looking at your implementation here in the context of https://github.com/jOOQ/jOOQ/issues/3787.

I'm not so sure if I understand this correctly given that some of the API doesn't even exist (e.g. ctx.getDataSource() or ctx.setConnection()).

On the other hand, I don't think that this implementation of JdbcTemplate is sensible. It smells extremely fishy in my opinion and violates a couple of basic assumptions about JDBC contracts. I suspect that this just displays a flaw in Spring in general.

For instance: What if you want to fetch warnings from the statement? What if you want to execute the statement again?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.