Redis集成SSM框架

2018-12-27 21:38:00     

简介

jedis是redis的java客户端,spring将redis连接池作为一个bean配置。redis连接池分为两种,一种是“redis.clients.jedis.ShardedJedisPool”,这是基于hash算法的一种分布式集群redis客户端连接池。另一种是“redis.clients.jedis.JedisPool”,这是单机环境适用的redis连接池。

Redis集成SSM框架实际上就是spring集成redis,这篇博客是基于《个人档案系统》 的改进版。jar包通过maven管理,加入单机版的redis

改进版

Maven的pom.xml文件,管理相应的jar包

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<spring.version>4.3.6.RELEASE</spring.version>
	<!-- Test -->
	<junit.version>4.11</junit.version>
</properties>
<dependencies>
	<!-- spring mvc related.....start --> <!-- TODO: replace jackson with fastjson -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context</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-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>${spring.version}</version>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
	</dependency>
	<dependency>
		<groupId>commons-logging</groupId>
		<artifactId>commons-logging</artifactId>
		<version>1.1.3</version>
	</dependency>
	<dependency>
		<groupId>org.codehaus.jackson</groupId>
		<artifactId>jackson-mapper-asl</artifactId>
		<version>1.9.13</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-annotations</artifactId>
		<version>2.6.1</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-core</artifactId>
		<version>2.6.1</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.6.1</version>
	</dependency>
	<!-- spring mvc related.....end -->

	<!-- mybatis orm related.....start -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-orm</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>junit</groupId>
		<artifactId>junit</artifactId>
		<version>${junit.version}</version>
	</dependency>
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis-spring</artifactId>
		<version>1.2.3</version>
	</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>5.1.36</version>
	</dependency>
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.3.0</version>
	</dependency>
	<dependency>
		<groupId>c3p0</groupId>
		<artifactId>c3p0</artifactId>
		<version>0.9.1.2</version>
	</dependency>
	<dependency>
		<groupId>org.slf4j</groupId>
		<artifactId>slf4j-log4j12</artifactId>
		<version>1.7.12</version>
	</dependency>
	<!-- mybatis orm related.....end -->

	<!-- project log related.....start -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
	<!-- project log related.....end -->

	<!-- redis cache related.....start -->
	<dependency>
		<groupId>org.springframework.data</groupId>
		<artifactId>spring-data-redis</artifactId>
		<version>1.6.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
		<version>2.7.3</version>
	</dependency>
	<!-- redis cache related.....end -->
</dependencies>
<build>
	<plugins>
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-compiler-plugin</artifactId>
			<version>3.3</version>
			<configuration>
				<source>1.8</source>
				<target>1.8</target>
			</configuration>
		</plugin>
	</plugins>
</build>

加入redis缓存配置,在top.bounds.cache包下新建RedisCacheConfig

package top.bounds.cache;

import java.lang.reflect.Method;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;

/**
 * 通过spring管理redis缓存配置
 * 
 * @author bounds
 *
 */
@Configuration  
@EnableCaching 
public class RedisCacheConfig extends CachingConfigurerSupport {
    private volatile JedisConnectionFactory jedisConnectionFactory;
    private volatile RedisTemplate<String, String> redisTemplate;
    private volatile RedisCacheManager redisCacheManager;

    public RedisCacheConfig() {
        super();
    }

    /**
     * 带参数的构造方法 初始化所有的成员变量
     * 
     * @param jedisConnectionFactory
     * @param redisTemplate
     * @param redisCacheManager
     */
    public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate,
            RedisCacheManager redisCacheManager) {
        this.jedisConnectionFactory = jedisConnectionFactory;
        this.redisTemplate = redisTemplate;
        this.redisCacheManager = redisCacheManager;
    }

    public JedisConnectionFactory getJedisConnecionFactory() {
        return jedisConnectionFactory;
    }

    public RedisTemplate<String, String> getRedisTemplate() {
        return redisTemplate;
    }

    public RedisCacheManager getRedisCacheManager() {
        return redisCacheManager;
    }

    @Bean
    public KeyGenerator customKeyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... objects) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : objects) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
}

Spring对应的配置文件application-config.xml

<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: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-4.3.xsd  
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.3.xsd  
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
            
	<!-- 扫描包,通过注解,将Service、redis的生命周期纳入Spring的管理 -->
	<context:component-scan base-package="top.bounds.impl" />
	<context:component-scan base-package="top.bounds.cache" />
	<!-- class annotation related... end -->
	<!-- mybatis related... start -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations">
			<list>
				<value>classpath:db.properties</value>
				<value>classpath:redis.properties</value>
			</list>
		</property>
	</bean>
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="driverClass" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUrl"
			value="jdbc:mysql://${jdbc.host}:${jdbc.port}/${jdbc.database}?useUnicode=true&amp;characterEncoding=utf8" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<property name="acquireIncrement" value="1" />
		<property name="initialPoolSize" value="5" />
		<property name="maxPoolSize" value="20" />
		<property name="minPoolSize" value="5" />
		<property name="maxStatements" value="100" />
		<property name="testConnectionOnCheckout" value="true" />
	</bean>
	<!-- 扫描存放SQL语句的XML配置文件 -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="typeAliasesPackage" value="top.bounds.pojo" />
		<!-- 注入数据库连接信息 -->
		<property name="dataSource" ref="dataSource" />
		<property name="mapperLocations" value="classpath:top/bounds/mapper/*.xml" />
	</bean>
	<!-- 扫描Mapper类 ,并将其生命周期纳入Spring的管理 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="top.bounds.mapper" />
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager" />
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- redis config start -->
	<!-- 配置JedisPoolConfig实例 -->
	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxTotal" value="${redis.maxActive}" />
		<property name="maxWaitMillis" value="${redis.maxWait}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
	</bean>

	<!-- 配置JedisConnectionFactory -->
	<bean id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="hostName" value="${redis.host}" />
		<property name="port" value="${redis.port}" />
		<property name="password" value="${redis.pass}" />
		<property name="database" value="${redis.dbIndex}" />
		<property name="poolConfig" ref="poolConfig" />
	</bean>

	<!-- 配置RedisTemplate -->
	<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>

	<!-- 配置RedisCacheManager -->
	<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
		<constructor-arg name="redisOperations" ref="redisTemplate" />
		<property name="defaultExpiration" value="${redis.expiration}" />
	</bean>

	<!-- 配置RedisCacheConfig -->
	<bean id="redisCacheConfig" class="top.bounds.cache.RedisCacheConfig">
		<constructor-arg ref="jedisConnectionFactory" />
		<constructor-arg ref="redisTemplate" />
		<constructor-arg ref="redisCacheManager" />
	</bean>
	<!-- redis config end -->
</beans>

对应的classpath:redis.properties,我的redis没有设置密码,所以这里为空

redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true

对应的classpath:db.properties

jdbc.host=127.0.0.1
jdbc.database=transaction
jdbc.port=3306
jdbc.username=root
jdbc.password=123456

修改TeacherService的实现类TeacherImpl,缓存主要在service层进行,查询的结果会缓存,把对象序列号存到redis中去,key就是注解中的参数,例如@Cacheable("selectById"): 存在redis中的key就是selectById。缓存了这个结果之后再次请求这个方法就不会去数据库中查,而是从redis缓存中读取数据,这样就减少了跟数据库之间的交互。然后修改、删除、增加操作就会清除缓存,保持数据的一致性。

package top.bounds.impl;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import top.bounds.mapper.TeacherMapper;
import top.bounds.pojo.Teacher;
import top.bounds.service.TeacherService;

/**
 * @author bounds
 * @Cacheable("a")注解的意义就是把该方法的查询结果放到redis中去,下一次再发起查询就去redis中去取,存在redis中的数据的key就是a;
 * @CacheEvict(value={"a","b"},allEntries=true) 的意思就是执行该方法后要清除redis中key名称为a,b的数据;
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class TeacherImpl implements TeacherService {

	@Resource
	private TeacherMapper teacherMapper;

	@Cacheable("selectById") // 标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
	@Override
	public List<Teacher> selectById(int id) {

		return teacherMapper.selectById(id);
	}

	@CacheEvict(value = { "selectById", "listTeacher", "total", "selectCountById" }, allEntries = true) // 清空缓存,allEntries变量表示所有对象的缓存都清除
	@Override
	public int updateTeacher(Teacher teacher) {

		return teacherMapper.updateTeacher(teacher);
	}
	
	@CacheEvict(value = { "selectById", "listTeacher", "total", "selectCountById" }, allEntries = true) // 清空缓存,allEntries变量表示所有对象的缓存都清除
	@Override
	public int deleteTeacher(int id) {

		return teacherMapper.deleteTeacher(id);
	}
	
	@CacheEvict(value = { "selectById", "listTeacher", "total", "selectCountById" }, allEntries = true) // 清空缓存,allEntries变量表示所有对象的缓存都清除
	@Override
	public int addTeacher(Teacher teacher) {
		return teacherMapper.addTeacher(teacher);
	}

	@Cacheable("listTeacher") // 标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
	@Override
	public List<Teacher> listTeacher(int start, int limit) {

		return teacherMapper.listTeacher(start, limit);
	}

	@Cacheable("total") // 标注该方法查询的结果进入缓存,再次访问时直接读取缓存中的数据
	@Override
	public int total() {

		return teacherMapper.total();
	}

	@Override
	public int selectCountById(int id) {

		return teacherMapper.selectCountById(id);
	}

}

新建Redis缓存测试类SpringRedisTest

package top.bounds.test;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;

import top.bounds.cache.RedisCacheConfig;

public class SpringRedisTest {

	ApplicationContext context;

	@Before
	public void testBefore() {
		context = new ClassPathXmlApplicationContext("classpath:spring/application-config.xml");
	}

	@Test
	public void testOne() {
		@SuppressWarnings("unchecked")
		RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) context.getBean("redisTemplate");
		redisTemplate.opsForValue().set("1215", "peter");
		System.out.println(redisTemplate.opsForValue().get("1215"));
	}

	@Test
	public void testTwo() {
		RedisCacheConfig redisCacheConfig = (RedisCacheConfig) context.getBean("redisCacheConfig");
		redisCacheConfig.getRedisTemplate().opsForValue().set("onecent", "hhhh");
		System.out.println(redisCacheConfig.getRedisTemplate().opsForValue().get("onecent"));
	}

	@After
	public void testAfter() {
		((ClassPathXmlApplicationContext) context).close();
	}
}

查看redis-cli客户端,有相应的缓存记录,测试成功。

启动tomcat,访问http://localhost:8080/SpringRedis/test.html进行增删改查操作,结合redis-cli客户端查看缓存效果。

总结

  • 缓存机制说明:所有的查询结果都放进了缓存,也就是把MySQL查询的结果放到了redis中去,然后第二次发起该条查询时就可以从redis中去读取查询的结果,从而不与MySQL交互,从而达到优化的效果
  • redis的查询速度之于MySQL的查询速度相当于 内存读写速度 /硬盘读写速度
ps:本篇博客源码下载链接:https://pan.baidu.com/s/1XXPAAInURmfjfQNQ0Ih8xQ密码:gzna
Redis缓存的介绍

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。换句话说,Redis就像是一个HashMap,不过不是在JVM中运行,而是以一个独立进程的形式运行。一般说来,会被当作缓存使用。 因为它比数据库(mysql)快,所以常用的数据,可以考虑放在这里,这样就提高了性能

Quartz作业调度框架

你如果想要在每次作业完成时发送一个电子邮件或者进行一次数据备份时,可以用quartz Quartz是一个完全由java编写的开源作业调度框架。不要让作业调度这个术语吓着你。尽管Quartz框架整合了许多额外功能, 但就其简易形式看,你会发现它易用得简直让人受不了!

 发表评论