• springboot中如何同时操作同一功能


    问题描述

    测试阶段,由于存在某一功能的同时操作,该功能还是入库逻辑,此时若不进行处理,会造成插入表中多条重复数据,为此该问题需要修复。

    解决办法

    在接口开始进行对是否存在某个key值的判断,若不存在,则插入一条到redis中并加锁;若存在,则提示“正在处理中”;若中间出现逻辑处理异常,则需要对该key值删除;最后进行对锁的释放;

    话不多说,上代码

    pom.xml 依赖补充
    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-data-redisartifactId>
    4. dependency>
    application.yml文件中redis配置
    1. redis:
    2. host: 127.0.0.1
    3. port: 6379
    4. timeout: 10
    5. poolMaxTotal: 1000
    6. poolMaxIdle: 500
    7. poolMaxWait: 500
    UserMapper.java
    1. import com.example.demo.entity.User;
    2. import org.apache.ibatis.annotations.Mapper;
    3. @Mapper
    4. public interface UserMapper {
    5. int add(User user);
    6. User queryByName(String name);
    7. }
     UserMapper.xml
    1. "1.0" encoding="utf-8"?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="com.example.demo.mapper.UserMapper">
    6. <select id="queryByName" resultMap="userResult">
    7. select id,name,age from "USER"
    8. where name=#{name}
    9. select>
    10. <insert id="add" parameterType="com.example.demo.entity.User">
    11. INSERT INTO "USER" (id,name, age)
    12. VALUES (SYS_GUID(),#{name},#{age})
    13. insert>
    14. mapper>
    RedisService类
    1. import org.springframework.beans.factory.annotation.Autowired;
    2. import org.springframework.data.redis.core.RedisTemplate;
    3. import org.springframework.stereotype.Service;
    4. import java.util.concurrent.TimeUnit;
    5. @Service
    6. public class RedisService {
    7. @Autowired
    8. RedisTemplate redisTemplate;
    9. /**
    10. * 加锁
    11. * @param key
    12. * @param value
    13. * @param expireTime
    14. * @return
    15. */
    16. public boolean lock(String key, String value, Long expireTime) {
    17. Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value);
    18. if (expireTime != null && expireTime > 0) {
    19. redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
    20. }
    21. return success != null && success;
    22. }
    23. /**
    24. * 释放锁
    25. * @param key
    26. */
    27. public void unlock(String key) {
    28. redisTemplate.opsForValue().getOperations().delete(key);
    29. }
    30. /**
    31. * 根据key删除信息
    32. * @param key
    33. */
    34. public void deleteStr(String key) {
    35. redisTemplate.delete(key);
    36. }
    37. }
    @bean配置 解决redis内容乱码,为了方便,我这边直接在启动类中配置
    1. @Bean
    2. @SuppressWarnings("all")
    3. public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
    4. RedisTemplate template = new RedisTemplate();
    5. template.setConnectionFactory(factory);
    6. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    7. ObjectMapper om = new ObjectMapper();
    8. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    9. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    10. jackson2JsonRedisSerializer.setObjectMapper(om);
    11. StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    12. // key采用String的序列化方式
    13. template.setKeySerializer(stringRedisSerializer);
    14. // hash的key也采用jackson的序列化方式
    15. template.setHashKeySerializer(jackson2JsonRedisSerializer);
    16. // value序列化方式采用jackson
    17. template.setValueSerializer(jackson2JsonRedisSerializer);
    18. // hash的value序列化方式采用jackson
    19. template.setHashValueSerializer(jackson2JsonRedisSerializer);
    20. template.afterPropertiesSet();
    21. return template;
    22. }
    controller类

    该程序对新增用户功能同时操作的模拟,补充redis中key的判断,具体开发逻辑或内容可以视情况而定!

    1. import com.example.demo.entity.User;
    2. import com.example.demo.mapper.UserMapper;
    3. import org.slf4j.Logger;
    4. import org.slf4j.LoggerFactory;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.web.bind.annotation.PostMapping;
    7. import org.springframework.web.bind.annotation.RequestBody;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RestController;
    10. import com.example.demo.service.RedisService;
    11. import java.util.List;
    12. @RestController
    13. @RequestMapping("/user")
    14. public class UserController {
    15. private static final Logger logger = LoggerFactory.getLogger(UserController.class);
    16. @Autowired
    17. private UserMapper userMapper;
    18. @Autowired
    19. private RedisService redisService;
    20. @PostMapping("/addTest")
    21. public void addTest(@RequestBody User user) throws Exception {
    22. //todo 该功能的状态校验
    23. //1.判断该用户在redis是否存在
    24. if (!redisService.lock("addUser", String.valueOf(System.currentTimeMillis()), 15L)) {
    25. throw new Exception("正在操作中");
    26. }
    27. try {
    28. //2.逻辑处理
    29. User user1 = userMapper.queryByName(user.getName());
    30. if (user1 != null) {
    31. throw new Exception("该用户" + user.getName() + "已存在!");
    32. }
    33. for (int i = 0; i < 1000; i++) {
    34. for (int j = 0; j < 1000; j++) {
    35. logger.info("i*j={}", i * j);
    36. }
    37. }
    38. userMapper.add(user);
    39. } catch (Exception e) {
    40. redisService.deleteStr("addUser");
    41. throw e;
    42. } finally {
    43. redisService.unlock("addUser");
    44. }
    45. }
    46. }

    测试结果

    一用户信息操作结果:

    另一用户操作结果:

    等待2分钟,该用户继续操作该数据,会提示“该用户已存在!”

  • 相关阅读:
    java读取CSV文件
    Leetcode 135. 分发糖果
    软件工程开发和文档流程(及概要设计+详细设计)
    maven+mybatis—实现数据库中图书信息的增删改查
    如何在 Android Studio 中重命名软件包名称
    .NET开发中合理使用对象映射库,简化和提高工作效率
    【Linux】Linux中的基本概念
    使用WebApi+Vue3从0到1搭建《权限管理系统》:二、搭建JWT系统鉴权
    【MySQL系列】如何在MySQL中使用触发器?MySQL触发器详解
    详细介绍项目开发中多种常用的分布式锁的实现以及分析比较
  • 原文地址:https://blog.csdn.net/qq_37342720/article/details/134300334