Hibernate Level 2 Cache

Posted by Duke555 on Fri, 09 Aug 2019 11:18:43 +0200

Why do you need caching

Stretch program performance
   
   Relational databases: databases with relationships between data and data mysql/Oracle, sqlserver
   Non-relational databases: There is no relationship between data and data, key-value
		1. File-based database: ehcache
		2. Memory-based databases: redis, memcache
		3. Document-based database: mongodb

What kind of data needs to be cached

Data dictionaries that are rarely modified or not altered at all
 Business scenarios such as: time-consuming statistical analysis sql, telephone billing query sql, etc.

What is ehcache

Ehcache is the most popular pure Java open source caching framework with simple configuration, clear structure and powerful functions.
   
Note 1: This chapter introduces version 2.X, version 3.x and version 2.x API s are quite different.

Characteristics of ehcache

1 fast enough
 Ehcache has been released for a long time. After years of hard work and numerous performance tests, Ehcache was eventually designed for large, high concurrency systems.
2 is simple enough
 The developer's interface is very simple and straightforward. It only takes a few precious minutes for you to build and run Ehcache. In fact, many developers do not know that they are using Ehcache, which is widely used in other open source projects.
3 is small enough
 For this feature, the government has given a cute name, small foot print. Normally, the release version of Ehcache will not reach 2M and only 668KB in V 2.2.3.
4 is light enough
 Core program only depends on slf4j package, no one!
5 Good Expansion
 Ehcache provides memory and hard disk storage for large data. Recent versions allow multiple instances, high flexibility of objects, LRU, LFU, FIFO elimination algorithms, and basic attributes support hot configuration and many plug-ins.
6 monitor
 Cache Manager Listener and Cache EvenListener are good for doing some statistical or data consistency broadcasting.
7 Distributed Cache
 Beginning with Ehcache 1.2, it supports high-performance distributed caching with flexibility and extensibility

Use of ehcache

1 Import dependencies
      <dependency>
      	<groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>2.10.0</version>
      </dependency>
2 Core Interface
      Cache Manager: Cache Manager
      Cache: Cache object. Cache manager can place several caches to store the essence of data. All caches implement Ehcache interface.
      Element: The constituent unit of a single cache data
3 src:ehcache.xml

case

Tool class EhcacheUtil

package com.tzx.six.util;

import net.sf.ehcache.Cache;

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import java.io.InputStream;

public class EhcacheUtil {

    private static CacheManager cacheManager;

    static {
        try {
            InputStream is = EhcacheUtil.class.getResourceAsStream("/ehcache.xml");
            cacheManager = CacheManager.create(is);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private EhcacheUtil() {
    }

    public static void put(String cacheName, Object key, Object value) {
        Cache cache = cacheManager.getCache(cacheName);
        if (null == cache) {
            //Add a Cache named cacheName with the default configuration
            cacheManager.addCache(cacheName);
            cache = cacheManager.getCache(cacheName);
        }
        cache.put(new Element(key, value));
    }


    public static Object get(String cacheName, Object key) {
        Cache cache = cacheManager.getCache(cacheName);
        Element element = cache.get(key);
        return null == element ? null : element.getValue();
    }

    public static void remove(String cacheName, Object key) {
        Cache cache = cacheManager.getCache(cacheName);
        cache.remove(key);
    }
}

Guided pom dependence

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.zking</groupId>
  <artifactId>hiberbate</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>hiberbate Maven Webapp</name>
  <url>http://maven.apache.org</url>
  
  <properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>

		<junit.version>4.12</junit.version>
		<servlet.version>4.0.0</servlet.version>
		<hibernate.version>5.2.12.Final</hibernate.version>
		<mysql.driver.version>5.1.46</mysql.driver.version>

		<ehcache.version>2.10.0</ehcache.version>
		<slf4j-api.version>1.7.7</slf4j-api.version>
		<log4j-api.version>2.9.1</log4j-api.version>
	</properties>

  
  <dependencies>
    <dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.version}</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.driver.version}</version>
		</dependency>
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
			<version>${ehcache.version}</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<!-- slf4j Core package -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j-api.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${slf4j-api.version}</version>
			<scope>runtime</scope>
		</dependency>
		<!--For use with slf4j Keep Bridging -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
			<version>${log4j-api.version}</version>
		</dependency>
		<!--core log4j2jar package -->
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>${log4j-api.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>${log4j-api.version}</version>
		</dependency>
  </dependencies>
  <build>
    <finalName>hiberbate</finalName>
    <plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.7.0</version>
				<configuration>
					<source>${maven.compiler.source}</source>
					<target>${maven.compiler.target}</target>
					<encoding>${project.build.sourceEncoding}</encoding>
				</configuration>
			</plugin>
		</plugins>
  </build>
</project>

A Simple Caching Principle Using map Sets
EhcacheDemo1

package com.tzx.six.test;

import java.util.HashMap;
import java.util.Map;

/**
 * A Simple Caching Principle Using map Sets
 * @author Administrator
 *
 */
public class EhcacheDemo1 {
	static Map<String, Object> cache = new HashMap<String, Object>();
	static Object getValue(String key) {
		Object value = cache.get(key);
		System.out.println("Read data from memory");
		if(value == null) {
			System.out.println("Reading data from a database");
			cache.put(key, new String[] {"zs"});
			return cache.get(key);
		}
		return value;
	}
	
	public static void main(String[] args) {
		System.out.println(getValue("sname"));
		System.out.println(getValue("sname"));
	}
}


Demonstrate using caching to store data
log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>

<!-- status : Appoint log4j The level of the print log itself.ALL< Trace < DEBUG < INFO < WARN < ERROR 
	< FATAL < OFF.  monitorInterval : Used for specifying log4j Automatic reconfiguration of monitoring intervals in units of s,The minimum is 5. s. -->
<Configuration status="WARN" monitorInterval="30">
	<Properties>
		<!-- Configuration log file output directory ${sys:user.home} -->
		<Property name="LOG_HOME">/root/workspace/lucenedemo/logs</Property>
		<property name="ERROR_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/error</property>
		<property name="WARN_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/warn</property>
		<property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} - %msg%n</property>
	</Properties>

	<Appenders>
		<!--Configuration of this output console -->
		<Console name="Console" target="SYSTEM_OUT">
			<!-- Console output only level Information at and above levels(onMatch),Other direct rejections(onMismatch) -->
			<ThresholdFilter level="trace" onMatch="ACCEPT"
				onMismatch="DENY" />
			<!-- Format of output log -->
			<!-- %d{yyyy-MM-dd HH:mm:ss, SSS} : Log production time %p : Log output format %c : logger Name of 
				%m : Log content, that is logger.info("message") %n : Newline character %C : Java Class name %L : Number of rows where the log output is located %M 
				: The method name where the log output is located hostName : Local machine name hostAddress : local ip address -->
			<PatternLayout pattern="${PATTERN}" />
		</Console>

		<!--The file prints out all the information. This log Every time the program runs, it will be cleared automatically. append Attribute determination, which is also useful for temporary testing -->
		<!--append by TRUE Represents that the message is added to the specified file. false Represents that the message overwrites the specified file content, with the default value of true -->
		<File name="log" fileName="logs/test.log" append="false">
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</File>
		<!-- This will print out all of them. info Information at or below the level, each size exceeding size, Then this size Size logs are automatically saved by year-Folder created in January and compressed for archiving -->
		<RollingFile name="RollingFileInfo" fileName="${LOG_HOME}/info.log"
			filePattern="${LOG_HOME}/$${date:yyyy-MM}/info-%d{yyyy-MM-dd}-%i.log">
			<!--Console output only level Information at and above levels( onMatch),Other direct rejections( onMismatch) -->
			<ThresholdFilter level="info" onMatch="ACCEPT"
				onMismatch="DENY" />
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
			<Policies>
				<!-- Time-based rolling strategy, interval Property is used to specify how often to scroll, defaulting to 1 hour.  modulate=true To adjust the time: for example, it's 3 a.m. am,interval It's 4, so the first scroll is 4. am,Next came 8. am,12am...Not 7 am. -->
				<!-- The key point is that filePattern Later date format, and TimeBasedTriggeringPolicy Of interval, To which date format is accurate? interval To which unit -->
				<!-- log4j2 Diary files by genius : info-%d{yyyy-MM-dd}-%i.log -->
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
				<!-- SizeBasedTriggeringPolicy:Policies Subnodes, based on the scrolling strategy of the specified file size, size Property is used to define the size of each log file. -->
				<!-- <SizeBasedTriggeringPolicy size="2 kB" /> -->
			</Policies>
		</RollingFile>

		<RollingFile name="RollingFileWarn" fileName="${WARN_LOG_FILE_NAME}/warn.log"
			filePattern="${WARN_LOG_FILE_NAME}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
			<ThresholdFilter level="warn" onMatch="ACCEPT"
				onMismatch="DENY" />
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
			<Policies>
				<TimeBasedTriggeringPolicy />
				<SizeBasedTriggeringPolicy size="2 kB" />
			</Policies>
			<!-- DefaultRolloverStrategy Property is not set, the default is up to 7 files under the same folder, where 20 files are set. -->
			<DefaultRolloverStrategy max="20" />
		</RollingFile>

		<RollingFile name="RollingFileError" fileName="${ERROR_LOG_FILE_NAME}/error.log"
			filePattern="${ERROR_LOG_FILE_NAME}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd-HH-mm}-%i.log">
			<ThresholdFilter level="error" onMatch="ACCEPT"
				onMismatch="DENY" />
			<PatternLayout
				pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
			<Policies>
				<!-- log4j2 Minute-by-minute log file : warn-%d{yyyy-MM-dd-HH-mm}-%i.log -->
				<TimeBasedTriggeringPolicy interval="1"
					modulate="true" />
				<!-- <SizeBasedTriggeringPolicy size="10 MB" /> -->
			</Policies>
		</RollingFile>

	</Appenders>

	<!--Then define logger,Only defined logger And introduced appender,appender Only then will it take effect -->
	<Loggers>
		<!--Filtration spring and mybatis Some useless DEBUG information -->
		<logger name="org.springframework" level="INFO"></logger>
		<logger name="org.mybatis" level="INFO"></logger>

		<!-- Third Party Logging System -->
		<logger name="org.springframework" level="ERROR" />
		<logger name="org.hibernate" level="ERROR" />
		<logger name="org.apache.struts2" level="ERROR" />
		<logger name="com.opensymphony.xwork2" level="ERROR" />
		<logger name="org.jboss" level="ERROR" />


		<!-- Configure the root node of the log -->
		<root level="all">
			<appender-ref ref="Console" />
			<appender-ref ref="RollingFileInfo" />
			<appender-ref ref="RollingFileWarn" />
			<appender-ref ref="RollingFileError" />
		</root>

	</Loggers>

</Configuration>

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--Disk storage:Objects that are not used temporarily in the cache,Transfer to hard disk,Be similar to Windows Virtual memory of the system-->
    <!--path:Specify the path to store objects on the hard disk-->
    <!--java.io.tmpdir Is the default temporary file path. Specific file paths can be printed out as follows System.out.println(System.getProperty("java.io.tmpdir"));-->
    <diskStore path="D://xxx"/>


    <!--defaultCache: Default management policy-->
    <!--eternal: Cached elements Whether it will never expire. If true,The cached data is always valid if it is false So there's a basis for that. timeToIdleSeconds,timeToLiveSeconds judge-->
    <!--maxElementsInMemory: Cached in memory element Maximum number-->
    <!--overflowToDisk: If the data in memory exceeds the memory limit, do you want to cache it to disk?-->
    <!--diskPersistent: Is it persistent on disk? Refer to restart jvm After that, is the data valid? Default is false-->
    <!--timeToIdleSeconds: Object idle time(Unit: seconds),It refers to how long an object will fail without being accessed. Only right eternal by false Effective. The default value of 0 indicates that it is always accessible-->
    <!--timeToLiveSeconds: Object Survival Time(Unit: seconds),Refers to the time required for an object to be created to fail. Only right eternal by false Effective. The default value of 0 indicates that it is always accessible-->
    <!--memoryStoreEvictionPolicy: Three Clearing Strategies for Cache-->
    <!--FIFO: first in first out (FIFO)-->
    <!--LFU: Less Frequently Used (Minimum use).It means that it has been used at least for a long time. The cached element has one hit Attributes, hit The lowest value will be cleared out of the cache-->
    <!--LRU: Least Recently Used(Minimum Recent Use). (ehcache Default values).Cached elements have a timestamp. When the cache capacity is full and there is room for caching new elements, the elements with the farthest timestamp from the current time in the existing cached elements will be removed from the cache.-->
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="600" timeToLiveSeconds="900" memoryStoreEvictionPolicy="LRU"/>


    <!--name:  Cache The name must be unique(ehcache I'll take this one. cache put to HashMap in)-->
    <cache name="com.tzx.one.entity.User" eternal="false" maxElementsInMemory="100"
           overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
           timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU"/>
</ehcache>

EhcacheDemo2

package com.tzx.six.test;

import com.tzx.six.util.EhcacheUtil;


/**
 * Demonstrate using caching to store data
 * @author Administrator
 *
 */
public class EhcacheDemo2 {
	public static void main(String[] args) {
		System.out.println(System.getProperty("java.io.tmpdir"));
		EhcacheUtil.put("com.tzx.four.entity.Book", 11, "zhangsan");
		System.out.println(EhcacheUtil.get("com.tzx.four.entity.Book", 11));
	}
}

It can be adjusted in ehcache.xml

Demonstration Check Individual Users Use Caching

Be sure to add it to hibernate.cfg.xml

<!-- Open Level 2 Cache -->
	 *  <property name="hibernate.cache.use_second_level_cache">true</property>
      <!-- Open Query Cache -->
      <property name="hibernate.cache.use_query_cache">true</property>
      <!-- EhCache drive -->
      <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

EhcacheDemo3

package com.tzx.six.test;

import org.hibernate.Session;

import org.hibernate.Transaction;

import com.tzx.one.entity.User;
import com.tzx.six.dao.UserDao;
import com.tzx.two.uitl.SessionFactoryUtils;



/**
 * Demonstration Check Individual Users Use Caching
 * @author Administrator
 *
 */
public class EhcacheDemo3 {
	/**
	 * By default, sql statements form three times, where a secondary cache SessionFactory cache must be used to improve performance.
	 *  <!-- Open Level 2 Cache - >
	 *  <property name="hibernate.cache.use_second_level_cache">true</property>
      <!-- Open Query Cache - > ____________
      <property name="hibernate.cache.use_query_cache">true</property>
      <!-- EhCache Drive - >
      <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
      
      	Add labels to mapping files
      	<cache usage="read-write" region="com.javaxl.one.entity.User"/>
      	The region here refers to cacheName in Ehcache.xml
	 * @param args
	 */
	public static void main(String[] args) {
		UserDao userDao  = new UserDao();
		User u = new User();
		u.setId(7);
		User user = userDao.get(u);
		System.out.println(user);
		User user2 = userDao.get(u);
		System.out.println(user2);
		User user3 = userDao.get(u);
		System.out.println(user3);
		
	}
	
	/**
	 * In the same session, the sql statement is generated only once, and the first level cache is used here.
	 */
//	public static void main(String[] args) {
//		Session session = SessionFactoryUtils.openSession();
//		Transaction transaction = session.beginTransaction();
//		
//		User user = session.get(User.class, 7);
//		System.out.println(user);
//		User user2 = session.get(User.class, 7);
//		System.out.println(user2);
//		User user3 = session.get(User.class, 7);
//		System.out.println(user3);
//		
//		transaction.commit();
//		session.close();
//	}
}

To improve performance, we use a secondary cache SessionFactory cache

package com.tzx.two.uitl;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

/**
 * It's only used in learning hibernate projects, but it's useless when you get into spring learning. There will be ssh to replace it later.
 * Effect:
 * Used to check the accuracy of configuration files in hibernate
 * 			hiberbate.cfg.xml
 * 			*.hbm.xml
 * @author 
 *
 */
public class SessionFactoryUtils {
	private static SessionFactory sessionFactory;
	static {
		Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
		sessionFactory = cfg.buildSessionFactory();
	}
	
	public static Session openSession() {
//		Getting session sessions from local threads is definitely not available for the first time, so you need to re-create session factories
//		The second time you can reuse the session you created for the first time, saving performance
		Session session = sessionFactory.getCurrentSession();
		if(session == null) {
			session = sessionFactory.openSession();
		}
		return session;
	}
	
	public static void closeSession() {
		Session session = sessionFactory.getCurrentSession();
		if(session != null && session.isOpen()) {
			session.close();
		}
	}
	
	public static void main(String[] args) {
		Session session = SessionFactoryUtils.openSession();
		session.beginTransaction();
		System.out.println(session.isConnected());
		SessionFactoryUtils.closeSession();
		System.out.println(session.isConnected());
	}
}

Add a cache tag to the User's mapping file

<cache usage="read-write" region="com.tzx.one.entity.User"/>

hibernate secondary cache does not cache multiple data at the same time

EhcacheDemo4

package com.tzx.six.test;

import java.util.List;


import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;

import com.tzx.two.uitl.SessionFactoryUtils;



/**
 * hibernate Secondary caching does not cache multiple data at the same time
 * @author Administrator
 *
 */
public class EhcacheDemo4 {
	public static void main(String[] args) {
		Session session = SessionFactoryUtils.openSession();
		Transaction transaction = session.beginTransaction();
		
		Query query = session.createQuery("from User");
//		Controlling secondary caching
		query.setCacheable(true);
		List list = query.list();
		System.out.println(list);
		List list2 = query.list();
		System.out.println(list2);
		List list3 = query.list();
		System.out.println(list3);
		
		
		transaction.commit();
		session.close();
	}
}

Manual Opening of Level 2 Cache

query.setCacheable(true);

Topics: Ehcache Session Hibernate Maven