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.