美文网首页
Springboot2.0 + jpa + redis缓存

Springboot2.0 + jpa + redis缓存

作者: 树蜂 | 来源:发表于2019-01-24 15:39 被阅读0次

    本文基于Springboot2.0,使用mysql数据库,通过jpa实现orm,再用redis实现数据库的缓存。
    目录
    1、项目结构
    2、环境配置
    3、代码
    4、测试
    5、参考文章


    1、项目结构

    项目结构

    2、环境配置

    1)pom.xml

    <dependencies>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
            
            <!-- 引入Redis缓存 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            
        </dependencies>
    

    2)application.yml
    注意:

    • 创建mysql数据库名称为 jpa_redis
    • redis 端口、
    • mysql 数据库账号密码
    server:
      port: 8081
     # context-path: /
    spring:
      redis:
        host: localhost
        port: 6379
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/jpa_redis
        username: root
        password: abc
      jpa:
        hibernate:
          ddl-auto: update
        show-sql: true
    

    3、代码

    1)SpringBootRedisApplication
    注意添加 @EnableCaching

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cache.annotation.EnableCaching;
    
    @SpringBootApplication
    @EnableCaching
    public class SpringBootRedisApplication
    {
        public static void main(String[] args)
        {
            SpringApplication.run(SpringBootRedisApplication.class, args);
        }
    }
    

    2)RedisConfig

    import org.springframework.cache.CacheManager;
    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.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.cache.RedisCacheWriter;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializationContext;
    
    import java.lang.reflect.Method;
    import java.time.Duration;
    
    /**
     * Redis 缓存配置类
     */
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport
    {
    
        /**
         * 缓存对象集合中,缓存是以 key-value 形式保存的。
         * 当不指定缓存的 key 时,SpringBoot 会使用 SimpleKeyGenerator 生成 key。
         */
    //  @Bean
        public KeyGenerator wiselyKeyGenerator()
        {
            // key前缀,用于区分不同项目的缓存,建议每个项目单独设置
            final String PRE_KEY = "test";  
            final char sp = ':';
            return new KeyGenerator()
            {
                @Override
                public Object generate(Object target, Method method, Object... params)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.append(PRE_KEY);
                    sb.append(sp);
                    sb.append(target.getClass().getSimpleName());
                    sb.append(sp);
                    sb.append(method.getName());
                    for (Object obj : params)
                    {
                        sb.append(sp);
                        sb.append(obj.toString());
                    }
                    return sb.toString();
                }
            };
        }
    
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory factory)
        {
            // 更改值的序列化方式,否则在Redis可视化软件中会显示乱码。默认为JdkSerializationRedisSerializer
            RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer());
            RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration
                    .defaultCacheConfig()
                    .serializeValuesWith(pair)      // 设置序列化方式
                    .entryTtl(Duration.ofHours(1)); // 设置过期时间
    
            return RedisCacheManager
                    .builder(RedisCacheWriter.nonLockingRedisCacheWriter(factory))
                    .cacheDefaults(defaultCacheConfig).build();
        }
    }
    

    3)实体类User
    注意实现 Serializable 接口

    import java.io.Serializable;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /**
     * 用户实体
     */
    @Entity
    @Table(name = "user")
    public class User implements Serializable {
        private static final long serialVersionUID = 1l;
        
        @Id
        @GeneratedValue
        private Integer id;
    
        @Column(length = 20)
        private String userName;
    
        @Column(length = 20)
        private String password;
    
        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;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    4)UserDao

    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    
    import com.cun.entity.User;
    
    /**
     * 用户 dao 接口
     */
    public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>
    {
    
    }
    

    5)UserService

    import java.util.List;
    
    import com.cun.entity.User;
    
    public interface UserService
    {
        List<User> getAllUsers();
    
        User findById(Integer pId);
        
        void clearAllUserCache();
        
        void clear(Integer pId);
    }
    

    6)UserServiceImpl
    cacheNamesvalue 作用一样

    import java.util.List;
    import java.util.Optional;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.CacheConfig;
    import org.springframework.cache.annotation.CacheEvict;
    import org.springframework.cache.annotation.Cacheable;
    import org.springframework.stereotype.Service;
    
    import com.cun.dao.UserDao;
    import com.cun.entity.User;
    import com.cun.service.UserService;
    
    @Service
    @CacheConfig(cacheNames = "userService")
    public class UserServiceImpl implements UserService
    {
        @Autowired
        private UserDao userDao;
    
        /**
         * cacheNames 与 value 定义一样,设置了 value 的值,则类的 cacheNames 配置无效。<br>
         * 使用 keyGenerator ,注意是否在config文件中定义好。
         * @see com.cun.service.UserService#getAllUsers()
         */
        @Override
        @Cacheable(value = "getAllUsers")
    //  @Cacheable(value = "getAllUsers", keyGenerator = "wiselyKeyGenerator")
        public List<User> getAllUsers()
        {
            return userDao.findAll();
        }
        
        /**
         * 执行该函数时,将清除以 userService 的缓存,【cacheNames = "userService"】<br>
         * 也可指定清除的key 【@CacheEvict(value="abc")】
         */
        @CacheEvict(value = "getAllUsers")
        public void clearAllUserCache()
        {
            
        }
        
        /**
         * key ="#p0" 表示以第1个参数作为 key
         */
        @Override
        @Cacheable(value="user", key ="#p0")
        public User findById(Integer pId)
        {
            Optional<User> _User = userDao.findById(pId);
            
            return Optional.ofNullable(_User).get().orElse(null);
        }
        
        @CacheEvict(value="user", key ="#p0")
        public void clear(Integer pId)
        {
            
        }
    }
    

    7)UserController

    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.cun.entity.User;
    import com.cun.service.UserService;
    
    
    /**
     * 参考 https://blog.csdn.net/larger5/article/details/79696562
     */
    @RestController
    public class UserController
    {
        @Autowired
        private UserService userService;
    
        // http://localhost:8081/all
        @GetMapping("/all")
        public List<User> getAllUsers()
        {
            System.out.println("只有第一次才会打印sql语句");
            return userService.getAllUsers();
        }
    
        // http://localhost:8081/findById?id=1
        @GetMapping("/findById")
        public User findById(@RequestParam(name = "id")Integer pId)
        {
            return userService.findById(pId);
        }
        
        // http://localhost:8081/clear
        @GetMapping("/clear")
        public void clear()
        {
            userService.clearAllUserCache();
        }
        
        // http://localhost:8081/clearOne?id=1
        @GetMapping("/clearOne")
        public void clear(@RequestParam(name = "id")Integer pId)
        {
            userService.clear(pId);
        }
    }
    

    4、测试

    启动服务后,可以看到 jpa 框架自动生成 user 表


    user表

    1)添加测试数据

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.*;
    
    import com.cun.SpringBootRedisApplication;
    import com.cun.dao.UserDao;
    import com.cun.entity.User;
    
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest(classes=SpringBootRedisApplication.class)
    public class AddTester {
        @Autowired
        private UserDao userDao;
        @Test
        public void test()
        {
            User _User = new User();
            _User.setPassword("123");
            _User.setUserName("老王");
            userDao.save(_User);
            
            User _User2 = new User();
            _User2.setPassword("456");
            _User2.setUserName("小李");
            userDao.save(_User2);
        }
    }
    

    2)缓存测试
    访问 http://localhost:8081/all ,可看到缓存数据

    image.png

    访问 http://localhost:8081/findById?id=1,可看到缓存数据

    image.png

    则调用 http://localhost:8081/clear 后,getAllUsers 的缓存将被清除;
    则调用 http://localhost:8081/clearOne?id=1 后,user::1 的缓存将被清除。

    5、参考文章

    相关文章

      网友评论

          本文标题:Springboot2.0 + jpa + redis缓存

          本文链接:https://www.haomeiwen.com/subject/hewyjqtx.html