I have a requirement in my Java application to execute a set of DB statements in an atomic & isolated fashion. For example, the application needs to read data rows from one table and update a data row in another table.
QueryRunner queryRunner = new QueryRunner(); // DBUtils query runner
Object[] params = new Object[] { param };
Connection conn = null;
try {
conn = ...; // get connection
conn.setAutoCommit(false);
result = queryRunner.query(conn, "select x, y, z from table1 where column1 = ?", new BeanHandler<SomeBean>(SomeBean.class), params);
// logic to get value for update
queryRunner.update(conn, "update table2 set p = ? where q = ?", some_value, some_id);
conn.commit();
} catch (SQLException e) {
//
} finally {
DBUtils.closeQuietly(conn);
}
The transaction management is achieved by setting auto commit to false for the connection and explicitly commit later on, as shown above. But the above code can also be executed in a multi-thread environment and I also want the two DB statements (select & update) to be run as a whole mutual exclusively.
I have some idea to use a shared Java Lock object in that method, depicted below.
In the class,
private Lock lock = new ReentrantLock(); // member variable
In the method,
lock.lock();
try {
conn = ...; // get connection
conn.setAutoCommit(false);
result = queryRunner.query(conn, "select x, y, z from table1 where column1 = ?", new BeanHandler<SomeBean>(SomeBean.class), params);
// logic to get value for update
queryRunner.update(conn, "update table2 set p = ? where q = ?", some_value, some_id);
conn.commit();
} finally {
DBUtils.closeQuietly(conn);
lock.unlock();
}
It seems sort of capable of solving the issue. However, I am wondering if this is the best practice and is there any better alternative (such as frameworks) for this?