缓存技术(一)ssm添加缓存技术

学习指南:

我们在写一般的项目在使用增删改查,一般是直接操作数据库,但是我们可以换一个思路,如果当前时间段1万个人同时访问数据库,就会造成数据库的宕机。我们可不可以换个思路,把数据库复制一份“一模一样”的数据,只要查一次就完成了复制,如果下次再进行查询,就直接从“副本”里进行查询。这样就不会直接访问数据库了。这种副本就叫做缓存。这个技术就叫做缓存技术。

 

基础项目三层结构:

添加缓存后的层次结构:

 

RedisTemplate对象介绍

使用Spring提供的一个操作Redis数据库的模板对象,提供了对象redis数据库的增删查改的功能,封装了Jedis,同时自身实现了:

对象的序列化和反序列化功能(obj----byte[]),作为对象存储的默认方案。

如果需要将对象转化为json字符串存储,需要覆盖默认方案。

 

RedisTemplate操作对象我们已经在之前以及有提及,所以这次直接上手项目:

第一步:导入pom依赖(和之前ssm整合的依赖无异,需要额外添加的是:jackson包、Jedis包、spring-data-redis包(封装了Jedis))

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.bjsxt.usercache</groupId>
	<artifactId>maven-cache</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<!--声明需要的资源坐标 -->
	<dependencies>
		<!--mysql驱动包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.38</version>
		</dependency>
		<!--mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.6</version>
		</dependency>
		<!--mybatis-spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!--pagehelper -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper</artifactId>
			<version>4.0.3</version>
		</dependency>
		<!--德鲁伊数据连接池 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.10</version>
		</dependency>
		<!--spring-aop -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>
		<!--spring-beans -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>
		<!--spring-beans -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>
		<!--spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-core -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-expression -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-tx -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-web -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!--spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.18.RELEASE</version>
		</dependency>

		<!-- jstl -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- jsp -->
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.2</version>
			<scope>provided</scope>
		</dependency>

		<!-- servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.9.4</version>
		</dependency>
		
		<!-- 因为RedisTemplate是将对象修改为jaskson数组进行读取,所以这里需要这个转环包 -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.7.0</version>
		</dependency>
		
		<!-- RedisTemplate底部是Jedis的封装,所以也是需要Jedis插件 -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>


		<!-- 使用RedisTemplate -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.8.6.RELEASE</version>
		</dependency>
	</dependencies>
</project>

第二步:书写一个正常的ssm项目:我们这里书写一个能够正常的查询,修改,删除的ssm简易项目:

  xml文件一:application-context.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"
	xsi:schemaLocation="                                               
            http://www.springframework.org/schema/beans    
            http://www.springframework.org/schema/beans/spring-beans.xsd    
          ">
	<!-- 实例化dataSource连接池 -->
	<bean id="dataSource"
		class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName"
			value="com.mysql.jdbc.Driver"></property>
		<property name="url"
			value="jdbc:mysql://localhost:3306/db_email"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
	</bean>

	<!-- 实例化SqlSessionFactory -->
	<bean id="sqlSessionFactory"
		class="org.apache.ibatis.session.SqlSessionFactory">
		<!-- 输入数据库连接池 -->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 注入分页插件 -->
		<property name="plugins">
			<list>
				<!-- 实例化 -->
				<bean class="com.github.pagehelper.PageHelper">
					<!-- 给properties属性注入值 -->
					<property name="properties">
						<props>
							<!-- 方言 -->
							<prop key="dialect">mysql</prop>
							<!-- 分页合理化参数,不用自己判断最大页和最小页 -->
							<prop key="reasonable">true</prop>
						</props>
					</property>
				</bean>
			</list>
		</property>
	</bean>

	<!-- 扫描Mapper接口,产生代理对象 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.bjsxt.mapper"></property>
		<property name="sqlSessionFactoryBeanName"
			value="sqlSessionFactory"></property>
	</bean>


</beans>

 

文件二:applicationContext-service.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: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/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<!-- 扫描service对象 -->
	<context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>
	
	<!--实例化事务管理对象  -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<!-- 声明事务管理切面 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="load*" read-only="true"/>
			<tx:method name="save*" read-only="false"/>
			<tx:method name="insert*" read-only="false"/>
			<tx:method name="delete*" read-only="false"/>
			<tx:method name="update*" read-only="false"/>
			<tx:method name="*" read-only="true"/>
		</tx:attributes>
	</tx:advice>
	
	<aop:config>
		<aop:pointcut expression="execution(* com.bjsxt.service.impl.*.*(..))" id="pc"/>
		<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
	</aop:config>


</beans>

文件三:配置springmvc.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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<context:component-scan
		base-package="com.bjsxt.controller"></context:component-scan>

	<mvc:annotation-driven></mvc:annotation-driven>

	<!-- <mvc:resources location="" mapping=""></mvc:resources> -->

	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

配置文件四:我们在这里还需要加入cache.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"
	xsi:schemaLocation="                                               
            http://www.springframework.org/schema/beans    
            http://www.springframework.org/schema/beans/spring-beans.xsd    
          ">

	<!-- 使用redisTemplate操作数据库对象 -->
	<bean id="redisTemplate"
		class="org.springframework.data.redis.core.RedisTemplate">
		<!-- 因为需要使用jedis连接数据库,所以我们需要一个工厂对数据库进行连接 
			进入该类>找到该类的父类,父类有构造方法,方法里有connectionFactory,底层还是需要这个工厂连接数据库
			keySerializer实现键的序列化 点进去查看类 因为对key不要求选择String的
			valueSerializer实现值的序列化,选择General
		-->
		<property name="connectionFactory" ref="connectionFactory"></property>
		<property name="keySerializer" ref="keySerializer"></property>
		<property name="valueSerializer" ref="valueSerializer"></property>
	</bean>
	
	<!-- 通过工厂连接数据库 -->
	<bean id="connectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<property name="hostName" value="192.168.224.11"></property>
		<property name="port" value="6379"></property>
	</bean>
	
	<!-- 键与值都是通过无参构造方法对其进行连接 -->
	<bean id="keySerializer" 
		class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>

	<bean id="valueSerializer" 
		class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"></bean>
</beans>

配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>car2-controller</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>
  
  <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext-*.xml</param-value>
  </context-param>
  
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <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:springmvc.xml</param-value>
  	</init-param>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <filter>
  	<filter-name>charset</filter-name>
  	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>utf-8</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>charset</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

关键部分:Service实现类

缓存是从service实现类时查询缓存:

package com.bjsxt.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.bjsxt.mapper.UserMapper;
import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;

@Service
public class UserServiceImpl implements UserService {
	@Autowired
	UserMapper userMapper;
	
	//加载redisTemplate对象
	@Autowired
	RedisTemplate<String, User>redisTemplate;
	
	@Override
	public User selectUser(Integer uid) {
		//通过redisTemplate绑定键
		BoundValueOperations<String,User> boundValueOps = redisTemplate.boundValueOps(String.valueOf(uid));
		//通过这个键取得相应的值(对象)
		User user = boundValueOps.get();
		//第一次查为空,之后查就一直会从缓存中读取数据
		if(user!=null) {
			return user;
		}
		//第一次查的情况会先从数据库查
		user=userMapper.selectUser(uid);
		//将查到的数据添加到Redis数据库中
		boundValueOps.set(user);
		return null;
	}

	@Override
	public void updateUser(User user) {
		BoundValueOperations<String,User> boundValueOps = redisTemplate.boundValueOps(String.valueOf(user.getUid()));
		//对相同的键进行值的覆盖,也就是对象的覆盖达到更新的效果
		boundValueOps.set(user);
		//更新数据库操作
		userMapper.updateUser(user);

	}

	@Override
	public void deleteUser(Integer uid) {
		//直接删除键为uid的这个对象
		redisTemplate.delete(String.valueOf(uid));
		userMapper.deleteUser(uid);

	}

}

这样就可以通过缓存来进行查询了

总结:  需要修改pom中的依赖   (Jedis   spring-data-jedis    jackson)

             添加cache.xml注解。

              修改service实现类修改代码,其余地方不动

 

二:使用注解来实现缓存机制:

与自己手写代码不同的是,

一:对cache.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:cache="http://www.springframework.org/schema/cache" 
    xsi:schemaLocation="                                               
            http://www.springframework.org/schema/beans    
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/cache    
            http://www.springframework.org/schema/cache/spring-cache.xsd  
          ">
          
    
     
     
     <!-- 实例化Redis的链接工厂 -->
     <bean id="connectionFactory" 
     	class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
     	<property name="hostName" value="192.168.25.100"></property>
     	<property name="port" value="6379"></property>
     	
     </bean>
     
     <!-- 实例化StringRedisSerializer,实现key的序列化
      StringRedisSerializer keySerializer=new StringRedisSerializer();
      -->
     <bean id="keySerializer" 
     	class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
     <!-- 实例化GenericJackson2JsonRedisSerializer,实现key的序列化 -->    
     <bean id="valueSerializer" 
     	class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer">
     </bean> 
     <!-- 实例化RedisTemplate对象 -->
     <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
     	<!-- 注入redis链接工厂对象 -->
     	<property name="connectionFactory" ref="connectionFactory"></property>
     	<!-- 给keySerializer注入值 
     		redisTemplate.setKeySerializer(keySerializer);
     	-->
     	<property name="keySerializer" ref="keySerializer"></property>
     	<!-- 给valueSerializer注入值 -->
     	<property name="valueSerializer" ref="valueSerializer"></property>
     </bean>
     
     
      <!-- 实例化cacheManager对象 -->
     <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
     	<!-- 注入RedisTemplate对象 -->
     	<constructor-arg name="redisOperations" ref="redisTemplate"></constructor-arg>
     </bean>
     <!-- 开启缓存注解驱动 -->    
     <cache:annotation-driven cache-manager="cacheManager"/>
     
     
     
</beans>

修改Service层的返回值(有注解是对方法的返回值进行缓存,所以更新不能再是无返回值的了。),在serviceImpl添加注解

这么做的优点是在不改动源代码的情况下就能够实现缓存机制。

实现类的代码:

package com.bjsxt.service.impl;

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.bjsxt.mapper.UsersMapper;
import com.bjsxt.pojo.Users;
import com.bjsxt.service.UsersService;

@Service
public class UsersServiceImpl implements UsersService {

	//注入Mapper
	@Autowired
	private UsersMapper usersMapper;
	 
	/***
	 * @Cacheable() 作用,缓存方法的返回值,该方法在第一次查询的时候进入
	 * cacheNames:给缓存起的名字
	 * key:表示redis数据库的键
	 */
	@Cacheable(cacheNames= {"users_cahce"},key="#id+''")
	@Override
	public Users loadUsersService(Integer id) {
		// TODO Auto-generated method stub
		System.out.println("=======查询数据库========");
		Users users= usersMapper.loadUsersMapper(id);
		return users;
	}

	@CacheEvict(cacheNames= {"users_cahce"},key="#id+''")
	@Override
	public void deleteUsersService(Integer id) {
		// TODO Auto-generated method stub
		usersMapper.deleteUsersMapper(id);	
	}

	/***
	 * @CachePut作用,缓存方法的返回值,每次都进入
	 * cacheNames:给缓存起的名字
	 * key:表示redis数据库的键
	 * 	   可以使用spring的el表达式,主要是获得方法的参数值
	 * 		如果是简单的数据类型String,Integer
	 *      	只有一个参数:#p0  或者  #argName
	 *      	只有一个参数:#p0,#p1  或者  #argName1,#argName2
	 *      如果参数是javabean对象:
	 *      	#javabean.属性名
	 *      	
	 */
	@CachePut(cacheNames= {"users_cahce"},key="#users.id+''")
	@Override
	public Users updateUsersService(Users users) {
		// TODO Auto-generated method stub
		System.out.println("=======更新redis缓存======");
		usersMapper.updateUsersMapper(users);
		
		return users;
	}

}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值