What is the right way to use JDBC transactions in Java? - java

I'm using this template:
try {
connection.setAutoCommit(false);
try {
// ... do something with that connection ...
connection.commit();
catch (SQLException exception) {
connection.rollback();
throw exception;
} finally {
connection.setAutoCommit(true);
}
} catch (SQLException exception) {
// log error
}
Is this the right way? How can this template be improved?

Your code should work fine. Do you get any errors or anything else?
Here's an example on using JDBC Transaction anyway
http://www.java2s.com/Code/Java/Database-SQL-JDBC/JDBCTransaction.htm
P.S. Specify your problem and I'll try to help.

Related

MySQL lock wait timeout with a form submit

Here is my doPost method of my servlet that in theory add data in db
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
Date d=(Date) request.getAttribute("data");
DatiAnagrificiImpl dai=new DatiAnagrificiImpl();
dai.addDatiAnagrafici(new DatiAnagraficiBean(request.getParameter("username"),request.getParameter("cap"),request.getParameter("nome")
,request.getParameter("cognome"),request.getParameter("telefono"),d));
}
And here the method that will insert data in db
enter public void addDatiAnagrafici(DatiAnagraficiBean dab) {
// TODO Auto-generated method stub
try {
Statement s=c.createStatement();
s.executeUpdate("insert into Dati_anagrafici values('"+dab.getIdUtente()+"','"+dab.getIdCittà()+"',"
+ "'"+dab.getNome()+"','"+dab.getCognome()+"','"+dab.getTelefono()+"','"+dab.getDataNascita()+"')");
}catch(SQLException e) {
}finally {
al.add(dab);
}
}
But when I try to do that with a servlet I have this error
ERROR 1205 (HY000): Lock wait timeout exceeded;
Someone knows how to resolve? If I do the same thing with a normal java class is all fine.
It appears you have a transaction that's not completing. In MySQL, try running these to get a view into what's going on:
SHOW ENGINE INNODB STATUS;
SHOW FULL PROCESSLIST;
One or both should provide some clues.
A few issues stand out in your code. The first thing I would address is that the Statement is never closed (but should be). You can close the statement in a few places, but as the simplest example, you could close it right after you call executeUpdate(), like this:
Statement s = c.createStatement();
s.executeUpdate("...");
s.close();
Another easy change: when catching an exception, do something with it (instead of "swallowing" the exception silently). It's possible there's an exception being thrown, but the code above will hide that exception. For example, instead of this:
catch (SQLException e) {
}
try this:
catch (SQLException e) {
e.printStackTrace();
}
A final improvement would be to rework the code a bit to use "try-with-resources" - a nice convenience to automatically close a resource for you (in this case, your Statement). That could look like this:
Connection connection = getConnection();
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("...");
} catch (SQLException e) {
e.printStackTrace();
}
EDIT: One more thing.. the connection can (and should) be committed by calling commit() (or rollback() if something went wrong). Here's a final edit to try which shows commit() in the main try block, and a rollback() in the catch block to undo the transaction if an exception is thrown:
Connection connection = getConnection();
try (Statement statement = connection.createStatement()) {
statement.executeUpdate("...");
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}

nested try block without a catch or finally block

Is it fine to have a nested try block without a catch or finally block and let the outer catch block handle the exception if any from the nested try block?
Something like:
try (Connection con = ds.getConnection();
PreparedStatement ps = con.prepareStatement(sql);) {
//nested try block without a catch or finally block
try (ResultSet rs = ps.executeQuery();) {
while (rs.next()) {
list.add(rs.getInt("id"));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
If you remove the 'try' the result set will not close automatically.
The try-with-resources statement sort of executes rs.close in a hidden finally.
It is good practice to close the resultset, open resultset can lead to problems : java.sql.SQLException: - ORA-01000: maximum open cursors exceeded
Problem with exception catching in this example is how do you differentiate between datasource exceptions, query creation exceptions or query execution SQLExceptions? I would probably throw a specific RuntimeException when my datasource can not deliver an connection.
No. Your code won't compile.
Every try block (even nested) must be followed with catch(..) and/or finally.
In your case add a second catch block if you want to handle any other additional exceptions.
Sample code:
try {
// code which may throw exceptions
} catch(Exception e1) {
// e1 specific code
} catch (Exception e2) {
// e2 specific code
} finally {
// Optional. Executes whether exception thrown or not!
}

Can return connection object inside a try with resources

I have connection provider class as bleow to return connection.
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws ClassNotFoundException, SQLException {
try (Connection connection = DriverManager
.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
) {
return connection;
}
}
}
Here is main method to call connection provider.
public void Test() {
try {
Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
But "com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed." error are always show at below line of code.
PreparedStatement ps = con.prepareStatement("");
Because, according to Oracle documentation, If use try with resources java 7 features, resources are auto close after try block even it's errors occurred or not. So even I returned the connection it's already closed.
Let me know, my usage logic is wrong?
How can I return this connection inside try with resource?
I tried many time googling for solution but does not get convenience answers for me.
Let me know your suggestion and feedback please.
What you can't do...
With a try-with-resources as you have it after you return the connection you return(d) is close(d). You can't return the connection from inside the try with resources.
What you can do...
Pass the connection (inside your try-with-resources) to a method that takes a connection. You can also use a ConnectionPool, and get the Connection when you need it (to create and execute a query).
Let me know, my usage logic is wrong?
The usage of 'try-with-resources' logic is wrong in this context, because the intention of ConnectDB() is to return a connection instance which could be actually used by the caller to send a SQL statement, but instead, the connection instance is getting auto-closed, before it could be used by the caller, because of using 'try-with-resources' construct of Java.
Quick how-to on try-with-resource and JDBC
Your ConnectionProvider's ConnectDB already declares it is throwing SQLException - so no need to catch it in here: (You should consider replacing this code with connection pool maybe)
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
}
}
Instead use try-with-resource in your test-class to clean up your code and focus on errors your SQL code
might have:
public void Test() {
try (Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("SELECT 1")) {
//Prepare your Statement
ps.setInt(1, 1);
//And another try-with-resource for the result - note the closing brace
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
//Handle your Result
System.out.println(rs.getString(1));
}
} // This closes try-with-resource. Exception will be rethron to be caught in outer catch!
} catch (SQLException e) {
//SQL is Broken - but only ONE catch to catch them all
e.printStackTrace();
}
}
That way you gain
Better readability for your code (no calls to close surrounded by finally and if != null)
Centralized error handling if anything in your SQL code breaks (so you can focus on functional error of "statement didn't run")
Better code quality: No need to worry about Cursors, Statements, Connections not being propery closed.

Closing connection but still getting Exception: null.Message:FATAL: too many connections for role "me"

There are many similar questions but I am closing the connection in the finally block. I am testing so I am refreshing the same page often.
in the DAO ( which is called from the controller when the view is accessed)
try {
con= DB.getConnection();
st= connection.createStatement();
rs = statement.executeQuery(MY_QUERY);
while (rs.next()) {
...
}
} catch (SQLException e ) {
e.printStackTrace();
} finally {
try { rs.close(); } catch (Exception e) { /* ignored */ }
try { st.close(); } catch (Exception e) { /* ignored */ }
try { conn.close(); } catch (Exception e) { /* ignored */ }
}
in application.conf
db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://hostname2/schema"
db.default.user="myuser"
db.default.password="mypass"
Inevitably after a few hours coding I hit the no more connections error. shouldn't the finally close the connection and return it to myuser's pool? Does hitting CTRL-D not close the connection?
Using: PostgreSQL, Java with Play2 framework, running with play run (testing/building stage)
UPDATE: still looking for a reason
Here's some working database code from a project I'm working on:
try
{
//Run a query.
statement = connection.createStatement();
statement.execute(db_request);
results = statement.getResultSet();
//Put the list of names into the table.
table = getTableResults(results);
if(table == null)
return null;
System.out.println("Running database command: " + db_request);
//End.
results.close();
statement.close();
connection.close();
}
catch (SQLException ex)
{
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
return null;
}
return table;
I run all the close statements at the end of the try block and only catch SQLException. If anything else is going on, the console prints the stack trace and shows me the exact line where it broke.
By the way, catch(Exception e) is a REALLY bad coding practice that causes Java to hide errors from you unless they're fatal. I imagine you'd get a lot more information from the stack trace that's automatically printed to the console if you removed those lines.
Seeing how Play Framework gives you play.Logger class, you could instrument that finally and the try {} catch {} inside it with
Logger.info("Something happened...");
and start getting the idea of whats happening for yourself. From top of my head - nothing looks wrong with your code. Do you know the max number of concurrent connections that your db supports btw? If its running in the cloud, there may be an artificial limitation as well.

Efficient JDBC connection management in a stateless session bean

I have a stateless session bean a method of which is used repetitively for running an SQL query within a plain JDBC connection. To avoid having to open and close connections too frequently, I came up with the following approach and wondering if it is a good practice:
I open the connection once in a method annotated #PostConstruct and close the connection in another method annotated #PreDestroy
The code works fine with no apparent memory leaks or any issues that I know of - just wondering if more experienced developers would agree if it is a good practice.
#PostConstruct
public void initBean() {
try {
conn = Connector.getConnection();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
}
}
public String runTheQuery(String sql) {
String result ="";
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
result = rs.getString(1);
rs.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
}
return result;
}
#PreDestroy
public void endingTitles() {
System.out.println("Closing the JDBC connection...");
try {
rs.close();
conn.close();
pstmt.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (pstmt != null)
pstmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}// end finally try
}// end try
}
The best solution is to use DataSource
#Resource(mappedName="java:/DefaultDS")
DataSource dataSource;
public String runTheQuery(String sql) throws SQLException
Connection con = dataSource.getConnection();
try {
...
} finally {
con.close();
}
}
Data sources normally always have a minimum number of open connections, so in most cases there will be no real overhead getting a connection from a data source.
So it's only a valid practice, if you have measured before, and it it really solves an existing performance problem.
Otherwise it's not common, and therefore it's something like premature performance optimization.
Data sources offer additonal functionality: For example to check a connection, if it's still valid, before it gets injected. If you did it yourself, you would have to reimplement it. And there are possibly errors in that code.

Categories