You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+JPA下避免CommandLineRunner重复初始化数据库数据

解决Spring Boot初始化数据重复问题的几种方案

方案1:执行前检查数据是否存在(最直接简单)

在保存初始化数据前,通过Repository的查询方法判断数据是否已存在,仅当数据不存在时才执行创建和保存逻辑。这种方式无需额外表或配置,适配你的场景。

修改DataLoader类代码如下:

@Component
@RequiredArgsConstructor
public class DataLoader implements CommandLineRunner {

    private final RoleRepository roleRepository;
    private final UserRepository userRepository;

    @Override
    public void run(String... args) throws Exception {
        // 检查user角色是否已存在
        if (!roleRepository.existsByRoleName("user")) {
            Role userRole = new Role();
            userRole.setRoleName("user");
            userRole.setDescription("test user");
            roleRepository.save(userRole);
            
            // 检查目标用户是否已存在(用唯一标识phoneNumber判断)
            if (!userRepository.existsByPhoneNumber("xx-232323232323")) {
                User user = new User();
                user.setFirstName("UserFirstName");
                user.setLastName("UserLastName");
                user.setPhoneNumber("xx-232323232323");
                user.addRoleToUser(userRole);
                userRepository.save(user);
            }
        }
    }
}

注意:需要在RoleRepository和UserRepository中添加对应的查询方法,比如existsByRoleName(String roleName)、existsByPhoneNumber(String phoneNumber),Spring Data JPA会自动实现这些方法。

方案2:使用初始化标记表

创建一张专门记录初始化状态的表,比如init_status,启动时先查询该表是否有初始化完成的记录,无记录则执行初始化并插入标记。适合初始化逻辑复杂、需要明确标记完成状态的场景。

  1. 创建标记表(可通过schema.sql或实体类实现):
CREATE TABLE IF NOT EXISTS init_status (
    id INT PRIMARY KEY AUTO_INCREMENT,
    init_key VARCHAR(50) UNIQUE NOT NULL,
    is_completed BOOLEAN NOT NULL DEFAULT FALSE,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
  1. 修改DataLoader类:
@Component
@RequiredArgsConstructor
public class DataLoader implements CommandLineRunner {

    private final RoleRepository roleRepository;
    private final UserRepository userRepository;
    private final EntityManager entityManager;

    @Override
    public void run(String... args) throws Exception {
        // 查询是否已执行过基础数据初始化
        String checkSql = "SELECT COUNT(*) FROM init_status WHERE init_key = 'base_data_init' AND is_completed = TRUE";
        Long count = (Long) entityManager.createNativeQuery(checkSql).getSingleResult();
        
        if (count == 0) {
            // 执行初始化逻辑
            Role userRole = new Role();
            userRole.setRoleName("user");
            userRole.setDescription("test user");
            roleRepository.save(userRole);
            
            User user = new User();
            user.setFirstName("UserFirstName");
            user.setLastName("UserLastName");
            user.setPhoneNumber("xx-232323232323");
            user.addRoleToUser(userRole);
            userRepository.save(user);
            
            // 标记初始化完成
            String insertSql = "INSERT INTO init_status (init_key, is_completed) VALUES ('base_data_init', TRUE)";
            entityManager.createNativeQuery(insertSql).executeUpdate();
            entityManager.flush();
        }
    }
}

方案3:用data.sql处理关联映射(解决你的顾虑)

如果想用data.sql初始化数据,关联映射可通过SQL直接处理:

  • 用自增ID时,借助数据库的自增ID获取函数(MySQL用1029338,PostgreSQL用currval())
  • 手动指定ID时,直接插入对应关联值即可

示例MySQL的data.sql:

-- 插入角色,避免重复
INSERT INTO role (role_name, description) 
SELECT 'user', 'test user' 
WHERE NOT EXISTS (SELECT 1 FROM role WHERE role_name = 'user');

-- 插入用户,避免重复
INSERT INTO user (first_name, last_name, phone_number)
SELECT 'UserFirstName', 'UserLastName', 'xx-232323232323'
WHERE NOT EXISTS (SELECT 1 FROM user WHERE phone_number = 'xx-232323232323');

-- 插入用户角色关联(多对多中间表),避免重复
INSERT INTO user_role (user_id, role_id)
SELECT u.id, r.id
FROM user u, role r
WHERE u.phone_number = 'xx-232323232323' 
  AND r.role_name = 'user'
  AND NOT EXISTS (
      SELECT 1 FROM user_role ur 
      WHERE ur.user_id = u.id AND ur.role_id = r.id
  );

注意:data.sql默认在Spring Boot启动时执行,可通过spring.sql.init.mode配置执行时机,同样需要用WHERE NOT EXISTS避免重复插入。


内容的提问来源于stack exchange,提问作者Syed Iftekharuddin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:44:56