Reputation: 56666
I am using JdbcTemplate from Spring framework.
The database is Oracle.
Simplified Code:
void m() {
setAutocommit(false); // the same result with/without this line (by default: true )
JdbcTemplate jt;
...
String selectForUpdateLine = "SELECT X FROM T ... FOR UPDATE";
int x = jt.queryForList(selectForUpdateLine, objs, types, Smth.class).size();
...
addDelay(); // to be sure that I can simulate 2 consecutive SELECTs (just for test)
...
if ( x == 0 )
jt.update(insertLine, objs2, types2); // insert
else
jt.update(updateLine, objs2, types2); // update
}
If I call m()
twice it executes:
SELECT > SELECT > INSERT/UPDATE > INSERT/UPDATE
but I want to have
SELECT > INSERT/UPDATE > SELECT > INSERT/UPDATE
I expected to have a lock after the first SELECT
( on the strengths of SELECT ... FOR UPDATE
), but both selects are called, so the UPDATE/INSERT
doesn't work well.
I also tried to use @Transactional
for the method, trying to have a single transaction that contains both INSERT
and UPDATE/INSERT
, but it didn't work.
E.g.:
@Transactional(isolation=Isolation.SERIALIZABLE,propagation=Propagation.REQUIRES_NEW)
How can I be sure that SELECT
and UPDATE/INSERT
will be run together ? (with/without SELECT ... FOR UPDATE
, @Transactional
, etc. )
Upvotes: 2
Views: 7805
Reputation: 21
Try removing JDBCTemplate and use simple jdbc statement and see if it locks.
Upvotes: 0
Reputation: 3099
Instead of a SELECT FOR UPDATE and then an INSERT or UPDATE can't you just issue a single MERGE statement, and let the database do the hard work for you. You may need to check you have the appropriate Unique Constraints on the table you are merging into e.g.
void m() {
JdbcTemplate jt;
...
jt.update(mergeLine, objs2, types2); // merge
}
Upvotes: 1
Reputation: 417747
Why did you turn off auto-commit?
setAutocommit(false);
Since you disabled auto-commit, your INSERT/UPDATE
will not be executed immediately. So if you call m()
twice, since it starts with a SELECT
that will be executed again before the INSERT/UPDATE
from the previous run will be executed, hence you'll see an execution order:
SELECT > SELECT > INSERT/UPDATE > INSERT/UPDATE
You should commit before you return from m()
or you should go with @Transactional
but don't disable auto-commit.
Upvotes: 1