Query not timing out when using Spring Core JdbcTemplate - spring-boot

I am working on a spring boot app, one of the methods that queries a ibm db2 db won't timeout per the set values. The datasource is managed by tomcat. is this the correct way of handling the query timeouts? I am expecting a sql timeout exception, when the query timeouts, but it's not happening for me.
Database Driver: com.ibm.as400.access.AS400JDBCDriver
try {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
int timeout = dataSourceConfig.getTimeout();
jdbcTemplate.setQueryTimeout(timeout);
Result = jdbcTemplate.queryForObject(SQL, new Object[]{Params....}, String.class);
} catch(DataAccessException ex){
log.error("Error Occurred :" + ex.getMessage());
} catch (Exception ex) {
log.error("Error Occurred :" + ex.getMessage());

Related

Keycloak how to access DB from protocol mapper

I use a protocol mapper to enrich the token with data from a custom database. How should I deploy the driver to use in the protocol mapper? If II copy the driver in /standalone/lib/ext keycloak folder the when the mapper is executing I get the error
SQL exception occuredjava.sql.SQLException: No suitable driver found for jdbc:oracle:thin:#.......:1521/CASDB
where should the driver be placed? Is it really necessary to deploy the driver as keycloak module?
my protocol mapper code
#Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
String field = mappingModel.getConfig().get(FIELD_NAME);
String type = mappingModel.getConfig().get(TYPE);
String value = "Test " + type;
System.out.println(">>>>>>>>>>>> " + type);
try {
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:#....:1521/CASDB",
"....",
"....");
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM CUSTOMER where CUSTOMER_ID = .....");
rs.close();
stmt.close();
con.close();
} catch (SQLException e) {
System.out.println("SQL exception occured" + e);
} finally {
}
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, value);
}
the error is
12:54:40,579 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-6) Uncaught server error: java.lang.NoClassDefFoundError: oracle/jdbc/driver/OracleDriver
at com.betex.keycloak.mapper.UserAttributeMapper.setClaim(UserAttributeMapper.java:72)
at org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper.transformUserInfoToken(AbstractOIDCProtocolMapper.java:71)
at org.keycloak.protocol.oidc.TokenManager.lambda$transformUserInfoAccessToken$8(TokenManager.java:716)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:390)
at java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.util.stream.Sink$C
But if test the connection via wildfly datasource it works ok
I found the solution creating a XADatasource on wildfly server and obtaining it via JNDI inside the code of protocol mapper. Where the DatasourceName is the name defined in your wildfly datasource config
Sample code :
InitialContext initialContext = new InitialContext();
Context context = (Context) initialContext.lookup("java:jboss");
DataSource DATASOURCE = (DataSource) context.lookup("/datasources/DatasourceName");

Spring data jpa and JdbcTemplate - Should I close connection?

Should I close connection or Spring will handle it?
#Autowired
MyRepository myRepository;
#Autowired
#Qualifier("myJdbc")
JdbcTemplate myJdbc;
#GetMapping("/v1/controlla-abilitazione")
public Set<String> controlloAbilitazione() {
try {
Connection conn = myJdbc.getDataSource().getConnection();
//Here I use previous connection to call an oracle PL/SQL via basic oracle jdbc
//Should I close connection?
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
(I know that I can use Spring to handle PL/SQL, but Spring doesn't have native support for Oracle Type as return from PL/SQL)
Not tried but if you execute the SQL or PL/SQL query from the Connection object, you don't use Spring JDBC features for executing your query, so you should not expect that Spring closes the connection for you. It is not aware of the datasource provider activity about that.
So Connection.close() should be probably required.
It is an theory but you could check it easily enough. Store the Connection in a field of the bean and do a check at the beginning of the method.
Connection conn;
#GetMapping("/v1/controlla-abilitazione")
public Set<String> controlloAbilitazione() {
if (conn != null && !conn.isClosed){
throw new RuntimeException("Oh it was not closed");
}
try {
conn = myJdbc.getDataSource().getConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Now invoke your controller once and another time. If you get the exception, you know why.

Can I use spring boot datasource to get connection object so as to use it with conn.executeQuery() manually?

I am working on spring boot application with Mysql backend and trying to use springboots datasource Bean to get connection object so as to use it with the following stmts:
stmt =conn.createStatement()
stmt.executeQuery("show tables");
which is expected to return the table list. Below is the code of connection class:
public class Test {
#Autowired
DataSource datasource;
public void test1(){
System.out.println("Inside Test Method");
try {
Connection conn = datasource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("show tables");
while (rs.next()) {
System.out.println(rs.getString("TableNames"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch(NullPointerException e){
System.out.println("Null Pointer exception");
}
}
}
But the datasource object is throwing null value and hence it doesnt return any connection object.
Following is the application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
driver-class-name: com.mysql.jdbc.Driver
username: ****
password: ****
initial-size: 1
max-idle: 2
max-active: 3
Ideally the datasource object should read these properties and be able to return connection object. Not sure if my understanding is correct.
Can anyone help me out in figuring the issue pls ?
I think spring boot automated this process completely. One doesn't have to inject the data source manually & connection pool mechanism is also automated. Just adding the connection properties and pool properties in yaml file or properties file under src/main/resources. It will inject the data source for you.

Spring Transactions not working - JDBCTemplate is reading uncommitted data

The following Method inserts two records (but doesn't commits them at this point) and it then tries to read one of the uncommitted records from the previous statements. I wrapped the code with Transaction, and set the isolationLevel to "READ_COMMITTED" but this doesn't seems to be working. The read/"SELECT" statement is reading the uncommitted records.
How is this possible? Where am I going wrong? Please see the code below and help me out. I would be really thankful ~
Note :
I am using BoneCP to get the DataSource.
dbConnectionPool.initConnectionPool(dbName) , will fetch a BoneCPDataSource.
#Override public void testDBCalls() {
dBConnectionPool.initConnectionPool("titans");
DataSource dataSource = dBConnectionPool.getDataSource("titans");
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
definition.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DataSourceTransactionManager txManager = new DataSourceTransactionManager(dataSource); TransactionStatus
transactionStatus = txManager.getTransaction(definition);
try {
try {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sql = "INSERT INTO groundwater(external_id,source_type) VALUES (12, 13);";
jdbcTemplate.update(sql);
System.out.println("Successfully inserted - 1");
String sql2 = "INSERT INTO groundwater(external_id, source_type,) VALUES(123,45);";
jdbcTemplate.update(sql2);
System.out.println("Successfully inserted - 2");
String sql3 = "select gw_id from groundwater where external_id= 123;";
System.out.println("Result : "+jdbcTemplate.queryForInt(sql3));
txManager.commit(transactionStatus);
System.out.println("Commiting the trasaction...");
} catch (Exception e) {
e.printStackTrace();
txManager.rollback(transactionStatus);
System.out.println("Rolling back the transaction");
}
} finally {
try {
dataSource.getConnection().close();
System.out.println("Closing the connection ...");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
As #M.Denium explained in the comment, I was trying to do everything from a single transaction. Isolation Levels are meant for maintaining consistency across different transactions. I was still learning the concepts, so I took it in a wrong way.

Mixing JdbcTemplate and raw JDBC

I am experiencing some strange behaviour which I can't easily explain. The following code runs fine:
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.executeUpdate("DELETE FROM product");
} catch (Exception ex) {
throw new RuntimeException(ex);
}
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.executeUpdate("INSERT INTO product ...");
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
However this code causes a deadlock:
jdbcTemplate.update("DELETE FROM product");
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.executeUpdate("INSERT INTO product ...");
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
The exception is
java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction
Both jdbcTemplate and dataSource are created by Spring boot and autowired
#Autowired
private DataSource dataSource;
#Autowired
private JdbcTemplate jdbcTemplate;
The statements form part of a method in a service (with the #Transactional annotation)
Can anyone explain why this happens?
If you want to use your own JDBC code that plays nice with the connections managed by Spring's transaction management you should use DataSourceUtils to obtain the connection -- see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/DataSourceUtils.html#getConnection-javax.sql.DataSource-
In your example, depending on the transaction configuration, the first statement using the JdbcTemplate might not be committed yet, so it would block the next JDBC statement from a different connection. Using the DataSourceUtils, both statements would be using the same connection.

Resources