1. Transaction Overview
A transaction is a set of data operations performed as a single logical unit of work. These operations must either be all successful or all fail to ensure data consistency and integrity. Transactions have the ACID attribute:
Atomicity: The smallest in nature. The transaction content is either done or not done.
Consistency: The status is consistent after the transaction ends. The system status is consistent with the logic rules of the business.
Isolation: locking mechanism. Multiple transactions access the same data separately.
Durability: Once the transaction ends, the transaction results are permanently saved.
Database Transaction Management
The ACID feature of database transactions is implemented by the relational database management system (RDBMS. The database management system uses logs to ensure the atomicity, consistency, and durability of transactions.
The database management system uses a locking mechanism to isolate transactions.
2. Transaction Management in Hibernate applications
Hibernate implements lightweight object encapsulation for JDBC. Hibernate itself does not have the transaction processing function during design. Hibernate transactions are usually used to encapsulate the underlying JDBCTransaction or JTATransaction, the Transaction and Session shells are put on the outside. In fact, the underlying layer is to delegate the underlying JDBC or JTA to implement the Transaction scheduling function.
1) Use JDBC transactions in Hibernate
To use JDBC transactions in Hibernate, you can specify the hibernate transaction as JDBCTransaction in Hibernate. cfg. xml. NOTE: If not configured, JDBC transactions are used by default.
<Property name = "hibernate. transaction. factory_class">
Org. hibernate. transaction. JDBCTransactionFactory
</Property>
Transaction tx = null;
Try {
Tx = session. beginTransaction ();
// Perform the persistence operation
Tx. commit ();
} Catch (Exception e ){
If (tx! = Null) tx. rollback ();
Throw e;
} Finally {
Session. close ();
}
2) use JTA transactions in Hibernate
JTA (Java Transaction API) can be simply understood as a cross-Database Transaction, implemented by the application JTA container. To use JTATransaction, You need to configure hibernate. transaction. factory_class parameter. The default value is org. hibernate. transaction. JDBCTransactionFactory, you need to change this parameter to org when using JTATransaction. hibernate. transaction. JTATransactionFactory and configure jta. userTransaction parameter JNDI name (Hibernate uses this value to find javax in the Context of JNDI when starting JTATransaction. transaction. userTransaction ).
Javax. transaction. usertranshyperlink tx = context. lookup ("jndiName ");
Try {
Tx. begin ();
// Session operations for multiple databases;
// Session1 ....
// Session2 ....
Tx. commit ();
} Catch (Exception e ){
Tx. rollback (); throw e;
}
3. Concurrent Access Control
Database Transaction concurrency issues:
Lost update: I also changed it when you changed it. The modified content overwrites the modified or changed content and is not saved.
Dirty read: read dirty data. It was modified only after you read it. The content you read is invalid or rolled back. Half of the modification, you read it and finally rolled back.
Non-repeated read: the content of the two queries is different; the content of the second query is modified.
Phantom read: the content of the two queries is different. The content of the second query is different from that of the first query. The possible cause is that someone has changed or deleted the content.
Transaction isolation level: in order to solve the problems caused by multiple transaction concurrency, you can make a reasonable balance between transaction isolation and concurrency as needed. The database system provides four transaction isolation levels.
Read Uncommitted: the lowest isolation level
Read committed: This
Repeatable Read)
Serializable: the highest isolation level, so no concurrency problems exist.
The database system uses different lock types to achieve the isolation level of the four. The specific implementation process is transparent to users. Users only need to select an appropriate isolation level.
The higher the isolation level, the more data integrity and consistency can be guaranteed, but the greater the impact on concurrency performance. For most applications, the isolation level is Read Committed, which can avoid reading data and has good concurrency performance.
The configuration file of Hibernate can display the setting isolation level. Each isolation level is a positive integer.
Read Uncommitted: 1
Read Committed: 2
Repeatable Read: 4
Serializable: 8
<Property name = "hibernate. connection. isolation"> 2 </property>
4. Optimistic Concurrency Control
When the database system adopts the Read Committed isolation level, it still cannot prevent repeated and phantom Read. In scenarios where such problems may occur, optimistic locks and pessimistic locks can be used in applications.
Optimistic locks assume that no other transactions are simultaneously accessed when the current transaction operates on the database resources, so no database locks are performed. Hibernate uses version and timestamp to maintain correct data.
1) Use the version number for Version Control
Define a version attribute in the persistence class. The data type can only be integer type.
Add the <version> label to the ing file. Note that it must be placed behind the <id> element.
5. pessimistic Concurrency Control
The pessimistic lock is assumed that when the current transaction operates on the data resource, other transactions must simultaneously access the data resource, so the resource is locked first.
The general implementation method is implemented by the database and the exclusive lock is used to lock the resource. Use get () and load () to display the specified lock mode: LockMode. UPGRADE
Session. get (Student. class, 1, LockMode. UPGRADE );
6. Configure the C3p0 connection pool
<! -- Enable the c3p0 connection pool to set the supplier provided by the connection pool -->
<Property name = "connection. provider_class"> org. hibernate. connection. C3P0ConnectionProvider </property>
<! -- Maximum number of connections -->
<Property name = "c3p0. max_size"> 20 </property>
<! -- Minimum connections -->
<Property name = "c3p0. min_size"> 5 </property>
<! -- Number of connections requested each time -->
<Property name = "c3p0. acquire_increment"> 5 </property>
<! -- Set the expiration time, in seconds. If a connection in the idle state in the connection pool exceeds this time, the connection will be deleted from the connection pool. -->
<Property name = "c3p0. timeout"> 120 </property>
<! -- Check idle connections in the connection pool every 3000 seconds -->
<Property name = "c3p0. idle_test_period"> 3000 </property>
7. Unsuitable Hibernate scenarios
Not suitable for OLAP (On-Line Analytical Processing Online Analytical processing), mainly for querying and analyzing data, and OLTP (on-line transaction Processing online transaction processing ).
For old systems with unreasonable relationship model design, the advantage of hibernate cannot be used. Systems with massive data volumes and demanding performance requirements are also difficult for hibernate to meet the requirements, and the efficiency of batch data operations is not high.
1). integrate Struts with Hibernate
The Hibernate framework is mainly used in the persistence layer to complete the CRUD operations of the object class.
2). Implementation of Hibenate in generic DAO mode
3). OpenSessionInView Mode
8. Case Analysis
Configure the following data in Hibernate. cfg. xml:
<Property name = "hibernate. connection. isolation"> 2 </property>
Configuration in the ing file:
<Version name = "version"> </version>
@ Test
// Test the optimistic lock. add data. No manual addition is required if the version number is automatically generated.
Publicvoid testAdd (){
Session session = HibernateUtil. getSession ();
Session. beginTransaction ();
User u = new User ();
U. setName ("Li Si ");
U. setBirthday (new Date ());
Session. save (u );
Session. getTransaction (). commit ();
HibernateUtil. close ();
}
@ Test
// Test the optimistic lock. If you change the data, the version number is automatically increased by 1.
Publicvoid testupdate (){
Session session = HibernateUtil. getSession ();
Session. beginTransaction ();
User user = (User) session. load (User. class, 4 );
User. setName ("Wang Wu ");
Session. getTransaction (). commit ();
HibernateUtil. close ();
}
@ Test
// Simulate transactions in hibernate. If the test fails, the following error occurs: transaction not successfully started. However, the experiment shows that the second modified value is saved to the database.
Publicvoid testtransaction (){
Session session1 = HibernateUtil. getSession ();
Session1.beginTransaction ();
User user1 = (User) session1.load (User. class, 4 );
Session session2 = HibernateUtil. getSession ();
Session2.beginTransaction ();
User user2 = (User) session1.load (User. class, 4 );
User1.setName ("aa ");
User2.setName ("bb ");
Session1.getTransaction (). commit ();
Session2.getTransaction (). commit ();
HibernateUtil. close ();
}
@ Test
// Test the pessimistic lock. When testing in the same resource class, remember to comment out the optimistic lock settings, especially the version labels in the ing file. This can be simply modified, change to property and then perform the experiment.
// Result: the select statement is different from the normal one. The where condition has one more sentence: where user0 _. id =? For update
Publicvoid find (){
Session session = HibernateUtil. getSession ();
Session. beginTransaction ();
User user = (User) session. load (User. class, 4, LockMode. UPGRADE );
System. out. println (user. getName () + "----" + user. getBirthday ());
Session. getTransaction (). commit ();
HibernateUtil. close ();
}