Bobby Fisher
Bobby Fisher

Reputation: 92

Concurrency - DB access

I need to process retrieving pending records and updating them to 'InProcess' state as a unit-of-work. I would like to make sure below code supports concurrency and other threads wait until my current thread is processed. What is the best way to achieve this?

public Collection<Object> processPendingMessages() {
    Collection<Object> messages = null;
    //Retrieve pending messages
    messages = messageDAO.getPendingMessages(Direction.INBOUND);
    //Update pending messages to Inprocess
    if (messages!=null && messages.size()>0) {
        messageDAO.updateMessagesToInprocess(messages); 
    } 
    return messages;
}

Your input is highly appreciated. Thanks.

Upvotes: 2

Views: 4366

Answers (3)

happymeal
happymeal

Reputation: 1413

you should let the database handle the concurrency.

in your DAO, you can issue the sql query:

// works on oracle.
// query may differ depending on vendor
select * from test where id=? for update 

the first thread will be able to acquire the lock but subsequent threads will block if they execute the query. once the first thread has commit/rollback, the one of the waiting threads will unblock. this way, you can have readers reading one at a time.

Upvotes: 0

reddyvaribabu
reddyvaribabu

Reputation: 878

You dont want to handle the DBAccess concurrency at the jvm level alone by using (synchronized). In your case the access is to the database which will not be possible with mere synchronization at jvm level. You need to handle the concurrency at the database connectivity level too as follows. You haven't mentioned what kind of implementation is in your DAO layer as far as DBaccess is concerned, but what ever it could be, the following isolation levels for JDBC should make sense with your implementation too irrespective of it being (JDBC, JPA with Hibernate or EJB, etc). Read through the isolation levels below and descide which one is good for your application. All the best with your implementation.

Transaction isolation levels specify what data is visible to statements within a transaction as a unit of transaction. These levels directly impact the level of concurrent access by defining what interaction is possible between transactions against the same target data source.

DATABASE ANOMOLIES

Database anomalies are generated results that seem incorrect when looked at from the scope of a single transaction, but are correct when looked at from the scope of all transactions. The different types of database anomalies are described as follows:

Dirty reads occur when: Transaction A inserts a row into a table. Transaction B reads the new row. Transaction A rolls back. Transaction B may have done work to the system based on the row inserted by transaction A, but that row never became a permanent part of the database.

Nonrepeatable reads occur when: Transaction A reads a row. Transaction B changes the row. Transaction A reads the same row a second time and gets the new results.

Phantom reads occur when: Transaction A reads all rows that satisfy a WHERE clause on an SQL query. Transaction B inserts an additional row that satisfies the WHERE clause. Transaction A re-evaluates the WHERE condition and picks up the additional row.

ISOLATION LEVELS THAT HANDLES EACH OF ABOVE ANOMOLIES

JDBC_TRANSACTION_NONE This is a special constant indicating that the JDBC driver does not support transactions.

JDBC_TRANSACTION_READ_UNCOMMITTED This level allows transactions to see uncommitted changes to the data. All database anomalies are possible at this level.

JDBC_TRANSACTION_READ_COMMITTED any changes made inside a transaction are not visible outside it until the transaction is committed. This prevents dirty reads from being possible.

JDBC_TRANSACTION_REPEATABLE_READ rows that are read retain locks so that another transaction cannot change them when the transaction is not completed. This disallows dirty reads and nonrepeatable reads. Phantom read are still possible.

JDBC_TRANSACTION_SERIALIZABLE tables are locked for the transaction so that WHERE conditions cannot be changed by other transactions that add values to or remove values from a table. This prevents all types of database anomalies.

The setTransactionIsolation method can be used to change the transaction isolation level for a connection.

Upvotes: 6

Eric Hydrick
Eric Hydrick

Reputation: 3527

To prevent race conditions in the code, use the synchronizedkeyword to keep threads from accessing a code block until the previous thread is done with it.

Upvotes: -1

Related Questions