redis做mysql的缓存

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis做mysql的缓存相关的知识,希望对你有一定的参考价值。

参考技术A

redis缓存其实就是把经常访问的数据放到redis里面,用户查询的时候先去redis查询,没有查到就执行sql语句查询,同时把数据同步到redis里面。redis只做读操作,在内存中查询速度快。

使用redis做缓存必须解决两个问题,首先就是确定用何种数据结构存储来自mysql的数据;确定数据结构之后就是需要确定用什么标识来作为数据的key。
mysql是按照表存储数据的,这些表是由若干行组成。每一次执行select查询,mysql都会返回一个结果集,这个结果是由若干行组成的。redis有五种数据结构:列表list,哈希hash,字符串string,集合set,sorted set(有序集合),对比几种数据结构,string和hash是比较适合存储行的数据结构,可以把数据转成json字符串存入redis。

全量遍历键: keys pattern keys *
有人说 KEYS 相当于关系性数据的库的 select * ,在生产环境几乎是要禁用的

不管上面说的对不对, keys 肯定是有风险的。那我们就换一种方案,在存数据的时候。把数据的键存一下,也存到redis里面选hash类型,那么取的时候就可以直接通过这个hash获取所有的值,自我感觉非常好用!

springboot2.0+redis实现消息队列+redis做缓存+mysql

本博客仅供参考,本人实现没有问题。

1、环境

  先安装redis、mysql

 

2、springboot2.0的项目搭建(请自行完成),本人是maven项目,因此只需配置,获取相应的jar包,配置贴出。

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--配置mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--配置数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.0</version>
        </dependency>

        <!-- 配置redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-redis</artifactId>
            <version>1.4.3.RELEASE</version>
        </dependency>

        <!--  配置fastjson,用于redis转换-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.7</version>
        </dependency>
</dependencies>

  

3、如果相应的springboot可以正常启动,同时mysql和redis已安装,相应的数据库配置如下(#本人使用了mysql做数据库,redis做缓存和消息队列)。

#默认使用配置
spring:
  profiles:
    active: dev

#公共配置与profiles选择无关
mybatis:
  typeAliasesPackage: com.cn.commodity.entity
  mapperLocations: classpath:mapper/*.xml


---

#开发配置
spring:
  profiles: dev

  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
    username: root
    password: yang156122
    driver-class-name: com.mysql.jdbc.Driver
    # 使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource


#redis配置
redis:
  host: 127.0.0.1
  port: 6379
  password:
  pool:
    max-active: 100
    max-idle: 10
    max-wait: 100000
  timeout: 0

 

4、mysql数据库表如下图所示:

 

 

 

到此,环境和数据库都已准备。项目代码如下:

controller层

  1、UserController 

import com.alibaba.fastjson.JSONObject;
import com.cn.commodity.entity.User;
import com.cn.commodity.service.RedisService;
import com.cn.commodity.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Controller
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserService userService;

    @Autowired
    private RedisService redisService;

    private JSONObject json = new JSONObject();

    @RequestMapping("/showUser")
    @ResponseBody
    public User showUser(HttpServletRequest request){
        User user = null;
        int userId = Integer.parseInt(request.getParameter("id"));
        String result = redisService.get("user");
        if(result==null) {
            user = this.userService.getUserById(userId);
            System.out.println("来自数据库:"+user.getUserName());
            redisService.set("user",json.toJSONString(user));
        }else {
            user = json.parseObject(result, User.class);
            System.out.println("来自redis缓存:"+user.getUserName());
        }
        return user;
    }

    @RequestMapping("/showListUser")
    @ResponseBody
    public List<User> showListUser(HttpServletRequest request) {
        List<User> userList = null;
        String result = redisService.get("userList");
        if(result==null){
            userList = userService.selectAllUser();
            System.out.println("来自数据库:"+userList);
            redisService.set("userList",json.toJSONString(userList));
        }else {
            userList = json.parseArray(result, User.class);
            System.out.println("来自redis缓存:"+userList);
        }
        System.out.println(userList);
        return  userList;
    }
}

  2、PublisherController.java 

import com.cn.commodity.service.PublisherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("publisher")
public class PublisherController {

    @Autowired
    private PublisherService publisherService;

    @RequestMapping("{name}")
    public String sendMessage(@PathVariable("name") String name) {
        List<String> strLists = new ArrayList<>();
        for(int i =0 ;i<10;i++){
            String result =  publisherService.sendMessage(name+i);
            strLists.add(result);
        }
         return strLists.toString();
    }
}

 

config层

  1、RedisConfig.java

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableAutoConfiguration
public class RedisConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.pool")
    public JedisPoolConfig getRedisConfig(){
        JedisPoolConfig config = new JedisPoolConfig();
        return config;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis")
    public JedisConnectionFactory getConnectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setUsePool(true);
        JedisPoolConfig config = getRedisConfig();
        factory.setPoolConfig(config);
        return factory;
    }

    @Bean
    public RedisTemplate<?, ?> getRedisTemplate() {
        JedisConnectionFactory factory = getConnectionFactory();
        RedisTemplate<?, ?> template = new StringRedisTemplate(factory);
        return template;
    }

}

  2、SubscriberConfig.java 

import com.cn.commodity.entity.Receiver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

@Configuration
@AutoConfigureAfter({Receiver.class})
public class SubscriberConfig {

    /**
     * 消息监听适配器,注入接受消息方法,输入方法名字 反射方法
     *
     * @param receiver
     * @return
     */
    @Bean
    public MessageListenerAdapter getMessageListenerAdapter(Receiver receiver) {
        return new MessageListenerAdapter(receiver, "receiveMessage"); //当没有继承MessageListener时需要写方法名字
    }

    /**
     * 创建消息监听容器
     *
     * @param redisConnectionFactory
     * @param messageListenerAdapter
     * @return
     */
    @Bean
    public RedisMessageListenerContainer getRedisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter messageListenerAdapter) {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        redisMessageListenerContainer.addMessageListener(messageListenerAdapter, new PatternTopic("TOPIC_USERNAME"));
        return redisMessageListenerContainer;
    }
}

 

3、Dao层

  1、UserDao.java 

import com.cn.commodity.entity.User;

import java.util.List;

public interface UserDao {
    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);

    List<User> selectAllUser();
}

 

4、entity层

  1、Receiver.java 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

@Component
public class Receiver implements MessageListener {
    private static Logger logger = LoggerFactory.getLogger(Receiver.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void onMessage(Message message, byte[] pattern) {
        RedisSerializer<String> valueSerializer = redisTemplate.getStringSerializer();
        String deserialize = valueSerializer.deserialize(message.getBody());
        logger.info("收到的mq消息" + deserialize);
    }
}

  2、User.java

public class User {
    private Integer id;

    private String userName;

    private String password;

    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName == null ? null : userName.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName=\'" + userName + \'\\\'\' +
                ", password=\'" + password + \'\\\'\' +
                ", age=" + age +
                \'}\';
    }
}

 

5、Service层

  1、UserService.java

import com.cn.commodity.entity.User;

import java.util.List;

public interface UserService {
    /**
     * 通过id查找用户
     * @param userId
     * @return
     */
    public User getUserById(int userId);

    /**
     * 添加用户
     * @param record
     * @return
     */
    boolean addUser(User record);

    /**
     * 查询所有用户
     * @return
     */
    List<User> selectAllUser();

}

  2、RedisService.java

public interface RedisService {

    /**
     * set存数据
     * @param key
     * @param value
     * @return
     */
    boolean set(String key, String value);

    /**
     * get获取数据
     * @param key
     * @return
     */
    String get(String key);

    /**
     * 设置有效天数
     * @param key
     * @param expire
     * @return
     */
    boolean expire(String key, long expire);

    /**
     * 移除数据
     * @param key
     * @return
     */
    boolean remove(String key);

}

  3、PublisherService .java

public interface PublisherService {

     String sendMessage(String name);
}

 

6、ServiceImp实现层

  1、UserServiceImpl.java 

import com.cn.commodity.dao.UserDao;
import com.cn.commodity.entity.User;
import com.cn.commodity.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao;

    @Override
    public User getUserById(int userId) {
        return userDao.selectByPrimaryKey(userId);
    }
    @Override
    public boolean addUser(User record){
        boolean result = false;
        try {
            userDao.insertSelective(record);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }

    @Override
    public List<User> selectAllUser() {
        return userDao.selectAllUser();
    }

}

  2、RedisServiceImpl.java

import com.cn.commodity.service.RedisService;
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.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Service("redisService")
public class RedisServiceImpl implements RedisService {

    @Resource
    private RedisTemplate<String, ?> redisTemplate;

    @Override
    public boolean set(final String key, final String value) {
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                connection.set(serializer.serialize(key), serializer.serialize(value));
                return true;
            }
        });
        return result;
    }

    @Override
    public String get(final String key) {
        String result = redisTemplate.execute(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                byte[] value = connection.get(serializer.serialize(key));
                return serializer.deserialize(value);
            }
        });
        return result;
    }

    @Override
    public boolean expire(final String key, long expire) {
        return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    @Override
    public boolean remove(final String key) {
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
                connection.del(key.getBytes());
                return true;
            }
        });
        return result;
    }
}

  3、PublisherServiceImpl.java

import com.cn.commodity.service.PublisherService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service("publisherService")
public class PublisherServiceImpl implements PublisherService {
    private static final Logger log = LoggerFactory.getLogger(PublisherServiceImpl.class);
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public String sendMessage(String name) {
        try {
            redisTemplate.convertAndSend("TOPIC_USERNAME", name);
            return "消息发送成功了";

        } catch (Exception e) {
            e.printStackTrace();
            return "消息发送失败了";
        }
    }

}

  

7、UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cn.commodity.dao.UserDao" >
    <resultMap id="BaseResultMap" type="com.cn.commodity.entity.User" >
        <id column="id" property="id" jdbcType="INTEGER" />
        <result column="user_name" property="userName" jdbcType="VARCHAR" />
        <result column="password" property="password" jdbcType="VARCHAR" />
        <result column="age" property="age" jdbcType="INTEGER" />
    </resultMap>
    <sql id="Base_Column_List" >
        id, user_name, password, age
    </sql>
    <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
        select
        <include refid="Base_Column_List" />
        from user_t
        where id = #{id,jdbcType=INTEGER}
    </select>
    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
        delete from user_t
        where id = #{id,jdbcType=INTEGER}
    </delete>
    <insert id="insert" parameterType="com.cn.commodity.entity.User" >
        insert into user_t (id, user_name, password,
        age)
        values (#{id,jdbcType=INTEGER}, #{userName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
        #{age,jdbcType=INTEGER})
    </insert>
    <insert id="insertSelective" parameterType="com.cn.commodity.entity.User" >
        insert into user_t
        <trim prefix="(" suffix=")" suffixOverrides="," >
            <if test="id != null" >
                id,
            </if>
            <if test="userName != null" >
                user_name,
            </if>
            <if test="password != null" >
                password,
            </if>
            <if test="age != null" >
                age,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides="," >
            <if test="id != null" >
                #{id,jdbcType=INTEGER},
            </if>
            <if test="userName != null" >
                #{userName,jdbcType=VARCHAR},
            </if>
            <if test="password != null" >
                #{password,jdbcType=VARCHAR},
            </if>
            <if test="age != null" >
                #{age,jdbcType=INTEGER},
            </if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="com.cn.commodity.entity.User" >
        update user_t
        <set >
            <if test="userName != null" >
                user_name = #{userName,jdbcType=VARCHAR},
            </if>
            <if test="password != null" >
                password = #{password,jdbcType=VARCHAR},
            </if>
            <if test="age != null" >
                age = #{age,jdbcType=INTEGER},
            </if>
        </set>
        where id = #{id,jdbcType=INTEGER}
    </update>
    <update id="updateByPrimaryKey" parameterType="com.cn.commodity.entity.User" >
        update user_t
        set user_name = #{userName,jdbcType=VARCHAR},
        password = #{password,jdbcType=VARCHAR},
        age = #{age,jdbcType=INTEGER}
        where id = #{id,jdbcType=INTEGER}
    </update>

    <select id="selectAllUser" resultMap="BaseResultMap" >
        select
        <include refid="Base_Column_List" />
        from user_t
    </select>

</mapper>

 

8、主程序CommodityApplication

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@MapperScan("com.cn.commodity.dao")
@SpringBootApplication
public class CommodityApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(CommodityApplication.class, args);
    }
}

注意:@MapperScan("com.cn.commodity.*")是错误的,必要要到dao包,即@MapperScan("com.cn.commodity.dao"),本人在开发过程就犯了这个错误,找了很久。

到此,所有代码都已贴上,准确无误。

 

开始运行:

1、启动redis:

  redis-server.exe redis.windows.conf #服务端

  redis-cli.exe  #客服端

2、执行

  http://localhost:8080/publisher/杨123   #这个是现实消息队列

  http://localhost:8080/user/showUser?id=1  #这个是实现redis做缓存

 

 

以上是关于redis做mysql的缓存的主要内容,如果未能解决你的问题,请参考以下文章

php redis做mysql的缓存,怎么异步redis同步到mysql数据库?

怎样使用redis缓存,java代码

springboot2.0+redis实现消息队列+redis做缓存+mysql

Redis三大缓存问题(穿透击穿雪崩)

记一次对以redis做缓存,异步写mysql的系统做性能测试经验

mysql读写分离和用Redis做缓存,这两种方案有啥异同