如何在Spring项目中使用jdbcTemplate插入一对多关联的数据库记录
Spring JdbcTemplate 一对多关联数据插入实现方案
你遇到的是典型的主从表关联插入场景,核心要求是保证事务一致性,整体逻辑为先插入主表获取主键,再批量插入关联子表数据,具体实现步骤如下:
前置说明:你提供的请求JSON修正后语法如下:
{ "name": "John", "courses": [ { "id": 1, "courseName": "Physics" }, { "id": 2, "courseName": "Chemistry" } ] }
默认业务场景为:主表student存储学生基础信息,子表student_course_rel存储学生和课程的关联关系,课程数据已提前存在course表中,如果需要同步新增课程,可对应调整逻辑即可。
实现步骤
1. 定义接收参数的DTO类
// 主参数DTO public class StudentDTO { private String name; private List<CourseDTO> courses; // 省略getter、setter方法 } // 课程子参数DTO public class CourseDTO { private Integer id; private String courseName; // 省略getter、setter方法 }
2. 业务层添加事务控制
涉及多步数据库写操作,必须开启事务保证数据一致性,直接在业务方法上添加@Transactional注解即可:
@Service public class StudentService { @Autowired private JdbcTemplate jdbcTemplate; // 所有异常都触发回滚 @Transactional(rollbackFor = Exception.class) public void addStudent(StudentDTO studentDTO) { // 插入逻辑写在该方法内 } }
3. 插入主表数据并获取自增主键
用GeneratedKeyHolder获取插入主表后生成的主键ID:
String insertStudentSql = "INSERT INTO student(name) VALUES (?)"; KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(connection -> { PreparedStatement ps = connection.prepareStatement(insertStudentSql, new String[]{"id"}); ps.setString(1, studentDTO.getName()); return ps; }, keyHolder); // 拿到生成的学生主键ID Long studentId = keyHolder.getKey().longValue();
4. 批量插入关联子表数据
用batchUpdate方法批量插入关联数据,性能远高于循环单条插入:
String insertRelSql = "INSERT INTO student_course_rel(student_id, course_id) VALUES (?, ?)"; List<CourseDTO> courseList = studentDTO.getCourses(); jdbcTemplate.batchUpdate(insertRelSql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setLong(1, studentId); ps.setInt(2, courseList.get(i).getId()); } @Override public int getBatchSize() { return courseList.size(); } });
特殊场景说明
如果业务需要同步新增课程数据而非关联已有课程,只需要在插入主表之后,先批量插入课程表拿到所有课程主键,再插入关联表即可,逻辑和上述流程完全一致。
内容的提问来源于stack exchange,提问作者Mahmood
相关产品推荐
相关产品推荐

