Lock (Locking)
In the process of implementing business logic, it is often necessary to guarantee the exclusivity of data access. As in the final settlement of the financial system, we want to process the data for a cut-off point in time, and we do not want the data to change again during the settlement process (which may be a few seconds or maybe a few hours). At this point, we need some mechanism to ensure that the data will not be modified in the process of the outside, such a mechanism, in this case, the so-called "lock", that is, to our selected target data locked, so that it can not be modified by other programs.
Hibernate supports two locking mechanisms: "Pessimistic lock (pessimistic Locking)" and "optimistic lock (optimistic Locking)", which is commonly referred to.
Pessimistic lock (Pessimistic Locking)
Pessimistic locking, as its name implies, is a conservative attitude to the data being modified by the outside world (including other transactions currently in the system, as well as transactions from external systems), so that the data is locked during the entire data processing process. Pessimistic lock implementation, often rely on the database provided by the lock mechanism (also only the database layer provides a lock mechanism to truly guarantee the exclusivity of data access, otherwise, even in this system to implement the locking mechanism, there is no guarantee that the external system will not modify the data).
A typical pessimistic lock call that relies on a database:
SELECT * from account where name= ' Erica ' for update
This SQL statement locks all records in the Account table that match the search criteria (name= "Erica").
These records cannot be modified by the outside world before the transaction commits (the locks in the transaction are freed during transaction commits).
Hibernate's pessimistic lock is also a database-based lock mechanism implementation.
The following code implements the locking of the query record:
String hqlstr = "from TUser as user where user.name= ' Erica '" ; Query query = session.createquery (HQLSTR), Query.setlockmode ( "user" , Lockmode.upgrade); //locking List userlist = Query.list (); //executes the query, gets the data Query.setlockmode locks the records corresponding to a particular alias in the query statement (we have specified an alias "user" for the Tuser Class), This is to lock all the user records returned. Observe the SQL statements generated by hibernate during run time: select tuser0_.id as ID, tuser0_.name as name, Tuser0_.group_idas group_id, Tuser0_.user_type as user_type, tuser0_.sex As sexfrom t_user tuser0_ where (tuser0_ . Name= ' Erica ' ) for update
Here hibernate implements the pessimistic locking mechanism by using the database's for UPDATE clause.
Hibernate's lock modes are:
? Lockmode.none: no lock mechanism.
? LockMode.WRITE:Hibernate is automatically acquired when the insert and update records are recorded.
? The LockMode.READ:Hibernate is automatically retrieved when the record is read.
These three types of locking mechanisms are typically used internally by hibernate, such as hibernate to automatically add write locks to the target object in the Save method implementation, in order to ensure that the object is not modified by the outside world during the update process.
? Lockmode.upgrade: Use the database's for UPDATE clause to lock.
? Lockmode. A specific implementation of the Upgrade_nowait:oracle, using Oracle's for UPDATE NOWAIT clause to implement the lock.
The above two kinds of locking mechanism is more commonly used in the application layer, lock is generally implemented by the following methods:
Criteria.setlockmode
Query.setlockmode
Session.lock
Note that locking is really done through the lock mechanism of the database only if the lock is set before the query starts (that is, before the hiberate generates SQL), otherwise the data has been loaded through a select SQL that does not contain a FOR UPDATE clause, so the so-called database lock is not possible.
Optimistic lock (optimistic Locking)
Relative pessimistic lock, the optimistic locking mechanism adopts a more relaxed locking mechanism. Pessimistic locking relies on the lock mechanism of the database in most cases, to ensure the maximum degree of exclusivity of the operation. But it comes with a lot of overhead for database performance, especially for long transactions, which are often unsustainable.
As a financial system, when an operator reads a user's data and modifies it on the basis of the user's data being read (such as changing the user account balance), the pessimistic locking mechanism means that the entire operation (from the operator reads the data, starts the modification until the entire process of submitting the modification result, even includes the operation
Staff to cook coffee in the middle of the time), database records are always locked, you can imagine, if faced with hundreds of thousands of concurrent, this situation will lead to what consequences.
The optimistic locking mechanism solves this problem to some extent. Optimistic locking, mostly based on the data version (versions) recording mechanism implementation. What is a data version? is to add a version identity to the data, which is typically done by adding a "version" field to the database table in the version solution based on the database table.
When the data is read, the version number is read together, and then the version number is added one after the update. At this point, the version data of the submitted data is compared to the current version information of the database table corresponding to the record, and if the submitted version number is greater than the current version number of the database table, it is updated, otherwise it is considered to be outdated data.
For the example above to modify user account information, assume that there is a version field in the Account information table in the database, the current value is 1, and the Current Account balance field (balance) is $ $.
1 operator A reads it out at this time (version=1) and deducts it from its account balance < Span class= "Mrow" id= "mathjax-span-2" > 50 ( 100-$50).
2 during operator A's operation, operator B also reads this user information (version=1) and deducts it from its account balance < Span class= "Mrow" id= "mathjax-span-8" > 20 ( 100-$20).
3 operator A has completed the modification work, the data version number plus one (version=2), together with the account deduction after the balance (BALANCE=$50), submitted to the database update, at this time because the submission data version is larger than the current version of database records, the data is updated, database record version updated to 2.
4 operator B completes the operation, and the version number plus one (version=2) attempts to submit data (BALANCE=$80) to the database, but at this time compared to the database record version, operator B submits the data version number 2, the database records the current version is 2, does not meet the " The commit version must be larger than the current version of the record to perform the update "optimistic locking policy, so the submission of operator B is dismissed.
This avoids the possibility of operator B overwriting operator A's results with the results of old version=1-based data modifications.
As can be seen from the above example, the optimistic locking mechanism avoids the database lock-up overhead in a long transaction (both operator A and operator B do not locking the database data), which greatly improves the overall performance of the system under large concurrent volume.
It should be noted that the optimistic locking mechanism is often based on the data storage logic in the system, so there are some limitations, as in the above example, because the optimistic locking mechanism is implemented in our system, the user balance update from the external system is not controlled by our system, it may cause dirty data to be updated into the database. In
During the system design phase, we should take full account of the possibility of these situations and make adjustments (such as implementing the optimistic locking policy in the database stored procedure, open only the data update path based on this stored procedure, rather than exposing the database table directly to the external).
Hibernate has built-in optimistic locking implementations in its data access engine. If you do not take into account the external system to update the database, using hibernate to provide a transparent optimistic lock implementation, will greatly enhance our productivity.
Hibernate can be specified by using the Optimistic-lock property of the class descriptor in conjunction with the version descriptor.
Now, let's add an optimistic locking mechanism to the tuser in the previous example.
1. First, add the Optimistic-lock property to the class descriptor for Tuser:
< hibernate-mapping > < classname = "Org.hibernate.sample.TUser" table= "T_user" dynamic-update = dynamic-insert = optimistic-lock = "version" > ... < /class> < /hibernate-mapping >
The Optimistic-lock property resembles the following selectable value:
? None
No optimistic lock
? Version
Optimistic locking via version mechanism
? Dirty
Optimistic locking by checking for properties that have changed
? All
Optimistic locking by checking all properties
The optimistic locking mechanism, which is implemented through version, is the optimistic lock implementation that hibernate officially recommends, and also
Is hibernate, the only lock machine that is still valid if the data object is modified from the session
System. Therefore, in general, we all choose the version mode as the hibernate optimistic lock implementation mechanism.
2. Add a Version Property descriptor
classname="Org.hibernate.sample.TUser"table="T_user"Dynamic-update="true"dynamic-insert="true"optimistic-lock="Version"><IDname="id"column="id"Type="Java.lang.Integer"><generatorclass="native"></generator></ID><versioncolumn="Version"name="Version"Type="Java.lang.Integer"/>......</class>
Note The version node must appear after the ID node.
Here we declare a version property, which holds the user's release information, and is saved in the Tuser table's versions field.
At this point, if we try to write a piece of code, update the record data in the Tuser table, such as:
Criteria = Session. Createcriteria(TUser. Class);Criteria. Add(Expression. EQ("Name","Erica"));List userlist = Criteria. List();TUser user = (TUser) userlist. Get(0);Transaction tx = Session. BeginTransaction();User. Setusertype(1);//update usertype fieldTx. Commit();
Each time we update the Tuser, we can see that the version in the database is incremented.
And if we try to start another session before Tx.commit, manipulate the user named Erica to emulate the Concurrency update scenario:
Session session= getsession ();Criteria = Session. Createcriteria(TUser. Class);Criteria. Add(Expression. EQ("Name","Erica"));Session Session2 = getsession ();Criteria criteria2 = Session2. Createcriteria(TUser. Class);Criteria2. Add(Expression. EQ("Name","Erica"));List userlist = Criteria. List();List UserList2 = criteria2. List(); TUser user = (TUser) userlist.get (0);TUser user2 = (TUser) userList2. Get(0);Transaction tx = Session. BeginTransaction();Transaction TX2 = Session2. BeginTransaction();User2. Setusertype( About);Tx2. Commit();User. Setusertype(1);Tx. Commit();
Executing the above code, the code throws an Staleobjectstateexception exception at Tx.commit () and indicates that the version check failed and that the current transaction is attempting to submit an expired data. By catching this exception, we can handle the optimistic lock check when it fails.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Implementation of Java pessimistic lock and optimistic lock