Hibernate Cache Mechanism

Hibernate Cache Mechanism

I. Role

Hibernate is a persistent layer framework that frequently accesses physical databases to improve application performance by reducing the frequency of access to physical data sources.The data in the cache is a copy of the data from the physical data source, the application reads and writes data from the cache at run time, and the cache and the data from the physical data source are synchronized at a specific time or event

2. Classification

Transaction Scope Hibernate Level 1 Cache
    Hibernate Level 1 Cache, also known as Session Cache, is built-in, meaning that session caches must be used whenever you use hibernate.Since the life cycle of a Session object usually corresponds to a database transaction or an application transaction, its cache is transaction-wide.In the first level cache, each instance of a persisted class has a unique primary key. 
Scope Hibernate Level 2 Cache
     Hibernate secondary cache is also known as the "SessionFactory Cache". Because the life cycle of the SessionFactory object corresponds to the entire process of the application, Hibernate secondary cache is a process-wide or cluster-wide cache, which can cause concurrency problems. Therefore, an appropriate concurrent access policy is required, which provides transaction isolation level for cached data..The second level cache is optional and a configurable plug-in that SessionFactory does not enable by default

Cluster scope (multiple SessionFactory) 
   In a cluster environment, the cache is shared by processes of one or more machines, the data in the cache is copied to each process node in the cluster environment, and the data in the cache is always in the form of loose data of objects through remote communication between processes.

3. What kind of data is suitable for storage in the second level cache

Data that is rarely modified.
Less important data, allowing occasional concurrent data. 
Data that will not be accessed concurrently. 
Constant data. 
Data that will not be modified by third parties

4. Data not suitable for second level caching

1 Frequently modified data
 2 Concurrent access to data, such as financial data, and concurrency should never be allowed.
3 Data shared with other applications

5. How does Hibernate lookup apply caching?

When Hibernate accesses data objects based on the ID, it first checks from the Session level cache; if not, if a second level cache is configured, it checks from the second level cache; if not, it queries the database and places the results in the cache according to the ID to delete, update, and increase the data, while updating the cache

6. Hibernate Management Cache Instance

Whenever we manage the Hibernate cache, when you pass an object to the save(), update(), or saveOrUpdate() methods, or when you get an object using the load(), get(), list(), iterate(), or scroll() methods, the object is added to Session's internal cache.When the flush() method is then called, the state of the object is synchronized with the database.If you do not want this synchronization to occur, or if you are working with a large number of objects and need to manage memory effectively, you can call the evict() method to remove these objects and their collections from the first level cache

7. Method of not using secondary cache

Among Hibernate's various query methods, there are several ways to read and write directly from a database without using a cache:

  • get()
  • find()
  • list()

Both of the latter are find() methods when using HibernateTemplate.However, when using these methods when the query cache is turned on, the results of the query are also stored in the cache, which can cause time consumption, but effectively avoid N+1 problems when using the cache.

4.2. Method of using secondary cache

Hibernate uses secondary caching in the following ways

  • load()
  • iterate()

Secondary Cache Operation Steps

2.2.1, Level 2 Cache Configuration

  1. Import jar ehcache

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
    <dependency>
       <groupId>org.hibernate</groupId>
       <artifactId>hibernate-ehcache</artifactId>
       <version>5.2.10.Final</version>
    </dependency>
    <dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.3</version>
    </dependency>
  2. Turn on secondary caching in hibernate.cfg.xml

    <propertyname="hibernate.cache.use_second_level_cache">true</property>        
    <!--Query Cache As true-->
    <property name="hibernate.cache.use_query_cache">true</property>
  3. Configure secondary caching technology providers

    <property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>
  4. Location of secondary cache profile

    ehcache.xml

  5. Configure the concurrency policy for cached data objects

    Use on classes
    @Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
    Register in cfg
     <class-cache usage="read-write" class="package name class name"/>  
    <collection-cache usage="read-write" collection="package name.class name.collection property"/>  
  6. Add secondary cache profile to resource folder

       <!--
          //The default cache configuration, if the class is not specifically set, uses the cache properties configured here.
    
           maxElementsInMemory  - Set the maximum object allowed to be saved in the cache ( pojo)Number
           eternal           - Sets whether the object is permanently saved if true,Then the data in the cache is never destroyed and kept.
           timeToIdleSeconds - Set idle destroy time.
                          //Only when Maximal is false will it work.Indicates that if the time between now and last access exceeds this value, the cache data will be destroyed
           timeToLiveSeconds - Set the activity destruction time.Indicates that if the cache creation time exceeds this value from now on, the cache will be destroyed automatically
           overflowToDisk    - Sets whether the excess is saved to the hard disk when the number of saves is exceeded.
           -->
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
       xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">  
       <diskStore path="java.io.tmpdir"/> Configure Secondary Cache Hard Drive Temporary Directory Location   
            <defaultCache    
               maxElementsInMemory="10000" // Maximum number of objects in memory, over which data will be cached to the hard disk   
               eternal="false"  
               timeToIdleSeconds="120" // Is Cache Permanent false Not permanent  
               timeToLiveSeconds="120" // Time to live, whether or not the object is used, time to recycle  
               overflowToDisk="true" // Is it possible to cache to a hard drive  
               maxElementsOnDisk="10000000" // Maximum number of objects cached on hard disk   
               // WhenjvmWhether to persist the object at the end true false Default isfalse  
               diskExpiryThreadIntervalSeconds="120"  // Specify polling times for listening threads dedicated to cleaning up expired objects   
               memoryStoreEvictionPolicy="LRU"   
               />  
      <!-- Specify area cache: adopt name Appoint, name Corresponding to Hibernate The area name in-->  
     <cache name="cn.javass.h3test.model.UserModel"  
                   eternal="false"  
                   maxElementsInMemory="100"  
                   timeToIdleSeconds="1200"  
                   timeToLiveSeconds="1200"  
                   overflowToDisk="false">  
     </cache>  
    </ehcache>  
    1. Test Code

    2. Entity Class

      @Entity
      //Read and Write Cache Permissions
      //@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
      //Read-only Cache Permissions
      @Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
      public class User {
        @Id
        @Column(name="id")
        @GenericGenerator
        private Integer userID;
        private String name ;
        private Integer age;
        @Column(name="birth")
        @Temporal(TemporalType.DATE)
        private Date birthday;
      
      
        public User(){}
      
        public User(Integer userID, String name, Integer age, Date birthday) {
            super();
            this.userID = userID;
            this.name = name;
            this.age = age;
            this.birthday = birthday;
        }
      
        public Integer getUserID() {
            return userID;
        }
        public void setUserID(Integer userID) {
            this.userID = userID;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
        @Override
        public String toString() {
            return "User [userID=" + userID + ", name=" + name + ", age=" + age
                    + ", birthday=" + birthday + "]";
        }
      
      }
    3. Secondary cache ecache:

      <?xml version="1.0" encoding="UTF-8"?>
      <!-- 
          maxEntriesLocalHeap:  Cached in memory element Maximum number. 
          maxEntriesLocalDisk:  Cached on disk element Maximum number, default value is 0, indicating no limit. 
          eternal:  Set Cached elements Will it never expire?If is true,The cached data is always valid.
                      //If it's false, it's also based on timeToIdleSeconds, timeToLiveSeconds. 
          <persistence strategy="localTempSwap"/>  Store data on hard disk when memory is full
          timeToIdleSeconds="10"  Cache idle time default 0 persists
          timeToLiveSeconds="15"  Maximum cache lifetime    Default value 0 is always alive
          diskExpiryThreadIntervalSeconds:Valid time for disk data
          memoryStoreEvictionPolicy="LFU"
              FIFO ,first in first out (FIFO). 
              LFU , Less Frequently Used (Minimum use).This means that it has been used least.The cached element has one hit Properties, hit 
                   //The minimum value will be flushed out of the cache.
              LRU ,Least Recently Used(Minimum recently used). (ehcache Default value).Cached elements have a timestamp, and when the cache is full,
                    //When you need to make room to cache new elements, the elements with the farthest timestamp from the current time in the existing cached elements will be flushed out of the cache.
      -->
      
      <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="ehcache.xsd">
      
        <!-- <diskStore path="java.io.tmpdir"/> -->
        <diskStore path="E:\\cache4"/>
        <defaultCache
                maxEntriesLocalHeap="2"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                diskSpoolBufferSizeMB="30"
                maxEntriesLocalDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
      </ehcache>
    4. hibernate profile:

      <?xml version="1.0" encoding="utf-8"?>
      <!-- 
          Document Constraints: DTD  Document Type Definition
                         : Tags, Attributes, Hierarchies, Order
       -->
      <!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
      <hibernate-configuration>
          <session-factory>
              <!-- Database connection correlation -->
              <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:xe</property>
              <property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
              <property name="hibernate.connection.username">hr</property>
              <property name="hibernate.connection.password">hr</property>
              <!-- maximum connection -->
              <property name="hibernate.c3p0.max_size">3</property>
              <!-- Lowest Connections -->
              <property name="hibernate.c3p0.min_size">1</property>
              <!-- Get link wait timeout: milliseconds-->
              <property name="checkoutTimeout">3000</property>
              <!-- Indicates the type of connection pool -->
              <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
              <!-- hibernate Self Configuration Information 
                          Dialect: Indicate the type of database for ease of use hibernate Adapt to different databases.
              -->
              <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
              <!-- Console Print Out sql Sentence -->
              <property name="hibernate.show_sql">true</property>
              <!-- Format sql Sentence -->
              <property name="hibernate.format_sql">true</property>
              <!-- Disable javaEE6 Of bean-validator -->
              <property name="javax.persistence.validation.mode">none</property>
              <!-- getCurrentSession -->
              <property name="hibernate.current_session_context_class">thread</property>
              <!-- Turn on secondary cache -->
              <property name="hibernate.cache.use_second_level_cache">true</property>
              <!-- Second level cache category: EhCache,OSCache,JbossCache -->
              <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
              <!-- Turn on query cache -->
              <property name="hibernate.cache.use_query_cache">true</property>
              <!-- Registration of Mapping Information -->
              <mapping class="User"></mapping>
          </session-factory>
      </hibernate-configuration>
    5. Level 1 Cache Test

      public class TestCache {
      
          /**
           * Level 1 Cache Test: Cannot Cross Transactions
           */
          @Test
          public void testFirstLevelCache(){
              Session session=HibernateUtil.getCurrentSession();
              Transaction tx=session.beginTransaction();
              //1. Check the cache, no data is available, turn to the database, query the data, enter the first level cache
              User user=(User)session.get(User.class,1);
              System.out.println(user);
              user.setAge(41);
              //2. Initiate the same query again, check the cache, and if there is data available, you are not querying the database.
              User user2=(User)session.get(User.class,1);
              System.out.println(user2);
              tx.commit();
      
              /*Session session2=HibernateUtil.openSession();
              Transaction tx2=session2.beginTransaction();
              User user3=(User)session2.get(User.class,109);
              System.out.println(user3);
              tx2.commit();
              session2.close();*/
          }
          /**
           * Level 1 Cache Test: HQL statement execution query cannot check cache
           */
          @Test
          public void testFirstLevelCache2(){
              Session session=HibernateUtil.getCurrentSession();
              Transaction tx=session.beginTransaction();
              //1. Check the cache, no data is available, turn to the database, query the data, enter the first level cache
              User user=(User)session.get(User.class,1);
              //2.list and uniqueResult cannot check the cache and go directly to the database.
              String hql="from User u where u.name='zhangjifeng'";
              Query query=session.createQuery(hql);
              User user2=(User)query.uniqueResult();
              System.out.println(user);
              System.out.println(user2);
              tx.commit();
          }
          /**
           * Level 1 cache test: iterate():
           */
          @Test
          public void testFirstLevelCache3(){
              Session session=HibernateUtil.getCurrentSession();
              Transaction tx=session.beginTransaction();
              //1.HQL queries multiple pieces of data and the data enters the first level cache
              String hql="from User u where u.name like ?";
              Query query=session.createQuery(hql);
              query.setString(0,"ji%");
              query.list();
      
              String hql2="from User u where u.name like ?";
              Query query2=session.createQuery(hql);
              query2.setString(0,"ji%");
              //Iterator Storage ID
              //Only the ID is queried, and the cache is checked by the ID.
              Iterator it=query2.iterate();
              while(it.hasNext()){
                  User user=(User)it.next();
                  System.out.println(user);
              }
              tx.commit();
          }
    6. Level 2 Cache Test

      /**
           * Level 2 Cache Test
           */
          @Test
          public void testSecondLevelCache(){
              Session session=HibernateUtil.openSession();
              Transaction tx=session.beginTransaction();
              User user=(User)session.get(User.class,1);
              User user3=(User)session.get(User.class,2);
              System.out.println(user);
              tx.commit();
              session.close();
      
              Session session2=HibernateUtil.openSession();
              Transaction tx2=session2.beginTransaction();
      
              User user2=(User)session2.get(User.class,1);
              user2.setName("second222");
              System.out.println(user2);
              tx2.commit();
              session2.close();
          }
          /**
           * Query Cache Test
           */
          @Test
          public void testQueryCache(){
              Session session=HibernateUtil.openSession();
              Transaction tx=session.beginTransaction();
              String hql="select u.name,u.age from User u where u.age>=?";
              Query query=session.createQuery(hql);
              query.setInteger(0,20);
              //Use query cache for this query
              query.setCacheable(true);
              //Check the query cache, if no cache is available, then go to the database and cache the results in the query cache: {HQL: Results (Fields)}
              query.list();
              tx.commit();
               session.close();
      
      //         Session session3=HibernateUtil.openSession();
      //        Transaction tx3=session3.beginTransaction();
      //         session3.save(new User());
      //        tx3.commit();
      //        session3.close();
      
              Session session2=HibernateUtil.openSession();
              Transaction tx2=session2.beginTransaction();
              String hql2="select u.name,u.age from User u where u.age>=?";
              Query query2=session2.createQuery(hql2);
              query2.setInteger(0,20);
              //Use query cache for this query
              query2.setCacheable(true);
              //Check query cache, find available cached data, use directly, not query database
              query2.list();
              tx2.commit();
              session2.close();
          }
          /**
           * Query Cache + Secondary Cache
           */
          @Test
          public void testQueryCache2(){
              Session session=HibernateUtil.openSession();
              Transaction tx=session.beginTransaction();
              String hql="from User u where u.age>=?";
              Query query=session.createQuery(hql);
              query.setInteger(0,20);
              //Use query cache for this query
              query.setCacheable(true);
              //Check the query cache, if no data is available, then go to the database and get an entity User to put {HQL:User ID} in the query cache
              // Save {User's ID:User} in the secondary cache
              query.list();
              tx.commit();
               session.close();
               Session session2=HibernateUtil.openSession();
              Transaction tx2=session2.beginTransaction();
              String hql2="from User u where u.age>=?";
              Query query2=session2.createQuery(hql2);
              query2.setInteger(0,20);
              //Use query cache for this query
              query2.setCacheable(true);
              //Check the query cache to get the cached data: User's ID, check the secondary cache through UserID, if there is data, use it directly, otherwise
              //Initiate queries on each ID
              query2.list();
              tx2.commit();
              session2.close();

2.2.2, Concurrent Access Policy

attribute Explain Remarks
transactional Providing Repeatable Read transaction isolation level is only applicable in managed environments. Frequently read, rarely modified data prevents dirty and non-repeatable read concurrency problems. Cache supports transactions and can roll back in case of exceptions Not recommended
read-write Providing a Read Committed transaction isolation level for use in a non-clustered environment applies to data that is frequently read and rarely modified to prevent dirty reads from locking data in the cache when updating the cache Not recommended
nonstrict-read-write Applicability is rarely modified, occasionally allowing dirty read data (rarely when two transactions modify the data at the same time) does not guarantee consistency between the cache and the data in the database Setting a very short expiration time for the cached data to minimize dirty read and unlock the data in the cache Not recommended
read-only Applicable to data that will never be modified, such as reference data In this mode, if data is updated, there will be a low level of exception transaction isolation and high concurrency performance that works well in a clustered environment Common

Optimize mechanism

1. Use two-way one-to-many Association instead of one-way one-to-many
 2. Flexible use of one-way one-to-many associations
 3. Use many-to-one instead of one-to-one
 4. Configure object cache without using collection cache
 5. Use Set for many-to-many collections
 6. Inheritance classes use explicit polymorphism
 7. Fewer table fields, not more table associations, supported by secondary cache

Scrambling Problem

Insert Chinese scrambling into mysql
    1. First you need to modify the configuration file my.ini of the MySQL database, which is placed in the root directory of mysql.Look for the default-character-set property under this file and change its value to utf8 (note: not utf-8, but also case). You need to change the value of all properties of the default-character-set property to utf8 here.Example:
        default-character-set = utf8
        Tip: There are two default-character-set attributes, one under [mysql] and the other under [mysqld].
    2. When you create a hibernate database at the same time, you need to show that utf8 is the encoding method for setting up the database.Example: create database daycode default charset=utf8;
    3. Do these two steps or not, you need to modify hibernate's configuration file hibernate.cfg.xml.

Configure the hibernate.connection.url property in the configuration file.Example:

Transactions and Concurrency in Hibernate

Important concepts

brief introduction
    A transaction is a logical set of operations that make up each unit of execution of a transaction, either all succeeding or all failing
 Transaction characteristics
    Atomicity--Transactions are inseparable.
    Consistency -- Data integrity is consistent before and after a transaction is executed.
    Isolation--A transaction should not be interfered with by other transactions while it is being executed.
    Persistence -- Once a transaction is committed, the data persists permanently in the database
 Without regard to isolation: raises some reading issues
    Dirty Read -- One transaction read uncommitted data from another transaction (the most important issue in database isolation)
    Non-repeatable read--One transaction read update data already committed by another transaction, resulting in inconsistent results for multiple queries.
    Dummy Read--One transaction read insert data already committed by another transaction, resulting in inconsistent query structure multiple times
 Solve the above reading problems by setting the isolation level of the database
    Unsubmitted Read: All of the above reading problems may occur.
    Submitted Reads: Avoid dirty reads, but do not repeat them. Dummy reads can occur.
    Repeatable reading: Avoid dirty reading, not repeatable reading. However, dummy reading is possible.
    Serialization: The above read scenarios can be avoided
 If you want to set isolation levels within the framework of Hibernate, you need to configure them with tags in the configuration file of hibernate.cfg.xml
    hibernate.connection.isolation = 4 to configure
    Value
        1—Read uncommitted isolation
        2—Read committed isolation
        4—Repeatable read isolation
        8—Serializable isolation

Problem with missing updates
problem
If isolation is not considered, problems with writing data can also arise, a type of problem called missing updates.
For example, if two transactions modify a record at the same time, the problem of losing updates is raised
A transaction and B transaction get one data at the same time and make modifications
If transaction A is modified and the transaction is committed
When the B-transaction is modified, whether committed or rolled back, it will affect the data if not processed
There are two solutions
It uses a lock mechanism provided by the database and, if so, adds a for update clause after the SQL L statement

    When transaction A operates on this record, it locks it. Other transactions cannot operate on this record.

    Only when the A transaction commits and the lock is released can other transactions operate on that record
 Optimistic Lock
        Instead of a database lock mechanism, a version number mechanism is used to solve the problem.Add a field version=0 to the table structure with a default value of 0
        When transaction A completes this record and commits the transaction, the version number is checked before the transaction can be committed if the value of the version number is the same.version=1 will also be updated.
        When the B transaction completes the operation of this record, the version number is checked before the transaction is committed, and the program will encounter errors if different versions are found.
Pessimistic Lock
        It uses a lock mechanism provided by the database and, if so, adds a for update clause after the SQL L statement
        When transaction A operates on this record, it locks it. Other transactions cannot operate on this record.
        Only when the A transaction commits and the lock is released can other transactions operate on that record
    Solve missing updates using the Hibernate framework
 Pessimistic locks (inefficient, uncommon)
Use session.get(Customer.class, 1,LockMode.UPGRADE); method
 Optimistic Lock
            Add an attribute to the corresponding JavaBean with any name.For example: private Integer version; provides get and set methods
            Add the @Version annotation above the properties

Keywords: Hibernate Session Database Ehcache

Added by dreamlove on Tue, 11 Jun 2019 19:26:30 +0300