The use of locks and query types in Java Hibernate framework database operations _java

Source: Internet
Author: User
Tags rollback

Hibernate and Database Locks
One, why use the lock?

To understand the reasons for the existence of the lock mechanism, the first thing to know is the concept of the transaction.
A transaction is a series of related operations to a database that must have acid characteristics:

    • A (atomicity): either all succeeds or all is withdrawn.
    • C (consistency): To maintain consistency in the database.
    • I (Isolation): When different transactions operate the same data, have to have their own data space.
    • D (persistence): Once a transaction completes successfully, its update to the database must be persisted permanently.

Our common relational database RDBMS implements these features of the transaction. Among them, the atomic nature,
Consistency and persistence are guaranteed by logging. And segregation is what we focus on today.
Lock mechanism to implement, which is why we need the lock mechanism.

What could be the consequences if there were no locks and no control over isolation?

    1. Update Missing: Transaction 1 submitted data is overwritten by transaction 2.
    2. Dirty reads: Transaction 2 queries the uncommitted data for transaction 1.
    3. Virtual read: Transaction 2 queries the new data submitted by transaction 1.
    4. Non-repeatable reads: Transaction 2 queries the update data submitted by transaction 1.

Here's a look at the hibernate example, two threads open two transaction operations Tb_account table
The same row of data col_id=1.

Package com.cdai.orm.hibernate.annotation; 
 
Import java.io.Serializable; 
Import Javax.persistence.Column; 
Import javax.persistence.Entity; 
Import Javax.persistence.Id; 
 
Import javax.persistence.Table; @Entity @Table (name = "Tb_account") public class account implements Serializable {private static final long serial 
 
  Versionuid = 5018821760412231859L; 
   
  @Id @Column (name = "col_id") private long Id; 
 
  @Column (name = "Col_balance") private long balance; 
    Public account () {} public account (long ID, long balance) {this.id = ID; 
  This.balance = balance; 
  Public long GetId () {return id; 
  public void SetId (long id) {this.id = ID; 
  Public long GetBalance () {return balance; 
  } public void Setbalance (long balance) {this.balance = balance; 
  @Override public String toString () {return "account [id=" + ID + ", balance=" + Balance + "]"; 
 } 
   
}

Package com.cdai.orm.hibernate.transaction; 
Import org.hibernate.Session; 
Import Org.hibernate.SessionFactory; 
Import org.hibernate.Transaction; 
 
Import org.hibernate.cfg.AnnotationConfiguration; 
 
Import Com.cdai.orm.hibernate.annotation.Account; public class Dirtyread {public static void main (string[] args) {final sessionfactory sessionfactory = new 
        Notationconfiguration ().        
        AddFile ("Hibernate/hibernate.cfg.xml"). 
        Configure (). 
        Addpackage ("Com.cdai.orm.hibernate.annotation"). 
        Addannotatedclass (Account.class). 
     
    Buildsessionfactory (); thread T1 = new Thread () {@Override public void Run () {Session Session1 = Sessionfactory. 
        Opensession (); 
        Transaction tx1 = null; 
          try {tx1 = Session1.begintransaction (); 
          System.out.println ("T1-begin trasaction"); 
           
          Thread.Sleep (500);  
   Account Account = (account)           Session1.get (Account.class, New Long (1)); 
          System.out.println ("t1-balance=" + account.getbalance ()); 
           
          Thread.Sleep (500); 
          Account.setbalance (account.getbalance () + 100); 
           
          System.out.println ("T1-change balance:" + account.getbalance ()); 
          Tx1.commit (); 
          System.out.println ("T1-commit transaction"); 
        Thread.Sleep (500); 
          catch (Exception e) {e.printstacktrace (); 
        if (tx1!= null) tx1.rollback (); 
        finally {session1.close (); 
     
    } 
      } 
       
    }; 3.Run Transaction 2 Thread t2 = new Thread () {@Override public void Run () {Sessio 
        n session2 = sessionfactory.opensession (); 
        Transaction tx2 = null; 
          try {tx2 = Session2.begintransaction (); 
          System.out.println ("T2-begin trasaction"); Thread.sLeep (500); 
          Account Account = (account) Session2.get (Account.class, New Long (1)); 
          System.out.println ("t2-balance=" + account.getbalance ()); 
           
          Thread.Sleep (500); 
          Account.setbalance (Account.getbalance ()-100); 
           
          System.out.println ("T2-change balance:" + account.getbalance ()); 
          Tx2.commit (); 
          System.out.println ("T2-commit transaction"); 
        Thread.Sleep (500); 
          catch (Exception e) {e.printstacktrace (); 
        if (tx2!= null) tx2.rollback (); 
        finally {session2.close (); 
     
    } 
      } 
       
    }; 
    T1.start (); 
     
    T2.start (); 
      while (t1.isalive () | | | t2.isalive ()) {try {thread.sleep (2000L); 
    The catch (Interruptedexception e) {}} System.out.println ("Both T1 and T2 are dead."); Sessionfactory.close (); 
     
  } 
 
} 
 

Transaction 1 reduces the col_balance by 100, and transaction 2 decreases it by 100, the end result may be 0, and
May be 200, the update of transaction 1 or 2 may be lost. Log output also confirms this, transactions 1 and 2
The log cross print.

T1-begin trasaction
t2-begin trasaction
hibernate:select account0_.col_id as col1_0_0_, Account0_.col_balanc E as col2_0_0_ from Tb_account account0_ where account0_.col_id=?
Hibernate:select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from Tb_account account0_ where Accoun T0_.col_id=?
t1-balance=100
t2-balance=100
t2-change balance:0
t1-change balance:200 hibernate:update Tb_accou
NT set col_balance=? where col_id=?
Hibernate:update Tb_account set col_balance=? where col_id=?
T1-commit transaction T2-commit transaction Both T1 and T2 are
.

Thus, isolation is a problem that needs careful consideration, it is necessary to understand the lock.


two, how many kinds of locks?

Common locks, update locks, and exclusive locks are shared.

1. Shared locks: For reading data operations, allowing other transactions to be read at the same time. When a transaction executes a SELECT statement, the
The database automatically assigns a shared lock to the transaction to lock the read data.
2. Exclusive lock: For modifying data, other transactions cannot be read or modified. When a transaction performs an INSERT,
Update and delete, the database is automatically allocated.
3. Update Lock: Used to avoid the deadlock caused by shared locks when updating operations, such as transactions 1 and 2 holding
Shares the lock and waits for an exclusive lock. When you execute update, the transaction gets the update lock first, and then the
Update locks are upgraded to exclusive locks, thus avoiding deadlocks.

In addition, these locks can be applied to different objects in the database, that is, these locks can have different granularity.
such as database-level locks, table-level locks, page-level locks, key-level locks, and row-level locks.

So there are many kinds of locks, so many locks to fully grasp the flexibility to use is too difficult, we are not DBAs.
What to do? Fortunately, the lock mechanism for our general users is transparent, the database will automatically add the appropriate
Lock, and in the appropriate time to automatically upgrade, downgrade a variety of locks, it is too thoughtful! All we have to do is
Learn to set the isolation level to suit different business needs.


third, how to set the isolation level?

In general, the database system provides four transaction isolation levels for users to choose from:

1.Serializable (serialization): When two transactions manipulate the same data at the same time, transaction 2 can only be stopped and so on.

2.Repeatable Read (REPEATABLE): Transaction 1 can see transaction 2 newly inserted data and cannot see the
An update of the existing data.

3.Read commited (read submitted data): Transaction 1 can see transactions 2 newly inserted and updated data.

4.Read uncommited (Read UNCOMMITTED data): Transaction 1 can see transaction 2 inserts and updates not committed
Data.


Iv. Locks in the application

Pessimistic or optimistic locks can be used in an application when the database uses the Read Commited isolation level.

1. Pessimistic lock: Assuming that the current transaction operation data will certainly have other transaction access, so pessimistic in the application
explicitly specifies that an exclusive lock is used in the program to lock the data resource. The following forms are supported in MySQL and Oracle:

   Select ... for update

Explicitly let select take a record of an exclusive lock-locked query, and other transactions to query, update, or delete these
The locked data will not be done until after the transaction has ended.

In hibernate, you can pass in the Lockmode.upgrade to use pessimistic locks when load. To modify the previous example,
More than one lockmode parameter is passed in the Get method call at transaction 1 and 2. As you can see from the log, transactions 1 and 2
is no longer a cross run, transaction 2 waits for transaction 1 to finish before reading the data, so the final col_balance value is correct
of 100.

Package com.cdai.orm.hibernate.transaction; 
Import Org.hibernate.LockMode; 
Import org.hibernate.Session; 
Import Org.hibernate.SessionFactory; 
 
Import org.hibernate.Transaction; 
Import Com.cdai.orm.hibernate.annotation.Account; 
 
Import Com.cdai.orm.hibernate.annotation.AnnotationHibernate; public class Upgradelock {@SuppressWarnings (' deprecation ') public static void main (string[] args) {final  
 
    Sessionfactory sessionfactory = Annotationhibernate.createsessionfactory (); Run Transaction 1 Thread t1 = new Thread () {@Override public void Run () {session 
        Session1 = Sessionfactory.opensession (); 
        Transaction tx1 = null; 
          try {tx1 = Session1.begintransaction (); 
          System.out.println ("T1-begin trasaction"); 
           
          Thread.Sleep (500); 
          Account Account = (account) Session1.get (Account.class, New Long (1), lockmode.upgrade); System.out.println ("t1-balance=" + account.getbalance ()); 
           
          Thread.Sleep (500); 
          Account.setbalance (account.getbalance () + 100); 
           
          System.out.println ("T1-change balance:" + account.getbalance ()); 
          Tx1.commit (); 
          System.out.println ("T1-commit transaction"); 
        Thread.Sleep (500); 
          catch (Exception e) {e.printstacktrace (); 
        if (tx1!= null) tx1.rollback (); 
        finally {session1.close (); 
     
    } 
      } 
       
    }; Run Transaction 2 Thread t2 = new Thread () {@Override public void Run () {session 
        Session2 = Sessionfactory.opensession (); 
        Transaction tx2 = null; 
          try {tx2 = Session2.begintransaction (); 
          System.out.println ("T2-begin trasaction"); 
           
          Thread.Sleep (500);  
             Account Account = (account) Session2.get (Account.class, New Long (1), lockmode.upgrade); 
          System.out.println ("t2-balance=" + account.getbalance ()); 
           
          Thread.Sleep (500); 
          Account.setbalance (Account.getbalance ()-100); 
           
          System.out.println ("T2-change balance:" + account.getbalance ()); 
          Tx2.commit (); 
          System.out.println ("T2-commit transaction"); 
        Thread.Sleep (500); 
          catch (Exception e) {e.printstacktrace (); 
        if (tx2!= null) tx2.rollback (); 
        finally {session2.close (); 
     
    } 
      } 
       
    }; 
    T1.start (); 
     
    T2.start (); 
      while (t1.isalive () | | | t2.isalive ()) {try {thread.sleep (2000L); 
    The catch (Interruptedexception e) {}} System.out.println ("Both T1 and T2 are dead."); 
 
  Sessionfactory.close (); 
 } 
 
}
T1-begin trasaction
t2-begin trasaction
hibernate:select account0_.col_id as col1_0_0_, Account0_.col_balanc E as col2_0_0_ from Tb_account account0_ with (Updlock, rowlock) where account0_.col_id=?
Hibernate:select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from Tb_account with (account0_ K, rowlock) where account0_.col_id=?
t2-balance=100
t2-change balance:0
hibernate:update tb_account set col_balance=? where col_id=?
T2-commit transaction
t1-balance=0
t1-change balance:100 hibernate:update
set tb_account? where col_id=?
T1-commit transaction
Both T1 and T2 are.

Hibernate executes SQL for SQL Server 2005:

Copy Code code as follows:

Select account0_.col_id as col1_0_0_, account0_.col_balance as col2_0_0_ from Tb_account account0_ with (Updlock, Rowlock) where account0_.col_id=?


Adds row and update locks to the selected col_id for 1 data rows.

2. Optimistic lock: assumes that the data for the current transaction operation does not have other transactions to be accessed concurrently, and therefore relies entirely on the database
Isolation level to automate the work of managing locks. Use version control in your application to avoid possible low probability occurrences
Concurrency issues.

In Hibernate, you use the version annotation to define the build Number field.

Replaces the account object in Dirtylock with Accountversion, the other code is unchanged, and an exception is executed.

Package com.cdai.orm.hibernate.transaction; 
Import Javax.persistence.Column; 
Import javax.persistence.Entity; 
Import Javax.persistence.Id; 
Import javax.persistence.Table; 
 
Import javax.persistence.Version; @Entity @Table (name = "Tb_account_version") public class Accountversion {@Id @Column (name = "col_id") privat 
   
  e long id; 
   
  @Column (name = "Col_balance") private long balance; 
 
  @Version @Column (name = "Col_version") private int Version; 
    Public accountversion () {} public accountversion (long ID, long balance) {this.id = ID; 
  This.balance = balance; 
  Public long GetId () {return id; 
  public void SetId (long id) {this.id = ID; 
  Public long GetBalance () {return balance; 
  } public void Setbalance (long balance) {this.balance = balance; 
  public int getversion () {return version; 
  public void setversion (int version) {this.version = version; } 
   
} 
 

Log is as follows:

T1-begin trasaction t2-begin trasaction hibernate:select accountver0_.col_id as col1_0_0_, accountver0_.col_balance
As col2_0_0_, accountver0_.col_version as col3_0_0_ from Tb_account_version accountver0_ where accountver0_.col_id=? Hibernate:select accountver0_.col_id as col1_0_0_, accountver0_.col_balance as col2_0_0_, accountver0_.col_version as
col3_0_0_ from Tb_account_version accountver0_ where accountver0_.col_id=? t1-balance=1000 t2-balance=1000 t1-change balance:900 t2-change balance:1100 hibernate:update tb_account_version Set col_balance=?, col_version=? where col_id=?
and col_version=? Hibernate:update tb_account_version set col_balance=?, col_version=? where col_id=?
and col_version=? T1-commit transaction 2264 [Thread-2] ERROR org.hibernate.event.def.abstractflushingeventlistener-could not Synchroni Ze database state with session Org.hibernate.StaleObjectStateException:Row is updated or deleted by another transaction (or Unsaved-value Mapping was IncOrrect): [Com.cdai.orm.hibernate.transaction.accountversion#1] at Org.hibernate.persister.entity.AbstractEntityPersister.check (abstractentitypersister.java:1934) at Org.hibernate.persister.entity.AbstractEntityPersister.update (abstractentitypersister.java:2578) at Org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert (abstractentitypersister.java:2478) at Org.hibernate.persister.entity.AbstractEntityPersister.update (abstractentitypersister.java:2805) at Org.hibernate.action.EntityUpdateAction.execute (entityupdateaction.java:114) at Org.hibernate.engine.ActionQueue.execute (actionqueue.java:268) at Org.hibernate.engine.ActionQueue.executeActions (actionqueue.java:260) at Org.hibernate.engine.ActionQueue.executeActions (actionqueue.java:180) at Org.hibernate.event.def.AbstractFlushingEventListener.performExecutions (abstractflushingeventlistener.java:321 ) at Org.hibernate.event.def.DefaultFlushEventListener.onFlush (defaultflusheventlistener.java:51) at Org.hibernate.impl.SessionImpl.flush (sessionimpl.java:1206) at Org.hibernate.impl.SessionImpl.managedFlush ( sessionimpl.java:375) at Org.hibernate.transaction.JDBCTransaction.commit (jdbctransaction.java:137) at

 Com.cdai.orm.hibernate.transaction.versionlock$2.run (versionlock.java:93) Both T1 and T2 are.

Since the optimistic lock completely controls transaction isolation to the database, transactions 1 and 2 cross, and transaction 1 commits
Succeeded and changed the col_version to 1, whereas transaction 2 was not able to find the col_version 0 data when it was submitted, so
Thrown an exception.

Comparison of Hibernate query methods
hibernate mainly has three kinds of query methods:

1.HQL (Hibernate Query Language)

Similar to SQL, it supports features such as paging, connectivity, grouping, aggregate functions, and subqueries,
But hql are object-oriented, not tables that are oriented to relational databases. Positive query statement
is oriented to the domain object, so using HQL can gain cross-platform benefits, Hibernate
will automatically help us translate different SQL statements from different databases. This is in need of support
A variety of database or database migration applications are very convenient.

But at the same time, because SQL statements are generated automatically by hibernate, this does not
Facilitate the efficiency of SQL statements optimization and debugging, when the volume of data is very large, there may be efficiency problems,
Out of the problem is not easy to troubleshoot and solve.

2.QBC/QBE (Query by Criteria/example)

QBC/QBE is the execution of queries by assembling query conditions or template objects. This is in need
It is more convenient to flexibly support many query conditions in the application of free combination. The same problem
Because the query statement is free to assemble, the code that creates a statement can be very long and
Contains many branching conditions that are not easy to optimize and debug.

3.SQL

Hibernate also supports queries that execute SQL directly. This way sacrificed the hibernate cross
The benefits of a database by manually writing the underlying SQL statements for optimal execution efficiency,
Compared with the first two methods, optimization and debugging are convenient.

Let's look at a simple set of examples.

Package com.cdai.orm.hibernate.query; 
Import Java.util.Arrays; 
 
Import java.util.List; 
Import Org.hibernate.Criteria; 
Import Org.hibernate.Query; 
Import org.hibernate.Session; 
Import Org.hibernate.SessionFactory; 
Import org.hibernate.cfg.AnnotationConfiguration; 
Import org.hibernate.criterion.Criterion; 
Import Org.hibernate.criterion.Example; 
 
Import org.hibernate.criterion.Expression; 
 
Import Com.cdai.orm.hibernate.annotation.Account; public class Basicquery {public static void main (string[] args) {sessionfactory sessionfactory = new Annotat 
                      Ionconfiguration ().        
                      AddFile ("Hibernate/hibernate.cfg.xml"). 
                      Configure (). 
                      Addpackage ("Com.cdai.orm.hibernate.annotation"). 
                      Addannotatedclass (Account.class). 
 
    Buildsessionfactory (); 
 
    Session session = Sessionfactory.opensession (); 1.HQL query query = Session.createquery ("from ACCOunt as a where a.id=:id "); 
    Query.setlong ("id", 1); 
    List result = Query.list (); 
    for (Object Row:result) {System.out.println (row); 
    }//2.QBC the criteria criteria = Session.createcriteria (Account.class); 
    Criteria.add (EXPRESSION.EQ ("id", New Long (2)); 
    result = Criteria.list (); 
    for (Object Row:result) {System.out.println (row); 
    //3.QBE Account example= new account (); 
    Example.setbalance (100); 
            result = Session.createcriteria (Account.class). 
            Add (Example.create (Example)). 
    List (); 
    for (Object Row:result) {System.out.println (row);  }//4.SQL query = Session.createsqlquery ("SELECT Top *"-Tb_account ORDER BY col_id Desc 
    "); 
    result = Query.list (); 
  for (Object Row:result) {System.out.println (arrays.tostring (object[) row)); 
  } session.close (); 
 } 
 
}
Hibernate:select account0_.col_id as col1_0_, account0_.col_balance as col2_0_ from Tb_account account0_ where account0_. Col_id=?
account [Id=1, balance=100]
hibernate:select this_.col_id as col1_0_0_, this_.col_balance as col2_0_0_ from Tb_accou NT This_ where this_.col_id=?
account [id=2, balance=100]
hibernate:select this_.col_id as col1_0_0_, this_.col_balance as col2_0_0_ from Tb_accou NT This_ where (this_.col_balance=?)
account [Id=1, balance=100] account
[id=2, balance=100] hibernate:select the top of Tb_account order by
col_id Desc
[2]
[1, 100]

From the log you can clearly see the hibernate for the generated SQL statement control, the specific choice
Which query method depends on the specific application.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.