8

SpringBoot集成Redis以及解决高并发问题

 3 years ago
source link: http://www.lzhpo.com/article/52
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

工程结构图:

提前说明:

注意:JavaBean必须实现序列化,不然数据无法存入Redis。
public class User implements Serializable

1.SpringBoot集成Redis实现缓存

首先需要引入SpringBoot的Redis依赖:

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>

关键代码:

@Servicepublic class UserServiceImpl implements UserService {    @Autowired    private UserMapper userMapper;    /**注入SpringBoot自动配置好的redisTemplate**/    //注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!    @Autowired    private RedisTemplate<Object,Object> redisTemplate;    @Override    public List<User> findAllUser() {        //字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)        RedisSerializer redisSerializer = new StringRedisSerializer();        redisTemplate.setKeySerializer(redisSerializer);        //查询缓存        List<User> userList = (List<User>) redisTemplate.opsForValue().get("AllUser");        if (userList == null){            //缓存为空,查询数据库            userList = userMapper.findAllUser();            //把查询出来的数据放入Redis中            redisTemplate.opsForValue().set("AllUser",userList);        }        return userList;    }    @Override    public User findUserById(Integer id) {        //字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)        RedisSerializer redisSerializer = new StringRedisSerializer();        redisTemplate.setKeySerializer(redisSerializer);        //查询缓存        User user = (User) redisTemplate.opsForValue().get("User");        if (user == null){            //缓存为空,查询数据库            user = userMapper.findUserById(id);            //把查询出来的数据放入到Redis中            redisTemplate.opsForValue().set("User",user);        }        return user;    }}

总结思路:

1.字符串序列化(名字)。
2.查询Redis缓存,如果为空,查询数据库。
3.将查询出来的数据放入Redis缓存中。
4.返回结果。

如果一万个人同时访问(高并发条件下),上面的代码是否有什么不恰当?

2.高并发下SpringBoot集成Redis缓存的问题

关键代码:

@Servicepublic class UserServiceImpl implements UserService {    @Autowired    private UserMapper userMapper;    /**注入SpringBoot自动配置好的redisTemplate**/    //注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!    @Autowired    private RedisTemplate<Object,Object> redisTemplate;    /**     * 测试高并发问题     * @param name     * @return     */    @Override    public List<User> findUserByName(String name) {        //字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)        RedisSerializer redisSerializer = new StringRedisSerializer();        redisTemplate.setKeySerializer(redisSerializer);        List<User> userList = (List<User>) redisTemplate.opsForValue().get("findByLikeName");        if (userList == null){            synchronized (this){                //查询Redis缓存                userList = (List<User>) redisTemplate.opsForValue().get("findByLikeName");                if (userList == null){                    //查询数据库                    userMapper.findUserByName(name);                    System.out.println("查询的数据库...");                    //将查询的结果放入Redis缓存中                    redisTemplate.opsForValue().set("findUserByName",userList);                }else {                    System.out.println("查询的缓存...");                }            }            System.out.println("查询的缓存...");        }        return userList;    }}

Controller:

@Controllerpublic class UserController {    @Autowired    private UserService userService;    /**     * 高并发问题     * @param name     * @return     */    @RequestMapping("/findUserByName/{name}")    @ResponseBody    public List<User> findUserByName(@PathVariable("name") String name){        Runnable runnable = new Runnable() {            @Override            public void run() {                userService.findUserByName(name);            }        };        ExecutorService executorService = Executors.newFixedThreadPool(25);        for (int i = 0; i < 10000; i++) {            executorService.submit(runnable);        }        List<User> userList = userService.findUserByName(name);        return userList;    }}

可以看到查询数据的次数非常非常多,这样对数据库的压力十分大,甚至我查询不出结果!

3.解决高并发问题

关键代码:

@Servicepublic class UserServiceImpl implements UserService {    @Autowired    private UserMapper userMapper;    /**注入SpringBoot自动配置好的redisTemplate**/    //注意:spring boot帮我们注入的redisTemplate类,泛型里面只能写 <String, String>、<Object, Object>,不能一个String一个Object!    @Autowired    private RedisTemplate<Object,Object> redisTemplate;    /**     * 测试解决高并发问题     * @param id     * @return     */    @Override    public User findUserById(Integer id) {        //字符串的序列化器(这里只将key序列化--->AllUser),为了在Redis管理工具更好看一点(AllUser不会出现前面的类似乱码的)        RedisSerializer redisSerializer = new StringRedisSerializer();        redisTemplate.setKeySerializer(redisSerializer);        //查询Redis缓存        User user = (User) redisTemplate.opsForValue().get("User");        //解决高并发问题:双重监测锁        if (user == null){            synchronized (this){                //查询Redis缓存                user = (User) redisTemplate.opsForValue().get("User");                if (user == null){                    //缓存为空,查询数据库                    user = userMapper.findUserById(id);                    System.out.println("查询的数据库...");                    //把查询出来的数据放入到Redis中                    redisTemplate.opsForValue().set("findUserById",user);                }else {                    System.out.println("查询的缓存...");                }            }        }else {            System.out.println("查询的缓存...");        }        return user;    }}

Controller:

@Controllerpublic class UserController {    @Autowired    private UserService userService;    /**     * 测试解决高并发问题     * @param id     * @return     */    @RequestMapping("/findUserById/{id}")    @ResponseBody    public User findUserById(@PathVariable("id") Integer id){        //多线程,该线程调用底层根据id查询学生的方法        Runnable runnable = new Runnable() {            @Override            public void run() {                userService.findUserById(id);            }        };        //多线程测试高并发条件下内网穿透问题        ExecutorService executorService = Executors.newFixedThreadPool(25); //线程池根据CPU来选择适当的值        for (int i = 0; i < 10000; i++) {            //提交线程runnable方法            executorService.submit(runnable);        }        User user = userService.findUserById(id);        return user;    }}

或者配置好Druid数据源:

发现只查询了一次数据库!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK