spring+ MyBatis level Two cache using Redis as cache

Source: Internet
Author: User
Tags aop connection pooling object object redis serialization static class port number

Springmybatisconfig.xml Configuration

<?xml version= "1.0" encoding= "Utf-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" xmlns: Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:aop= "HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP" xmlns:tx= " Http://www.springframework.org/schema/tx "xmlns:context=" Http://www.springframework.org/schema/context "xsi: schemalocation= "Http://www.springframework.org/schema/beans HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/BEANS/SPR Ing-beans-3.0.xsd HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/AOP http://www.springframework.org/schema/aop/spring -aop-3.0.xsd Http://www.springframework.org/schema/context HTTP://WWW.SPRINGFRAMEWORK.ORG/SCHEMA/CONTEXT/SPR Ing-context-3.0.xsd Http://www.springframework.org/schema/jee Http://www.springframework.org/schema/jee/spri Ng-jee-3.0.xsd Http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3 .0.xsd "default-autowire=" ByName "default-lazy-inIt= "false" > <!--one, register data source with Druid database connection pool-<bean id= "DataSource" class= "Com.alibaba.druid.pool.DruidDat Asource > <!--basic configuration-<property name= "url" value= "${jdbc.url}" ></property> &lt ;p roperty name= "Driverclassname" value= "Com.mysql.jdbc.Driver" ></property> <property name= "username" va Lue= "root" ></property> <property name= "password" value= "password" ></property> <!- -Key configuration-<!--the number of physical connections established when initializing. Initialization occurs when the display calls the Init method, or the first time getconnection-<property name= "InitialSize" value= "3"/> <!--the minimum number of connection pools Volume-<property name= "Minidle" value= "2"/> <!--maximum number of connection pools--<property name= "Max  
  
     Active "value="/> <!--configuration Get connection Wait timeout time-<property name= "maxwait" value= "10000"/> <!--performance Configuration-<!--open Pscache, and specify the size of Pscache on each connection-<property name="Poolpreparedstatements" value= "true"/> <property name= "maxpoolpreparedstatementperconnectionsize" value= "2 0 "/> <!--other Configurations-<!--configuration interval how often do you detect idle connections that need to be closed, in milliseconds--and <property name=" Ti Mebetweenevictionrunsmillis "value=" 60000 "/> <!--Configure the minimum lifetime of a connection in the pool, in milliseconds--and <property name=" M Inevictableidletimemillis "value=" 300000 "/> <!--is recommended to be configured to true without compromising performance and ensuring security. When applying for connection detection, if idle time is greater than Timebetweenevictionrunsmillis, perform validationquery to detect if the connection is valid. --<property name= "Testwhileidle" value= "true"/> <!--It is recommended to configure true to prevent access to the connection from being unavailable and to execute Validatio when requesting a connection Nquery detects if the connection is valid, and doing this will degrade performance. --<property name= "Testonborrow" value= "true"/> <!--when the connection is returned, the Validationquery detects if the connection is valid, this configuration will drop Low performance--<property name= "Testonreturn" value= "false"/> </bean> <bean id= "Sqlsessionfactor Y "class=" Org.mybatis.spring.SqlSessionFactoryBean "> <!
        The--datasource property specifies the connection pool to use--<property name= "DataSource" ref= "DataSource"/> <!--turn on cache support--
                <property name= "Configurationproperties" > <props> <!--Global Mapper enable Cache--
                <prop key= "cacheenabled" >true</prop> <!--query, close the associated object for immediate loading to improve performance-- <prop key= "lazyloadingenabled" >false</prop> <!--set the form of the associated object loading, where the field is loaded on demand (the Load field is specified by SQL) and the associated table is not loaded All fields to improve performance--<prop key= "aggressivelazyloading" >true</prop> <!--for unknown
                SQL query that allows different result sets to be returned to achieve a common effect--<prop key= "multipleresultsetsenabled" >true</prop> <!--allow column labels to be used instead of column names--<prop key= "Usecolumnlabel" >true</prop> <!-- Allows the use of custom primary key values (such as the program-generated UUID 32-bit encoding as the key value), the data table PK generation strategy will be overwritten--<prop key= "Usegeneratedkeys" >true</prop
               > <!--give nested resultmap with field-property mapping support--<prop key= "Automappingbehavior" >FULL</prop>
                <!--cache SQL for bulk update operations to improve performance--<prop key= "Defaultexecutortype" >BATCH</prop>
            <!--database is still not responding for more than 25,000 seconds timeout--<prop key= "Defaultstatementtimeout" >25000</prop> </props> </property> <!--automatically scan mapping.xml files--<property name= "Mapperl Ocations "value=" Classpath:com/dg/mapping/*.xml "></property> </bean> <!--(transaction management) transaction Manager, use Jtatransactionmanager for global TX--<bean id= "TransactionManager" class= "ORG.SPRINGFRAMEWORK.J Dbc.datasource.DataSourceTransactionManager "> <property name=" DataSource "ref=" DataSource "/> </be  An> </beans>

Springredisconfig.xml

<?xml version= "1.0" encoding= "UTF-8"?> <beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:
	Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xmlns:context= "Http://www.springframework.org/schema/context" Xmlns:cache= "Http://www.springframework.org/schema/cache" xsi:schemalocation= "http://www.springframework.org/ Schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework. Org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd Http://www.springfram Ework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd "> <!--redis data source--&G
	T <bean id= "Poolconfig" class= "Redis.clients.jedis.JedisPoolConfig" > <!--maximum idle number--<property name= "MaxI
		Dle "value="/> <!--maximum empty connections-<property name= "maxtotal" value= "6000"/> <!--max wait Time- <property name= "Maxwaitmillis" value= "1000"/&Gt <!--connection Timeout is blocked, false times abnormal, Ture blocked until timeout, default true--<property name= "blockwhenexhausted" value= "true"/> <!-  -When you return to the connection, detect if the connection is successful-<property name= "Testonborrow" value= "true"/> </bean> <!--spring-redis Connection Pool Management factory --<bean id= "Jedisconnectionfactory" class= " Org.springframework.data.redis.connection.jedis.JedisConnectionFactory "> <!--IP address--<property name="  HostName "value=" 127.0.0.1 "/> <!--port number--<property name=" Port "value=" 6379 "/> <!--time-out default 2000 --<property Name= "Timeout" value= "30000"/> <!--Connection Pool configuration Reference--<property name= "Poolconfig" ref= "p Oolconfig "/> <!--Usepool: whether to use connection pooling--<property name=" Usepool "value=" true "/> </bean> <!- -Redis Template definition--<bean id= "Redistemplate" class= " Org.springframework.data.redis.core.RedisTemplate "> <property name=" connectionfactory "ref=" Jedisconnectionfactory "/> <proPerty name= "Keyserializer" > <bean class= "Org.springframework.data.redis.serializer.StringRedisSerializer"/&
		Gt </property> <property name= "ValueSerializer" > <bean class= "Org.springframework.data.redis.serializ Er. Jdkserializationredisserializer "/> </property> <property name=" Hashkeyserializer "> <bean CLA ss= "Org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name= " Hashvalueserializer "> <bean class=" Org.springframework.data.redis.serializer.JdkSerializationRedisSerializer "/> </property> <!--open transaction-- > <property name= "Enabletransactionsupport" value= "true" ></property> </bean> <!--is not implemented MYBA TIS's cache interface implements the spring caches interface's cache configuration-<!--uses the implementation of the spring caches cache manager--<bean id= "CacheManager" class=
   "Org.springframework.cache.support.SimpleCacheManager" > <property name= "Caches" >         <set> <!--custom Redis cache operation implemented--<bean class= "Com.redisCache.RedisCach E "> <property name=" name "value=" Mycache "/> <property name=" Redistempl Ate "ref=" redistemplate "/> </bean> </set> </property> </be  An> <!--spring Enable cache annotations--<cache:annotation-driven cache-manager= "CacheManager"/> </beans>


Like most ORM layer frameworks, MyBatis naturally provides support for first-level caches and level two caches. The first level cache and level two cache are used and defined.

1, the first-level cache is the sqlsession level cache. The Sqlsession object needs to be constructed when manipulating the database, and there is a (memory area) data structure (HASHMAP) in the object that stores the cached data. The cache data regions (HASHMAP) between different sqlsession are not affected by each other.

Second-level cache is the mapper level of cache, multiple sqlsession to operate the same mapper SQL statement, multiple sqlsession to operate the database to get the data there will be two cache area, multiple sqlsession can share a two-level cache, The second-level cache is cross-sqlsession.

2, a first-level cache scope is the same sqlsession, two times in the same sqlsession execute the same SQL statement, the execution of the database will write the query data to the cache (memory), the second time from the cache will not query from the database, thereby improving query efficiency. The first-level cache in the sqlsession does not exist when a sqlsession is finished. MyBatis first-level caching is turned on by default.

A secondary cache is shared by multiple sqlsession, with the same namespace of mapper, different sqlsession two executions of SQL statements under the same namespace and passing parameters to SQL in the same way that the same SQL statements are eventually executed. After the first execution, the data queried in the database is written to the cache (memory), and the second time the data from the cache is no longer queried from the database, thus improving query efficiency. MyBatis no two cache is enabled by default and needs to be configured to turn on level two cache in the setting global parameter.

In general, when we integrate MyBatis and spring, the Mybatis-spring package will automatically split the sqlsession, and spring uses a template method to encapsulate the select () operation with dynamic proxy sqlsessionproxy. Each select () query executes the opensession () automatically first, and after close () calls the Close () method, which is equivalent to generating a new session instance, so we do not have to manually close the session (), It is also not possible to use MyBatis's first-level cache, which means that MyBatis's first-level cache does not work in spring.

Therefore, we generally implement the MyBatis level two cache in the project, although MyBatis comes with a level two cache function, but if the actual cluster environment, the use of the two-level cache is only for a single node, so we adopt a distributed two-level cache. Generic cache NoSQL databases such as Redis,mancache, or ehcache, can be implemented to better serve the ORM queries in the Tomcat cluster.

The following mainly through the Redis implementation of the MyBatis level two cache function. 1. Turn on level Two cache in configuration file

[HTML] View plain copy <setting name= "cacheenabled" value= "true"/> 2, implement MyBatis cache interface

Package Com.rediscache;
Import Java.io.ByteArrayInputStream;
Import Java.io.ByteArrayOutputStream;
Import Java.io.ObjectInputStream;
Import Java.io.ObjectOutputStream;
Import Java.util.Set;
Import Java.util.concurrent.locks.ReadWriteLock;

Import Java.util.concurrent.locks.ReentrantReadWriteLock;
Import Org.apache.ibatis.cache.Cache;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import Org.springframework.context.ApplicationContext;
Import Org.springframework.context.support.ClassPathXmlApplicationContext;
Import org.springframework.dao.DataAccessException;
Import org.springframework.data.redis.connection.RedisConnection;
Import Org.springframework.data.redis.core.RedisCallback;
Import Org.springframework.data.redis.core.RedisTemplate;

Import Org.springframework.util.DigestUtils;

	public class Rediscache implements Cache {private static Logger Logger = Loggerfactory.getlogger (Rediscache1.class); /** the Readwritelock. */private final readwritelock Readwritelock = new Reentrantreadwritelock ();
	Public final long livetime = 86400;

	Private final String Common_cache_key = "COM:";
	Private String ID;
	Private redistemplate<string, object> redistemplate;


	Private ApplicationContext context; Public Rediscache () {} public Rediscache (final String ID) {if (id = = null) {throw new illegalargumentexception
		("Must Pass in ID");
		}//springbean gets the configured redistemplate context = new Classpathxmlapplicationcontext ("Spring-redis.xml");
		Redistemplate = (redistemplate) context.getbean ("Redistemplate"); Logger.debug (">>>>>>>>>>>>>>>>>>>>>
		Mybatisrediscache:id= "+ ID);
	This.id = ID;
		} private String GetKey (Object key) {StringBuilder Accum = new StringBuilder ();
		Accum.append (Common_cache_key);
		Accum.append (this.id). Append (":");
		Accum.append (Digestutils.md5digestashex (string.valueof (key). GetBytes ()));
	return accum.tostring (); }/** * Redis key rule prefix */private String GETKEys () {return common_cache_key + this.id + ":*";
	} @Override Public String getId () {return id;
		} @Override public void PutObject (object key, Object value) {final String Keyf = GetKey (key);
		Final Object Valuef = value; Redistemplate.execute (New rediscallback<long> () {public Long Doinredis (redisconnection connection) throws Dataa
				ccessexception {byte[] keyb = Keyf.getbytes ();
				byte[] Valueb = serializeutil.serialize (VALUEF);
				Connection.set (keyb, VALUEB);
				Logger.debug ("Add cache Key:--------" + Keyf + "livetime seconds:" + livetime);
				if (Livetime > 0) {connection.expire (keyb, Livetime);
			} return 1L;

	}
		});
		} @Override public Object GetObject (object key) {final String Keyf = GetKey (key);
		Object object = null;  Object = Redistemplate.execute (new rediscallback<object> () {public Object Doinredis (redisconnection connection)
				Throws DataAccessException {byte[] k = Keyf.getbytes (); byte[] value = ConNection.get (k);
				if (value = = null) {return null;
			} return Serializeutil.unserialize (value);
		}
		});
	return object;
		} @Override public Object Removeobject (object key) {final String Keyf = GetKey (key);
		Object object = null; Object = Redistemplate.execute (new rediscallback<long> () {public Long Doinredis (redisconnection connection) thro
				WS DataAccessException {logger.debug ("Remove cache key:--------" + keyf);
			Return Connection.del (Keyf.getbytes ());
		}
		});
	return object; } @Override public void Clear () {Redistemplate.execute (new rediscallback<integer> () {@Override public I Nteger Doinredis (redisconnection connection) throws DataAccessException {set<byte[]> keys = Connection.keys (get
				Keys (). GetBytes ());
				int num = 0;
					if (null! = Keys &&!keys.isempty ()) {num = Keys.size ();
					For (byte[] k:keys) {CONNECTION.DECR (k); }} logger.debug ("Remove all key prefixes to" + getkeys () + "number:" + num);
			return 1;

	}

		});
		} @Override public int getsize () {Object object = null; Object = Redistemplate.execute (new rediscallback<integer> () {@Override public Integer Doinredis (redisconnecti
				On connection) throws DataAccessException {set<byte[]> keys = Connection.keys (Getkeys (). GetBytes ());
				int num = 0;
				if (null! = Keys &&!keys.isempty ()) {num = Keys.size ();
				} logger.debug ("Query all key prefixes to" + getkeys () + "number:" + num);
			return num;
		}

		});
	Return ((Integer) object). Intvalue ();
	} @Override Public Readwritelock Getreadwritelock () {//TODO auto-generated method stub return readwritelock;
	} public redistemplate<string, Object> getredistemplate () {return redistemplate; } public void Setredistemplate (redistemplate<string, object> redistemplate) {this.redistemplate = RedisTemplate
	;
	} public void SetId (String id) {this.id = ID; } public static class Serializeutil {public static Byte[] Serialize (Object object) {ObjectOutputStream oos = null;
			Bytearrayoutputstream BAOs = null;
				try {//serialization BAOs = new Bytearrayoutputstream ();
				Oos = new ObjectOutputStream (BAOs);
				Oos.writeobject (object);
				byte[] bytes = Baos.tobytearray ();
			return bytes;
			} catch (Exception e) {e.printstacktrace ();
		} return null;
			public static Object unserialize (byte[] bytes) {if (bytes = = null) return null;
			Bytearrayinputstream Bais = null;
				try {//deserialization Bais = new Bytearrayinputstream (bytes);
				ObjectInputStream ois = new ObjectInputStream (Bais);
			return Ois.readobject ();
			} catch (Exception e) {e.printstacktrace ();
		} return null; }
	}

}
3, two-level cache of practical

We need to serialize all the entity classes and then add the custom cache feature to the mapper. Custom Cache Classes

	<cache eviction= "LRU" type= "com. Rediscache.rediscache "/>


After the Mapper XML file is configured to support the cache, all Mapper statement in the file are supported. To treat a particular article at this time, you need to:
<select id= "Inetaton" parametertype= "string" resulttype= "integer" usecache= "false" >
Select Inet_aton (#{name})
</select>

See the following example, a common cache tag attribute:

<cache 
eviction= "FIFO"  <!--recycle policy is first-in, and
flushinterval= "60000" <!--auto-refresh time 60s-->
Size= <!--cache up to 512 reference objects-
readonly= "true"/> <!--read-only
1 2 3) 4 5

Eviction (Recycling strategy)

lru– Least Recently used: Removes objects that are not used for the longest time. (The default property)

fifo– FIFO: Removes them by the order in which they are entered in the cache.

soft– Soft Reference: Removes objects based on the garbage collector state and soft reference rules.

weak– Weak references: More aggressively remove objects based on the garbage collector state and weak reference rules.

Flushinterval (Refresh interval)

Can be set to any positive integer, and they represent a reasonable millisecond in the form of a time period. The default is not set, that is, there is no refresh interval, and the cache simply refreshes when the statement is invoked.

Size (number of references)

Can be set to any positive integer, keep in mind the number of objects you cache and the number of available memory resources in your running environment. The default value is 1024.

ReadOnly (Read only)

Can be set to TRUE or false. A read-only cache returns the same instance of the cached object to all callers. Therefore, these objects cannot be modified. This provides a very important performance advantage. A read-write cache returns a copy of the cached object (by serialization). This will be slower, but safe, so the default is false.



Second, attention to a few details
1. If ReadOnly is false, the result set object is serializable at this time.
<cache readonly= "false"/>

2, before the sqlsession is not closed, if the same conditions to repeat the query, at this time using the local session cache, rather than the above-mentioned cache.

3. MyBatis cache query to the result set object, not the result set data, is to cache the mapped Po object collection.


Comment Methods used by the cache:

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.