Apr 07

Persistence in enterprise solutions is not only about CRUD operations, but handling concurrency. Concurrency is handled mostly by locks at the database levels. These locks are configured at the dataobject level and cannot be easily controlled from the flow. The only way of controlling it based on the flow is a programmatic approach to it (via JPA locking api or equivalents). Most of the concurrency issues are discovered only in the later stages of development or at times only after the application goes live, a code change at these points is very difficult.

The approach outlined in this blog addresses this issue by making the lock management declarative. Rather than configuring the locks only at the dataobject level, it adds the dimension of flows too to the lock management configuration. For example : A show account Detail flow and a debit money from account flow would use the same account dataobject, most probably even the same method to retrieve the account information from the database, but the locking needs in both these scenarios are very different. The suggested solution allows for defining locks needed at a dataobject level (in this case Account) for these two flows differently.

The flow information is identified by the entry method. This entry method could be a EJB method or a Spring bean method, (any method call that can be intercepted as interceptors are a vital part of the implementation solution). Whenever an entity is now queried or operated on, the lock mode is automatically set based on the configuration. Under the hood it uses JPA or the persistence framework’s lock management interaction api to do so. It is assumed however that the lock management implementation leverages the database locks rather than a java side implementation of it.

This solution makes solving deadlocks easier, as the central lock manager is aware of all the flows and the locks. We can enforce a strict ordering in obtaining locks by associating strategies for obtaining locks. For example, we could define a comparator-based strategy for obtaining locks on a particular entity class. This could solve cases where rows from the same table cause deadlock between flows. The paper also details some of the other deadlock scenarios and strategies for solving them via this framework. It also touches on the diagnostics aspect, though it relies on the database for detecting the deadlock, it provides detailed information about the two participating flows and dataobjects, the information is not limited to just the transaction id or the sqls, but captures much more useful information.

More details about the implementation would be added in the later blogs depending on the interest in the discussion of this solution.

3 Responses to “Persistence and Locking”

  1. Using an isolation level is declarative form of concurrency control in databases. In most cases using the correct isolation level prevents setting any lock yourself. The database also is the central place where all locks are managed (not some jvm) and the database uses different strategies to deal-with/prevent deadlocks. In some cases using a time out can be enough, but also the inference of a deadlock is done. So when using a database, deadlocks are not my main worry.

    So the database is a very very advances mechanism for concurrency control. You could even say that in some areas it is much more advanced than Java (for example Multi Version Concurrency Control: MVCC) to improve upon concurrency by providing multiple versions of the same data.

  2. David Otaguro says:

    The only issue with the idea of “the central lock manager [that is] aware of all the flows and the locks” is that concurrency issues between clustered applications can’t be handled by a centralized lock manager unless you’re willing to make the centralized lock manager a clustered beast itself, which becomes potentially problematic.

    The database itself already has an excellent centralized lock manager… rather than locking rows in the actual tables and manipulating the lockmode of the selects, it might be better to use semaphores obtained from a table explicitly for the purpose of controlling locking behavior, for example a table called, LOCK_SEMAPHORES or somesuch. That makes the table the source of lock data (for the application), if necessary you can use the database’s utilities for lock manipulation to deal with lock problems, and you can distribute your locking manager with the shared lock state explicitly visible in the locks table.

    Just a thought.

  3. apnath says:

    The approach suggested centralized locking which manages locks, by managing I meant initiating the calls for getting and releasing the locks. The actual locks would be maintained at the db end. The whole idea is to spare individual methods from the locking parlance and decide it at a central level on the basis of flows. For example for two flows:
    1. That deposits money into an account
    2. Shows account balance
    We would need to get the account details from the account table, assuming that we wanted to lock the account details while making the deposit in case 1, the centralized manager would help us do so without coding special method for selecting the accounts.
    The lock obtained by the centralized manager is actually a db lock, in short the centralized manager would decide if the sql to be executed is a “FOR UPDATE” sql or otherwise. It could fit in more locking semantics as the need arises.

Leave a Reply

preload preload preload