导读:本期聚焦于小伙伴创作的《Spring Boot中如何实现记录存在性检查与按需创建策略》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Spring Boot中如何实现记录存在性检查与按需创建策略》有用,将其分享出去将是对创作者最好的鼓励。

在Spring Boot的业务开发中,记录存在性检查与按需创建是非常常见的需求,比如用户注册时判断账号是否已存在、订单创建时判断对应商品库存记录是否存在等,核心逻辑是先查询目标记录是否存在,不存在则执行新增操作。

Spring Boot中如何实现记录存在性检查与按需创建策略

核心实现思路

整个策略的执行流程可以分为三步:首先根据唯一标识查询对应记录,然后判断查询结果是否为空,最后根据判断结果执行新增或者跳过操作。需要注意的是,在高并发场景下,简单的先查后插可能会出现重复创建的问题,需要额外做并发控制。

基于JPA的实现方案

JPA是Spring Boot默认的持久层框架,提供了丰富的查询和保存方法,实现该策略非常便捷。

1. 定义实体类

首先创建对应的实体类,假设我们需要操作用户表,实体类定义如下:

import javax.persistence.*;
import java.time.LocalDateTime;

@Entity
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String username;

    private String password;

    private LocalDateTime createTime;

    // 省略getter、setter方法
}

2. 定义Repository接口

在Repository中定义根据用户名查询的方法,JPA会根据方法名自动生成查询语句:

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

public interface UserRepository extends JpaRepository<User, Long> {
    // 根据用户名查询用户,返回Optional避免空指针
    Optional<User> findByUsername(String username);
}

3. 业务逻辑实现

在Service层编写存在性检查与按需创建的逻辑:

import org.springframework.stereotype.Service;
import java.time.LocalDateTime;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUserIfNotExists(String username, String password) {
        // 第一步:检查记录是否存在
        Optional<User> existUser = userRepository.findByUsername(username);
        if (existUser.isPresent()) {
            // 已存在则返回已有记录
            return existUser.get();
        }
        // 第二步:不存在则创建新记录
        User newUser = new User();
        newUser.setUsername(username);
        newUser.setPassword(password);
        newUser.setCreateTime(LocalDateTime.now());
        return userRepository.save(newUser);
    }
}

基于MyBatis的实现方案

如果项目使用MyBatis作为持久层框架,实现逻辑类似,只是查询和插入的操作需要通过Mapper来完成。

1. 定义Mapper接口

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;

@Mapper
public interface UserMapper {
    // 根据用户名查询用户
    List<User> selectByUsername(@Param("username") String username);

    // 插入新用户
    int insertUser(User user);
}

2. 编写XML映射文件

对应的Mapper XML文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://ipipp.com/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectByUsername" resultType="com.example.entity.User">
        SELECT id, username, password, create_time AS createTime
        FROM t_user
        WHERE username = #{username}
    </select>

    <insert id="insertUser" parameterType="com.example.entity.User">
        INSERT INTO t_user (username, password, create_time)
        VALUES (#{username}, #{password}, #{createTime})
    </insert>
</mapper>

3. 业务逻辑实现

import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class UserService {
    private final UserMapper userMapper;

    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public User createUserIfNotExists(String username, String password) {
        // 检查记录是否存在
        List<User> userList = userMapper.selectByUsername(username);
        if (!userList.isEmpty()) {
            return userList.get(0);
        }
        // 不存在则创建
        User newUser = new User();
        newUser.setUsername(username);
        newUser.setPassword(password);
        newUser.setCreateTime(LocalDateTime.now());
        userMapper.insertUser(newUser);
        return newUser;
    }
}

并发场景的问题与解决

上述方案在单线程场景下没有问题,但在高并发场景中,比如多个请求同时判断某个用户名不存在,然后同时执行插入操作,就会出现重复记录。常见的解决方式有两种:

  • 数据库唯一约束:在数据库表中给需要唯一判断的字段(比如username)添加唯一索引,这样即使并发插入,数据库会抛出唯一约束异常,我们捕获异常后返回已有记录即可。这种方式可靠性最高,建议优先使用。
  • 分布式锁:在查询和插入操作之前加分布式锁,保证同一时间只有一个请求能执行这个流程,适合分布式部署的场景。

基于唯一约束的优化实现

以JPA方案为例,添加唯一约束后,优化Service逻辑:

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User createUserIfNotExists(String username, String password) {
        // 先尝试查询
        Optional<User> existUser = userRepository.findByUsername(username);
        if (existUser.isPresent()) {
            return existUser.get();
        }
        // 查询不存在则尝试插入
        User newUser = new User();
        newUser.setUsername(username);
        newUser.setPassword(password);
        newUser.setCreateTime(LocalDateTime.now());
        try {
            return userRepository.save(newUser);
        } catch (DataIntegrityViolationException e) {
            // 插入失败说明已经被其他线程插入,重新查询返回
            return userRepository.findByUsername(username).orElseThrow(() -> new RuntimeException("用户不存在且插入失败"));
        }
    }
}

方案对比

不同实现方案的优缺点对比如下:

实现方案优点缺点适用场景
JPA先查后插代码简洁,框架自带支持高并发下有重复风险低并发、内部系统场景
MyBatis先查后插SQL可控,灵活性高高并发下有重复风险低并发、需要自定义SQL的场景
唯一约束+异常捕获并发安全,可靠性高需要处理异常逻辑高并发、对外服务场景

在实际开发中,建议优先给数据库对应字段添加唯一约束,再结合先查后插的逻辑,既能减少不必要的插入操作,又能保证并发场景下的数据正确性。

Spring_Boot记录存在性检查按需创建策略数据库操作修改时间:2026-06-13 16:49:02

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。