Mixing JdbcTemplate and raw JDBC - spring

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.

Related

Query not timing out when using Spring Core JdbcTemplate

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());

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.

Java Oracle JDBC Connection Timeout

I have developed some JSON web services using Servlets for my mobile app. I'm using (Oracle + Private Tomcat) hosting. I have one single class DBOperations.java which has a lot of static functions which are called in Servets for database operation. I use getConnection() method in each function to get Connection Object, create statement and execute queries. Issue is after some time connection get lost. I'm using the following code to re-establish the connection.
public static Connection conn;
Statement stmt;
public static Connection getConnection() throws SQLException {
if (conn == null || conn.isClosed() ) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(DB_URL, "username", "password");
return conn;
} catch (ClassNotFoundException | SQLException ex) {
}
} else {
return conn;
}
return conn;
}
I'm unable to figure out how I can handle the timeout/closed connection issue as the above code isn't re-establishing the connection. I need to restart Tomcat to get it back in working state. Any suggestions or help is highly appreciated.
You must use connection pooling, And let Tomcat server to handle everything. Create a JNDI datasource to achieve the same and you will never face such issue.
Used OraceDataSource for connection pooling and it's working perfectly.
public static OracleDataSource ods;
public static Connection getConnection() throws SQLException {
if (ods == null) {
ods = new OracleDataSource();
ods.setURL(DB_URL);
ods.setUser("username");
ods.setPassword("password");
}
return ods.getConnection();
}

Resources