Monday, April 1, 2013

SELECT ... FOR UPDATE with Spring JDBC

SELECT ... FOR UPDATE is required to lock specific row in database in order to prevent other query thread to read or make changes to the same row. The lock is released once you update the data or commit it.

As a Spring lover, it's hard to find references about implementing the technique in Spring JDBC template. But finally I managed to use it.


public MyDao {
    private PreparedStatementCreatorFactory queryForUpdateFactory;

    public MyDao() {
        queryForUpdateFactory = new PreparedStatementCreatorFactory(
            "SELECT name FROM people WHERE id = ? FOR UPDATE",
            Arrays.asList(new SqlParameter(Types.INTEGER)));

        // These lines are important!
        queryForUpdateFactory.setUpdatableResults(true);
        queryForUpdateFactory.setResultSetType(
            ResultSet.TYPE_SCROLL_SENSITIVE);
    }


    public void testSelectForUpdate() {
        Object id = "someID";

        PreparedStatementCreator psc = 
            queryForUpdateFactory.newPreparedStatementCreator(
            new Object[] { id });

        RowCallbackHandler rch = new RowCallbackHandler() {
            @Override
            public void processRow(ResultSet rs) throws SQLException {
                String name = rs.getString("name");

                // Do some manipulation
                if (name != "Jack") {
                    name = "Jack Sparrow";
                }

                // Update and release the lock
                rs.updateString("name", name);
            }

        };

        jdbcTemplate.query(psc, rch);
    }
}

I hope it's useful!

5 comments:

Christopher R. Gardner said...

Tried this with an in-memory H2 database. The select worked fine, but I couldn't get the update part to work.

Unknown said...

Did you manage to run the SQL without Spring?

O Noon Noeito said...

You need to add a "rs.updateRow()" after the "rs.updateString()" in order to "update" the actual row.

Neuronal Project said...

Hello, do you think it's possible to do a select for update like this :

1)

jdbc.query(MY_QERY_STRING, new MyMapper());

2) in the mapRow function just do :
rs.updateString("blabla","value");
rs.updateRow();

Thanks

Anil Karamchandani said...

Hi

Nice article, however I have a question, how about if the select is a join on 2 tables ?
would still

rs.updateString("blabla","value");
rs.updateRow();


this work ? how would oracle know which primary key this belongs to ?

thansk !