This article mainly studies all the contents of Hibernate pessimistic locks and optimistic locks, as detailed below.
Pessimistic locking is usually implemented by the database mechanism. During the entire process, data is locked (when querying). As long as things are not released (commit/rollback), no user can view or modify it.
Let’s explain it through a case below.
Case: Suppose the inventory of goods is 1000, and when the accountant 1 takes out the data and prepares for modification, but there is something temporary, he leaves. During this period, the accounting 2 extracted the data and subtracted the quantity by 200, and then the accounting 1 came back and subtracted the quantity just removed by 200. This caused a problem. The accounting 1 did not make any modifications based on 800. This is called update loss, and it can be solved by using pessimistic locks.
Inventory.java:
public class Inventory { /* Inventory number*/ private String itemNo; /* Inventory name*/ private String itemName; /* Inventory quantity*/ private int quantity; //Omit setter and getter methods}Inventory.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.lixue.bean.Inventory" table="t_inventory"> <!-- Manual assignment of primary key--> <id name="itemNo"> <generator//id> <!-- Mapping properties--> <property name="itemName"/> <property name="quantity"/> </class> </hibernate-mapping>
Test class:
Accountant 1 loads data through pessimistic locking and modifies the data!
public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); /*A pessimistic lock is added when loading, making it impossible for other users to access*/ Inventory inv = (Inventory) session.load(Inventory.class, "1001", LockMode.UPGRADE); /*Get data*/ System.out.println("opt1-->itemNo=" + inv.getItemNo()); System.out.println("opt1-->itemName=" + inv.getItemName()); System.out.println("opt1-->quantity=" + inv.getQuantity()); /*Quantity minus 200*/ inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit(); } catch (Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }Accountant 2 and Accountant 1 have the same operations, and both modify the data in the database!
public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); /*Add a lock when loading data, so that others cannot get data*/ Inventory inv = (Inventory) session.load(Inventory.class, "1001", LockMode.UPGRADE); /*Get the real data*/ System.out.println("opt2-->itemNo=" + inv.getItemNo()); System.out.println("opt2-->itemName=" + inv.getItemName()); System.out.println("opt2-->quantity=" + inv.getQuantity()); /*Inventory minus 200*/ inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit(); } catch (Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }Note: The operations performed by the two accountants are the same. If a pessimistic lock is added, the accountant takes out the data and modifys the data. Before Accountant 1 submits the thing, Accountant 2 cannot access the data and can only be in a waiting state. Only after knowing that Accountant 1 has submitted the thing, Accountant 2 has the opportunity to operate on the data in the database.
Through the above pessimistic lock case, we can find that the biggest advantage of pessimistic lock is that it can prevent update loss. When Calculator 1 is processing data, Calculator 2 can only be in a waiting state. Only after Calculator 1 submits the thing, Calculator 2 has the opportunity to modify the data. But there is also a big problem, that is, if the accountant 1 queries the data and leaves, then the others will have to wait for most of the day, which is a very waste of time. In order to solve this problem, we can use optimistic locks.
Optimistic locks are not locks in the true sense. In most cases, they are implemented in the form of a data version. Generally, a version field is added to the database, and the version is read out when reading the data. When saving the data, it determines whether the version value is smaller than the version value of the database. If it is less, it will not be updated, otherwise it will be updated.
The javaBean settings under optimistic locks, Inventory.java:
public class Inventory { /*Inventory number*/ private String itemNo; /*Inventory name*/ private String itemName; /*Inventory quantity*/ private int quantity; /*Data version*/ private int version; //Omit setter and getter methods}Inventory.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- Add the optimistc-lock attribute to the class tag, and its value is version confidence--> <class name="com.lixue.bean.Inventory" table="t_inventory" optimistic-lock="version"> <!-- Primary key mapping--> <id name="itemNo"> <generator/> </id> <!-- Data version, must be at the location after the primary key --> <version name="version"/> <!-- Basic property mapping --> <property name="itemName"/> <property name="quantity"/> </class> </hibernate-mapping>
Note: The mapping file using optimistic locks stipulates that the mapping of the version field must be mapped first after the primary key ID.
Accountant 1 processes data in an optimistic lock situation:
public void testLoad1() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); /*Load data under optimistic lock*/ Inventory inv = (Inventory)session.load(Inventory.class, "1001"); /*Real data acquisition*/ System.out.println("opt1-->itemNo=" + inv.getItemNo()); System.out.println("opt1-->itemName=" + inv.getItemName()); System.out.println("opt1-->version=" + inv.getVersion()); System.out.println("opt1-->quantity=" + inv.getQuantity()); /*Quantity minus 200*/ inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }Accountant 2 processes data under optimistic locking (accountant 2 can process data without submitting it)
public void testLoad2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction(); /*Load data under optimistic lock*/ Inventory inv = (Inventory)session.load(Inventory.class, "1001"); /*Real data acquisition*/ System.out.println("opt2-->itemNo=" + inv.getItemNo()); System.out.println("opt2-->itemName=" + inv.getItemName()); System.out.println("opt2-->version=" + inv.getVersion()); System.out.println("opt2-->quantity=" + inv.getQuantity()); /*Quantity minus 200*/ inv.setQuantity(inv.getQuantity() - 200); session.getTransaction().commit(); }catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }Note: On the premise that the accountant takes out the data and subtracts the number by 200 and does not submit it, the accountant 2 can also operate the data. This is different from pessimistic lock. When the accountant 2 operates the data and submits it, the data version version in the database will be added by 1. Then when the accountant 1 comes back to submit the thing, an error message will appear that the data has been updated, please reload it.
Pessimistic locks will affect high concurrency, so it is better to use optimistic locks.
The above is all the detailed explanation of Hibernate pessimistic lock and optimistic lock examples in this article. I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!