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

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:21   2392   0

学习指南:

我们在写一般的项目在使用增删改查,一般是直接操作数据库,但是我们可以换一个思路,如果当前时间段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 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP