zoukankan      html  css  js  c++  java
  • SpringBoot + Mybatis + Redis 整合入门项目

    这篇文章我决定一改以往的风格,以幽默风趣的故事博文来介绍如何整合 SpringBoot、Mybatis、Redis。

    很久很久以前,森林里有一只可爱的小青蛙,他迈着沉重的步伐走向了找工作的道路,结果发现许多的招聘要求都要会 Redis。

    小青蛙就想啥是 Redis 呢,为什么要用 Redis 呢?难道是因为 Mysql 的币格不够高吗,小青蛙点开了收藏已久的网站:十万个为什么

    发现原来随着使用网站的用户越来越多,表中的数据也越来越多,查询速度越来越慢。

    MySql 的性能遇到了瓶颈,所以许多网站都用 Redis 作缓存。

    然而能作缓存的不仅只有 Redis,还有 Memcache,那为什么要用 Redis 呢?

    1、性能方面:它们都是将数据存放在内存中,所以性能基本相似。

    2、数据类型方面:Redis 支持五种数据数据类型:字符串、散列、列表、集合、有序集合,而 Memcache 仅仅支持简单的 key-value。

    3、数据持久化方面:Redis 可以通过 RDB快照、AOF日志 等方式进行数据持久化,但是 Memcache 不可以。

    4、数据备份方面:Redis  支持 master-slave 主从模式的数据备份。

    在了解到许多 Redis 的好处后,小青蛙已经迫不及待的想了解它了。

    为了更好的使用 Redis,了解 Redis 的五种数据类型适应场景是很有必要的。

    1、String 类型:一个 key 对应一个 value,而 value 不仅仅是 String,也可以是数字、甚至是一个序列化对象。

    2、Hash 类型:一个 key 对应 多个 field,一个 field 对应 yige value,实际上该类型最适合存储序列化对象。

               key 相当于数据库表名字,field  相当于主键,value 也就是序列化对象。

    3、List 类型:简单的字符串列表,按照插入顺序排序,该结构类似于数据结构中的双向链表,可以从头部插也可以从尾部插。

    4、Set 类型:它是字符串集合,只不过它是无序的且不存在重复的字符串,但是它可以实现 交集、并集、差集。

    5、ZSet 类型:它也是字符串集合,它和 Set 的区别是该集合的元素存在 score 属性,按照 score 属性的高低排序。可以应用在排行榜上。

    值得注意的是,不要习惯性的认为 Redis 字符串只能存字符串,实际上,它可以存储任何序列化后的对象,当然也可以读出来。

    小青蛙知道了 Redis 的五种数据类型应用场景后,迫不及待的想要实践它了。

    为了知道如何让它作为缓存,以及如何操作数据,小青蛙打开了珍藏已久的视频网站来学习:青蛙爱学习

    在该视频网站上,小青蛙沉迷其中无法自拔,额,呸呸。缓过神来,发现了一个很好的视频。小青蛙幽默的说:快进我的收藏夹吃灰去吧。

    小青蛙向来都不是一个收藏从未停止,学习从未开始的青蛙。它模仿着视频建了一个 SpringBoot 项目。

    此时,小青蛙想为什么要勾选 Lombok 呢,因为它可以简化类,并且提供了 log 等功能。

    之后小青蛙为了连上 Mysql 和 Redis 就开始配置 application.properties 文件:

    # 数据源配置
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=UTC&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=lemon@mango
    
    # Redis 配置
    spring.redis.database=0
    spring.redis.host=127.0.0.1
    spring.redis.port=6379
    spring.redis.password=
    spring.redis.lettuce.pool.max-active=8
    spring.redis.lettuce.pool.max-wait=-1
    spring.redis.lettuce.pool.max-idle=8
    spring.redis.lettuce.pool.min-idle=0
    spring.redis.lettuce.shutdown-timeout=100

    配置好该文件后,需要 redisTemplate 模板 Bean,因为自动配置的 redisTemplate Bean 没有提供序列化操作:(因为是入门版的,所以这样最好理解)

    package com.demo.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @Configuration
    public class RedisConfig {
        
        @Bean
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
                    template.setConnectionFactory(factory);
                    GenericJackson2JsonRedisSerializer genericJsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
                    template.setKeySerializer(new StringRedisSerializer());
                    template.setValueSerializer(genericJsonRedisSerializer);
                    template.setHashKeySerializer(genericJsonRedisSerializer);
                    template.setHashValueSerializer(genericJsonRedisSerializer);
                    template.afterPropertiesSet();
                    return template;
        }
    }

    至此就整合完成了,小青蛙心想这就完事了?!!!,不信?那就来演示一下:(先建一个简单的类测试一下)

    package com.test.serviceImpl;
    
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.beans.factory.annotation.Autowired;
    import lombok.extern.slf4j.Slf4j;
    
    @Service
    @Slf4j
    public class JustForTest {
        
        @Autowired
        private RedisTemplate redisTemplate;
        
        public void test(String username) {
            
            if(redisTemplate.hasKey(username)) {
                log.info((String)redisTemplate.opsForValue().get(username));
                log.info("get value from redis");
            }else {
                String password = "password";
                log.info(password);
                log.info("get value from mysql");
                log.info("set value to redis");
                redisTemplate.opsForValue().set(username, password);
            }
            
        }
    
    }
    package com.test;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.beans.factory.annotation.Autowired;
    import com.test.serviceImpl.JustForTest;
    
    @SpringBootTest
    class TestApplicationTests {
        
        @Autowired
        private JustForTest justFortest;
    
        @Test
        void contextLoads() {
            justFortest.test("username");
        }
    }

    哦嚯,报错了,原来是 pom.xml 中少了 commons.pool 依赖,咱给它加上:

            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>

    再来一次:

    再再来一次:

    可以看到确实存入 Redis 了,小青蛙便去 Redis 数据库中看看有没有:

    事实证明确实整合完毕了,小青蛙仍然表示不解,说好的是SpringBoot、Mybatis、Redis的整合呢,怎么只看到 Redis 的?

    小青蛙刚这么想,然后视频里就说了,心急吃不了热豆腐,需要慢慢来。紧接着,小青蛙就看到了完整的项目结构:

    为了让青蛙们只关注有关整合的部分,视频里仅仅只给出 serviceImpl 中的代码:

    package com.demo.serviceImpl;
    
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.beans.factory.annotation.Autowired;
    import com.demo.pojo.SimpleUser;
    import com.demo.dao.SimpleUserDao;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import lombok.extern.slf4j.Slf4j;
    
    @Service
    @Slf4j
    @SuppressWarnings({"rawtypes","unchecked"})
    public class SimpleUserServiceImpl implements UserDetailsService {
    
        @Autowired
        private RedisTemplate redisTemplate;
        @Autowired
        private SimpleUserDao userDao;
        @Override 
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            // TODO Auto-generated method stub
            if(redisTemplate.opsForHash().hasKey("user",username)) {
                SimpleUser user = (SimpleUser)redisTemplate.opsForHash().get("user",username);
                return new User(user.getUsername(),user.getPassword(),user.getAuthorities());
            }else {
                SimpleUser user = userDao.findUserByUsername(username);
                if(user != null) {
                    redisTemplate.opsForHash().put("user", "username", user);
                    return new User(user.getUsername(),user.getPassword(),user.getAuthorities());
                }else {
                    throw new UsernameNotFoundException("Username or Password is not correct");
                }
            }
        }
        
        public int addSimpleUser(SimpleUser user) {
            user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
            return userDao.addSimpleUser(user);
        }
    }

    和上面测试的简单小例子相似,仅仅是把 String 换成了对象。小青蛙对 Mysql 的表结构和Redis中存入的数据比较感心趣:

    由于对 String 类型带有 " 符号,所以需要对其进行转义。

    小青蛙是一个有分享精神的蛙,每次它觉得有价值的东西,它都会分享给它的朋友们,项目地址为:GitHub

    小青娃逐渐的弄懂了怎么去进行整合,但是它还是不太明白为什么这样就能整合,也就是 know how but don't konw why!

    小青蛙知道:万事开头难,但它不知道的是,后面也很难...从此,小青蛙踏上了探寻源码的道路!呱呱呱......

  • 相关阅读:
    c#中开发ActiveX的学习笔记
    [转]李战大师悟透delphi 第七章 组织你的模块
    在网页中实现QQ的屏幕截图功能
    vs.net的调试小技巧之#define debug(适合新手)
    socket中的byte消息格式设计
    [转]李战大师悟透delphi第五章 包
    [转]李战大师悟透delphi 第九章 多层体系结构
    [转]李战大师悟透delphi第一章 delphi的原子世界
    重温delphi之控制台程序:Hello World!
    silverlight中的socket编程注意事项
  • 原文地址:https://www.cnblogs.com/M-Anonymous/p/13158049.html
Copyright © 2011-2022 走看看