In a multi-threaded environment, each thread is executing this call() >>
PreparedStatement st1 = null
PreparedStatement st2 = null;
.....
.....
st1.executeBatch();
st2.executeBatch();
connection.commit();
Is it guaranteed that for each thread, the sql batches inside st1 will execute BEFORE the sql batches in st2? In other words, is the synchronous behavior guaranteed in this case?
Thanks
According to the documentation, the connection object can have auto-commit mode either enabled (default mode) or disabled. When auto-commit is false:
If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode.
Therefore if auto-commit is false, the first batch will be committed before the second. If auto-commit is true, the first and second batches will be committed as one transaction. Note that Connection.close() should only be used when auto-commit is false.
In both cases, the execution order (regardless of the commit mode) follows the order in the code.
Related
I am working on Legacy project now and it requires some deep knowledge of low level JDBC API
in some places I see code like this:
try {
con = ....
con.setAutoCommit(false);
//insert_1 pack to db
con.commit();
//insert_2 pack to db
con.commit();
//insert_3 pack to db
con.commit();
} catch (SQLException e) {
try {
con.rollback();
} catch (SQLException e) {
log.warn("SQLException on rolling back the destination connection. ", e);
throw e;
}
throw ex;
}
and sometimes con.rollback(); is not invoked in the the catch:
try {
con = ....
con.setAutoCommit(false);
//insert_1 pack to db
con.commit();
//insert_2 pack to db
con.commit();
//insert_3 pack to db
con.commit();
} catch (SQLException e) {
throw new MyBusinessException(ex);
}
Could you please explain difference from transaction standpoint ?
P.S.
I've read java doc for rollback but it doesn't answer my question.
Undoes all changes made in the current transaction and releases any
database locks currently held by this Connection object. This method
should be used only when auto-commit mode has been disabled. Throws:
SQLException – if a database access error occurs, this method is
called while participating in a distributed transaction, this method
is called on a closed connection or this Connection object is in
auto-commit mode See Also: setAutoCommit
The code looks incorrect.
There are several commits executed. This would mean that the explicit rollback could just rollback the state to the beginning of the last commit. This is, I guess, not what the rollback should do.
If no explicit rollback is called, at least in a pooled database connection (in a pooled database connection the connection is never closed, but reused) the already executed statements are still in transaction. I.e. calling here a rollback later would lead to strange kind of errors and also rolling back the last executed statements actually not related to the current business process. I see in the Hikari Connection Pool Implementation that dirty states are automatically rolled back, but maybe this correct behavior cannot be assumed for every implementation. E.g. the Apache DBCP is not that straight forward in the code and asking the maintainers if they are doing this should be helpful.
I see no close call.
For your questions this means the second code snippet should:
In a single non pooled connection not commit the last statements after the last commit, this is what would be correct (by accident).
In a pooled connection leave the transactions pending which could lead to the error that the next business logic committing something and reusing the connection will also commit this.
I am working with DB2. I created ConnectionPool for it. Some of the queries required to be executed in "aumoCommit = false" mode.
Connection con = ConnectionPool.getConnection // wrapper
con.setAutoCommit(false);
PreparedStatment ps = con.prepareStatement(// query... );
ps.setString(...);
ps.executeUpdate();
con.commit();
ps.close();
con.close();
con.setAutoCommit(true); // should be here ?
Question is: should i add con.setAutoCommit(true) line in the end or C3P0 resets state of every closed(returned to pool) Connection?
Edit: after a few comments, I add that my question is: should con.setAutoCommit(false) call be there in general or c3P0 reset state of this connection and nexct time this connection will be in con.setAutoCommit(false) by default?
c3p0 always releases Connections with autoCommit set to true, per the JDBC spec.
In general, c3p0 endeavors to make it true that nothing you do during an ordinary client session will have any effect on future client sessions. Once a Connection is checked back into the pool, c3p0 fully resets and restores its state.
The only place you can define Connection state that "sticks" across client sessions is in a ConnectionCustomizer's onAcquire(...) method, called before any client Session has been initiated. But this only works for Connection attributes whose value is undefined by the JDBC spec. Since autoCommit is required by spec to be true of a new Connection, and JDBC transparent Connection pooling requires pooled and new Connections be indistinguishable in application semantics, freshly checked-out Connections always have autoCommit set to true.
I have a method that creates a Connection with Embedded Derby Database and performs a Select query on it.
public PersonMID findPersonMID(String personAlias, CodeUID aliasTypeCodeUID, LogicalDomainMID logicalDomainMID) throws SQLException
{
Connection connection = getConnection();
try
{
QueryExecutor<Long> findPersonIdByPersonAliasExecutor = FindPersonIdByPersonAliasDelegate.getExecutor(authority,connection, personAlias);
Long result = findPersonIdByPersonAliasExecutor.execute();
if(result == null)
{
return null;
}
return PersonMID.create(authority, result);
}
finally
{
JDBCAssistant.close(connection);
}
Here is what my query looks like:
select P.PRSON_ID from PRSON_ALIAS PA join PRSON P on P.PRSON_ID = PA.PRSON_ID and P.LOGICAL_DOMAIN_ID = ? where PA.PRSON_ALIAS_TYPE_CD = ? and PA.ALIAS = ?
When I run through this code, I get an Exception
JDBCException: java.sql.SQLException: Cannot close a connection while a transaction is still active.
But when I call Connection.commit() before I close the Connectionor set autoCommit true (it is set to false by default for my Connection) for my Connection, it is allowing me to successfully close the connection and get the reqired result.
But do I really need to call commit() for a Select operation? What's there to commit? Is there a lock somewhere that is not being released if I dont commit?
This post says I shouldn't have to do it. I should be able to close my connection without having to commit or rollback.
What am I missing?
If you are not in autoCommit mode, then a SELECT statement is in fact holding read locks, depending on your isolation level, and so committing a SELECT query is more than a no-op.
Yes, there is no change to the database, but the commit still tells the database engine that your transaction is finished looking at the data, and it can therefore allow other transactions to modify the data.
Here's some background material:
Isolation levels and concurrency; https://db.apache.org/derby/docs/10.12/devguide/cdevconcepts15366.html
Shared locks: https://db.apache.org/derby/docs/10.12/devguide/cdevconcepts842304.html
I am pretty new to model layer just need clarification that in our code if autocommit is false like
Connection conn = DBUtil.getConnection(userDb);
conn.setAutoCommit(false);
And we get an exception which is not related to postgres like
if (response.getValue() != null) {
conn.commit();
}
Where response object is arbitrary value,does the transaction be roll backed automatically in postgres.
Thanks
It depends. If a connection is closed, the transaction should be rolled back by the database. If you're using a connection pool, the transaction should be rolled back by the pool, when the connection is returned.
However this can depend on the driver, as well as the connection pool, so you should explicitly do commits and rollbacks instead of relying on the driver or the pool.
For be sure, better rollback transaction explicitly:
if (response.getValue() != null) {
conn.commit();
}
else {
conn.rollback();
}
I have noticed some programmer using COMMIT other using conn.setAutoCommit(true); to end the transaction or roll back so what are the benefits of using one instead of the other?
Where is the main difference?
conn.setAutoCommit(true);
over
statement.executeQuery(query);
statement.commit();
You should in general use Connection.commit() and not Connection.setAutoCommit(true) to commit a transaction, unless you want to switch from using transaction to the 'transaction per statement' model of autoCommit.
That said, calling Connection.setAutoCommit(true) while in a transaction will commit the transaction (if the driver is compliant with section 10.1.1 of the JDBC 4.1 spec). But you should really only ever do that if you mean to stay in autoCommit after that, as enabling / disabling autoCommit on a connection may have higher overhead on a connection than simply committing (eg because it needs to switch between transaction managers, do additional checks, etc).
You should also use Connection.commit() and not use the native SQL command COMMIT. As detailed in the documentation of Connection:
Note: When configuring a Connection, JDBC applications should use the appropriate Connection method such as setAutoCommit or setTransactionIsolation. Applications should not invoke SQL commands directly to change the connection's configuration when there is a JDBC method available.
The thing is that commands like commit() and setAutoCommit(boolean) may do more work in the background, like closing ResultSets and closing or resetting Statements. Using the SQL command COMMIT will bypass this and potentially bring your driver / connection into an incorrect state.
The usage of conn.setAutoCommit(); applies to the connection and gives you the possibility to execute X queries in a single transaction, or use one single transaction per execute
As the API describes:
void setAutoCommit(boolean autoCommit)
throws SQLException
Sets this connection's auto-commit mode to the given state. If a connection is in auto-commit
mode, then all its SQL statements will be executed and committed as
individual transactions. Otherwise, its SQL statements are grouped
into transactions that are terminated by a call to either the method
commit or the method rollback. By default, new connections are in
auto-commit mode
For a simple case:
conn.setAutoCommit(false);
statement.executeQuery(query);
statement.commit();
will be the same as:
conn.setAutoCommit(true);
statement.executeQuery(query);