redis和spring集成(注解实现,方便,快捷)

Posted Fighter168

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis和spring集成(注解实现,方便,快捷)相关的知识,希望对你有一定的参考价值。

前言:

         spring和redis集成有很多方式,看到网上很多都是使用redistemplate自己去做redis 的一些操作,但是对于我们开发来说,肯定是使用越方便越好,于是乎就有了spring的对redis或者memcahe这些换成框架的封装,只需要引入spring的spring-data-redis的jar。 

         好了,废话不多说,我们开始上代码。


工程目录结构

        我们先预览一下这个项目的工程目录结构先:


启动redis

        还没安装的redis 的同学可以自己去安装redis,我自己是在window上安装的,其实也不是安装,解压一下就可以使用了,不过需要注意的是它的启动方式,直接点击redis-server启动会直接闪退的,正确的启动方式使用命令【redis-server.exe  redis.windows.conf】,详细请参考:Windows 64位下安装Redis详细教程



创建数据库



配置pom文件

pom文件就没什么好说的了,直接贴配置给大家吧

<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>ylink.com</groupId>
	<artifactId>spring-redis-test</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<build />

	<properties>
		<spring.version>4.2.6.RELEASE</spring.version>
		<slf4j.version>1.6.4</slf4j.version>
		<logback.version>1.0.0</logback.version>
		<junit.version>4.9</junit.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>$spring.version</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>$spring.version</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>$spring.version</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.1.1</version>
		</dependency>
		<!-- junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>$junit.version</version>
			<scope>test</scope>
		</dependency>

		<!-- memcached <dependency> <groupId>com.whalin</groupId> <artifactId>Memcached-Java-Client</artifactId> 
			<version>3.0.1</version> </dependency> -->
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.2</version>
		</dependency>
		<!-- log -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>$slf4j.version</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>$logback.version</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.8.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.7.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.31</version>
		</dependency>
		<dependency>
			<groupId>com.jolbox</groupId>
			<artifactId>bonecp</artifactId>
			<version>0.7.1.RELEASE</version>
		</dependency>
	</dependencies>
</project>



配置spring文件


下面是spring-mvc.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:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-4.2.xsd    
                        http://www.springframework.org/schema/mvc    
                        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
    <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->  
    <context:component-scan base-package="com.cn" />  
    
    <!-- 引入同文件夹下的redis属性配置文件 -->
    <import resource="spring-redis.xml"/>
    
    <import resource="spring-datasource-bonecp.xml"/>
    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		 <property name="basePackage" value="com.cn.dao"/> 
	 </bean>
    
</beans>  


下面是spring-redis.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:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    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.2.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-4.2.xsd    
                        http://www.springframework.org/schema/mvc    
                        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
                        http://www.springframework.org/schema/cache 
                        http://www.springframework.org/schema/cache/spring-cache-4.2.xsd"> 
    
    <context:property-placeholder location="classpath:redis-config.properties" />  

    <!-- 启用缓存注解功能,这个是必须的,否则注解不会生效,另外,该注解一定要声明在spring主配置文件中才会生效 -->  
    <cache:annotation-driven cache-manager="cacheManager" />  
    
     <!-- redis 相关配置 -->  
     <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
         <property name="maxIdle" value="$redis.maxIdle" />   
         <property name="maxWaitMillis" value="$redis.maxWait" />  
         <property name="testOnBorrow" value="$redis.testOnBorrow" />  
     </bean>  

     <bean id="JedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"  
       p:host-name="$redis.host" p:port="$redis.port" p:password="$redis.pass" p:pool-config-ref="poolConfig"/>  
  
     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
         <property name="connectionFactory" ref="JedisConnectionFactory" />  
     </bean>  
    
     <!-- spring自己的缓存管理器,这里定义了缓存位置名称 ,即注解中的value -->  
     <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">  
         <property name="caches">  
            <set>  
                <!-- 这里可以配置多个redis -->
                <!-- <bean class="com.cn.util.RedisCache">  
                     <property name="redisTemplate" ref="redisTemplate" />  
                     <property name="name" value="default"/>  
                </bean> -->  
                <bean class="com.cn.util.RedisCache">  
                     <property name="redisTemplate" ref="redisTemplate" />  
                     <property name="name" value="common"/>  
                     <!-- common名称要在类或方法的注解中使用 -->
                </bean>
            </set>  
         </property>  
     </bean>  
    
</beans>  

下面是spring-datasource-bonecp.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:task="http://www.springframework.org/schema/task"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
		http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

	<!--用于连接boneCp数据源 -->
	<bean id="commonDataSourceConfig" class="com.jolbox.bonecp.BoneCPDataSource" abstract="true" destroy-method="close">
        <!-- 每个分区最大的连接数 -->  
        <property name="maxConnectionsPerPartition" value="100" />  
        <!-- 每个分区最小的连接数 -->  
        <property name="minConnectionsPerPartition" value="10" />  
        <!-- 分区数 ,默认值2,最小1,推荐3-4,视应用而定-->  
        <property name="partitionCount" value="3" />  
        <!-- 每次去拿数据库连接的时候一次性要拿几个,默认值:2 -->  
        <property name="acquireIncrement" value="2" />
        <!-- 测试连接有效性的间隔时间,单位分钟   
        <property name="idleConnectionTestPeriod" value="40" />-->
        <!-- 空闲存活时间 分钟
        <property name="idleMaxAge" value="10"/>-->
        <!-- 连接超时时间 毫秒-->
		<property name="connectionTimeout" value="10000"/>
	</bean>
 
	<!-- 数据源配置 -->
	<bean id="dataSource" parent="commonDataSourceConfig">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		
		<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test" />
		<property name="username" value="root"/>
		<property name="password" value=""/>
	</bean>  
 
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:cfg.xml"/>
		<property name="dataSource" ref="dataSource"/>
	</bean>
</beans>


编写java类

直接上service,其他的大家可以自己去我上传的源码去下载查看,至于对spring的缓存的注解不太了解怎么使用的,可以参考下这边博客园博主写的博文:Spring Cache使用详解


package com.cn.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.cn.bean.User;
import com.cn.dao.UserDao;

/**
 * @类名称: UserServiceImpl
 * @类描述: 
 * @创建人: 1603254
 * @创建时间: 2016-12-2 上午11:10:33
 *
 * @修改人: 1603254
 * @操作时间: 2016-12-2 上午11:10:33
 * @操作原因: 
 * 
 */
@Service
public class UserServiceImpl implements UserService

	@Autowired
	private UserDao userDao;

	@Cacheable(value="common",key="'id_'+#id")
	public User selectByPrimaryKey(Integer id) 
		System.out.println("======================");
		System.out.println("======================");
		System.out.println("======================");
		return userDao.selectByPrimaryKey(id);
	
	
	@CachePut(value="common",key="#user.getUserName()")
	public void insertSelective(User user) 
//		userDao.insertSelective(user);
		System.out.println("########################");
		System.out.println("########################");
		System.out.println("########################");
	

	@CacheEvict(value="common",key="'id_'+#id")
	public void deleteByPrimaryKey(Integer id) 
//		userDao.deleteByPrimaryKey(id);
		System.out.println("******************************");
		System.out.println("******************************");
		System.out.println("******************************");
	


编写mybatis配置文件

下面是cfg.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
	 <!-- mapping 文件路径配置 -->  
	 <mappers>  
        <mapper resource="mapper/UserMapper.xml" />  
    </mappers>  
     <!-- <plugins>
	    <plugin interceptor="com.github.pagehelper.PageHelper">
	    	<property name="dialect" value="oracle"/>
	        该参数默认为false
	        设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用
	        和startPage中的pageNum效果一样
	        <property name="offsetAsPageNum" value="true"/>
	        该参数默认为false
	        设置为true时,使用RowBounds分页会进行count查询
	        <property name="rowBoundsWithCount" value="true"/>
	        设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果
	        (相当于没有执行分页查询,但是返回结果仍然是Page类型)
	        <property name="pageSizeZero" value="true"/>
	        启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页
	        禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据
	        <property name="reasonable" value="true"/>
	        增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值
	        可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值
	        <property name="params" value="pageNum=start;pageSize=limit;pageSizeZero=zero;reasonable=heli;count=contsql"/>
    	</plugin>
	</plugins>
 -->
</configuration>


下面是UserMapper.xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cn.dao.UserDao" >
  
  <resultMap id="resultMap" type="com.cn.bean.User" >
	    <result column="id" property="id" jdbcType="CHAR" />
	    <result column="name" property="name" jdbcType="CHAR" />
  </resultMap>
<!--添加--> 
 <insert id="insertSelective"  parameterType="com.cn.bean.User">
 insert into user(id,name) values(#id,jdbcType=CHAR,#name,jdbcType=VARCHAR)
 </insert>
<!--查询-->
 <select id="selectByPrimaryKey"  resultMap="resultMap">
 	select * from user where id=#id
 </select>
<!--删除-->
 <select id="deleteByPrimaryKey"  resultMap="resultMap">
 	delete   from user where id=#id
 </select>
</mapper>



配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app id="WebApp_ID">
	<display-name>spring-redis-test</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>


	<servlet>
		<servlet-name>SpringMVC</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>
</web-app>


编写测试用例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

import com.cn.bean.User;
import com.cn.service.UserService;


@ContextConfiguration(locations="classpath:spring-mvc.xml")
public class Test extends AbstractJUnit4SpringContextTests 

	@Autowired
	private UserService userService;
	
	
	
	@org.junit.Test
	public void  add()
		User user=new User();
		user.setName("wen");
		user.setId("1");
		userService.insertSelective(user);
	
	
	
	@org.junit.Test
	public void  query()
		User user=userService.selectByPrimaryKey(1);
		System.out.println(user.toString());
	

上面我是这样执行校验的:  1)先把数据库的操作打开,插入一条数据,插入的时候,数据库会插入一条数据,redis里面也会有一条数据。 2)然后执行查询的测试用例,第一次查询会将数据库的数据查到redis,然后第二次直接从redis里面去查询,你可以把数据库的数据删掉,结果显示是可以从redis里面查询出来
上面代码我都测试过,无措执行,部分缺少的java类,可以直接下载demo查看,有问题大家可以提出来讨论一下,谢谢~

源代码下载

下载地址是:spring集成redis源码+表结构



其实说实话,用起来还是蛮简单的,而且方便,快捷,真正想要了解深入一点的话,还是建议有时间去看看源代码。



后面大家评论说RedisCache类没写给出来,下面给一下(链接里面的demo 有Override 注解删除就可以使用了):

package com.cn.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
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;

public class RedisCache implements Cache

	private RedisTemplate<String, Object> redisTemplate;  
    private String name;  
    public RedisTemplate<String, Object> getRedisTemplate() 
	    return redisTemplate;  
	
	 
	public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) 
	    this.redisTemplate = redisTemplate;  
	
	 
	public void setName(String name) 
	    this.name = name;  
    
	 
    public String getName() 
       // TODO Auto-generated method stub  
        return this.name;  
    

    public Object getNativeCache() 
      // TODO Auto-generated method stub  
        return this.redisTemplate;  
    
 
    public ValueWrapper get(Object key) 
      // TODO Auto-generated method stub
      System.out.println("get key");
      final String keyf =  key.toString();
      Object object = null;
      object = redisTemplate.execute(new RedisCallback<Object>() 
      public Object doInRedis(RedisConnection connection)  
                  throws DataAccessException 
          byte[] key = keyf.getBytes();
          byte[] value = connection.get(key);
          if (value == null) 
             return null;
            
          return toObject(value);
          
       );
        return (object != null ? new SimpleValueWrapper(object) : null);
      
  
     public void put(Object key, Object value) 
       // TODO Auto-generated method stub
       System.out.println("put key");
       final String keyf = key.toString();  
       final Object valuef = value;  
       final long liveTime = 86400;  
       redisTemplate.execute(new RedisCallback<Long>()   
           public Long doInRedis(RedisConnection connection)  
                   throws DataAccessException   
                byte[] keyb = keyf.getBytes();  
	            byte[] valueb = toByteArray(valuef);  
	            connection.set(keyb, valueb);  
	            if (liveTime > 0)   
	                connection.expire(keyb, liveTime);  
                   
                return 1L;  
               
         );  
      

      private byte[] toByteArray(Object obj)   
         byte[] bytes = null;  
         ByteArrayOutputStream bos = new ByteArrayOutputStream();  
         try   
           ObjectOutputStream oos = new ObjectOutputStream(bos);  
           oos.writeObject(obj);  
           oos.flush();  
           bytes = bos.toByteArray();  
           oos.close();  
           bos.close();  
	      catch (IOException ex)   
	           ex.printStackTrace();  
	        
	      return bytes;  
	      

	   private Object toObject(byte[] bytes) 
         Object obj = null;  
	       try 
	           ByteArrayInputStream bis = new ByteArrayInputStream(bytes);  
	           ObjectInputStream ois = new ObjectInputStream(bis);  
	           obj = ois.readObject();  
	           ois.close();  
	           bis.close();  
	        catch (IOException ex)   
	           ex.printStackTrace();  
	         catch (ClassNotFoundException ex)   
	           ex.printStackTrace();  
	          
	        return obj;  
        
  
       public void evict(Object key)   
         // TODO Auto-generated method stub  
    	 System.out.println("del key");
         final String keyf = key.toString();  
         redisTemplate.execute(new RedisCallback<Long>()   
         public Long doInRedis(RedisConnection connection)  
                   throws DataAccessException   
             return connection.del(keyf.getBytes());  
              
          );  
        
 
	    public void clear()   
	       // TODO Auto-generated method stub  
	    	System.out.println("clear key");
	       redisTemplate.execute(new RedisCallback<String>()   
	            public String doInRedis(RedisConnection connection)  
	                    throws DataAccessException   
	              connection.flushDb();  
	                return "ok";  
	             
	       );  
	    

		public <T> T get(Object key, Class<T> type) 
			// TODO Auto-generated method stub
			return null;
		
	
		public ValueWrapper putIfAbsent(Object key, Object value) 
			// TODO Auto-generated method stub
			return null;
		



以上是关于redis和spring集成(注解实现,方便,快捷)的主要内容,如果未能解决你的问题,请参考以下文章

Spring集成Redis使用注解

Spring Boot (24) 使用Spring Cache集成Redis

spring-data-redis时效设置

SpringBoot Validation参数校验 详解自定义注解规则和分组校验

spring boot注解之@Scheduled定时任务实现

博学谷学习记录超强总结,用心分享 | SpringCache常用注解介绍+集成redis