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

问题描述

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

解决办法

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

话不多说,上代码

pom.xml 依赖补充

        org.springframework.boot
        spring-boot-starter-data-redis
application.yml文件中redis配置
redis:
  host: 127.0.0.1
  port: 6379
  timeout: 10
  poolMaxTotal: 1000
  poolMaxIdle: 500
  poolMaxWait: 500
UserMapper.java
import com.example.demo.entity.User;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

    int add(User user);

    User queryByName(String name);
}
 UserMapper.xml



    

    
      INSERT INTO "USER" (id,name, age)
      VALUES (SYS_GUID(),#{name},#{age})
    
RedisService类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


@Service
public class RedisService {

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 加锁
     * @param key
     * @param value
     * @param expireTime
     * @return
     */
    public boolean lock(String key, String value, Long expireTime) {
        Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value);
        if (expireTime != null && expireTime > 0) {
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
        }
        return success != null && success;
    }

    /**
     * 释放锁
     * @param key
     */
    public void unlock(String key) {
        redisTemplate.opsForValue().getOperations().delete(key);
    }

    /**
     * 根据key删除信息
     * @param key
     */
    public void deleteStr(String key) {
        redisTemplate.delete(key);
    }
}
@bean配置 解决redis内容乱码,为了方便,我这边直接在启动类中配置

    @Bean
    @SuppressWarnings("all")
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用jackson的序列化方式
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
controller类

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

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.service.RedisService;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisService redisService;

    @PostMapping("/addTest")
    public void addTest(@RequestBody User user) throws Exception {

        //todo 该功能的状态校验
        //1.判断该用户在redis是否存在
        if (!redisService.lock("addUser", String.valueOf(System.currentTimeMillis()), 15L)) {
            throw new Exception("正在操作中");
        }
        try {
            //2.逻辑处理
            User user1 = userMapper.queryByName(user.getName());
            if (user1 != null) {
                throw new Exception("该用户" + user.getName() + "已存在!");
            }
            for (int i = 0; i < 1000; i++) {
                for (int j = 0; j < 1000; j++) {
                    logger.info("i*j={}", i * j);
                }
            }
            userMapper.add(user);
        } catch (Exception e) {
            redisService.deleteStr("addUser");
            throw e;
        } finally {
            redisService.unlock("addUser");
        }
    }
}

测试结果

一用户信息操作结果:

springboot中如何同时操作同一功能_第1张图片

另一用户操作结果:

springboot中如何同时操作同一功能_第2张图片

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

springboot中如何同时操作同一功能_第3张图片

你可能感兴趣的:(工作中遇到的问题,spring,boot,后端,java)