JdbcTemplate、NamedParameterJdbcTemplate 执行数据插入后返回主键写法

一、简单需求

某业务操作,在执行数据保存后,需要查询具体的的数据信息,供二次确认。 从后台开发角度而言,转换成:插入1条数据库表记录后,如何返回当前插入数据的主键

二、准备工作

下面我们以JdbcTemplate、NamedParameterJdbcTemplate 为例来进行说明,为简单起见,我们以内存数据库H2
来进行演示。

首先,新建springboot工程,引入jdbc相关模块,在配置文件中引入数据源相关配置。

三、JdbcTemplate 实现


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.transaction.annotation.Transactional;

import com.fly.template.bean.StudentVO;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Transactional
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class JdbcTemplateTest2
{
    @Autowired
    JdbcTemplate jdbcTemplate;
    
    @BeforeEach
    public void init()
    {
        // execute可以执行所有SQL语句,因为没有返回值,一般用于执行DDL语句
        jdbcTemplate.execute("drop table if exists student");
        jdbcTemplate.execute("create table student(id bigint NOT NULL AUTO_INCREMENT, stu_name varchar(50), primary key(id))");
        jdbcTemplate.execute("insert into student(stu_name) values('Jack')");
        jdbcTemplate.execute("insert into student(stu_name) values('Phil')");
        jdbcTemplate.execute("insert into student(stu_name) values('Jenny')");
        
        // batchUpdate
        jdbcTemplate.batchUpdate("insert into student(stu_name) values(?)", Arrays.asList(new Object[][] {{"Tom"}, {"Jerry"}}));
        log.info("::: init success!!");
        log.info(">>>>> before: {}", jdbcTemplate.queryForObject("select count(*) from student", Long.class));
    }
    
    @AfterEach
    public void after()
    {
        log.info(">>>>> after : {}", jdbcTemplate.queryForObject("select count(*) from student", Long.class));
    }
    
    /**
     * 查询主键
     */
    @Test
    public void testQueryPk()
    {
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(new PreparedStatementCreator()
        {
            @Override
            public PreparedStatement createPreparedStatement(Connection conn)
                throws SQLException
            {
                // 预处理,注意参数PreparedStatement.RETURN_GENERATED_KEYS
                PreparedStatement ps = conn.prepareStatement("insert into student(stu_name) values(?)", PreparedStatement.RETURN_GENERATED_KEYS);
                ps.setString(1, "Chery");
                return ps;
            }
        }, keyHolder);
        log.info("pk: {}", keyHolder.getKey().longValue());
        
        // lambda写法
        jdbcTemplate.update((conn) -> {
            PreparedStatement ps = conn.prepareStatement("insert into student(stu_name) values(?)", PreparedStatement.RETURN_GENERATED_KEYS);
            ps.setString(1, "Chery");
            return ps;
        }, keyHolder);
        log.info("pk: {}", keyHolder.getKey().longValue());
    }
    
    /**
     * 查询非自增主键
     */
    @Test
    public void testQueryPk2()
    {
        jdbcTemplate.execute("drop table if exists student2");
        jdbcTemplate.execute("create table student2(id bigint NOT NULL, stu_name varchar(50), primary key(id))");
        
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update((conn) -> {
            PreparedStatement ps = conn.prepareStatement("insert into student2(id, stu_name) values(?,?)", PreparedStatement.RETURN_GENERATED_KEYS);
            ps.setInt(1, 11);
            ps.setString(2, "Chery");
            return ps;
        }, keyHolder);
        log.info("pk: {}", keyHolder.getKey().longValue());
    }
}
    

四、NamedParameterJdbcTemplate 实现


import java.util.Arrays;
import java.util.Date;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.transaction.annotation.Transactional;

import com.fly.template.bean.StudentVO;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Transactional
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class NamedJdbcTemplateTest
{
    @Autowired
    NamedParameterJdbcTemplate namedJdbcTemplate;
    
    @BeforeEach
    public void init()
    {
        /****** JdbcOperations实际就是JdbcTemplate ******/
        JdbcOperations jdbcOperations = namedJdbcTemplate.getJdbcOperations();
        
        jdbcOperations.execute("drop table if exists student");
        jdbcOperations.execute("create table student(id int not null AUTO_INCREMENT, stu_name varchar(50), create_date datetime, primary key(id))");
        
        // batchUpdate
        jdbcOperations.batchUpdate("insert into student(stu_name, create_date) values(?, CURRENT_TIMESTAMP())", Arrays.asList(new Object[][] {{"Jack"}, {"Phil"}, {"Jenny"}}));
        
        jdbcOperations.execute("delete from student where id > 100");
        log.info("before::: init success!!");
        log.info(">>>>> before: {}", namedJdbcTemplate.getJdbcTemplate().queryForObject("select count(*) from student", Long.class));
    }
    
    @AfterEach
    public void after()
    {
        log.info(">>>>> after : {}", namedJdbcTemplate.getJdbcTemplate().queryForObject("select count(*) from student", Long.class));
    }
    

    @Test
    public void testQueryPk()
    {
        // 查询主键
        KeyHolder keyHolder = new GeneratedKeyHolder();
        namedJdbcTemplate.update("insert into student(stu_name, create_date) values(:stuName, :time)", new MapSqlParameterSource("stuName", "jackson").addValue("time", new Date()), keyHolder);
        log.info("pk: {}", keyHolder.getKey().longValue());
        
        namedJdbcTemplate.update("insert into student(stu_name, create_date) values(:stuName, :time)", new BeanPropertySqlParameterSource(new StudentVO().setStuName("jackson").setTime(new Date())), keyHolder);
        log.info("pk: {}", keyHolder.getKey().longValue());
    }
}

五、结论

从上面的实现过程可以看出,NamedParameterJdbcTemplate的实现方式更加简洁,言简意赅 ,建议采用!

六、源码放送

https://gitcode.com/00fly/springboot-demo/


有任何问题和建议,都可以向我提问讨论,大家一起进步,谢谢!

-over-

### 使用 `namedParameterJdbcTemplate` 实现瀚高数据库插入数据并处理主键自增 为了在瀚高数据库中使用 `NamedParameterJdbcTemplate` 插入数据并实现主键自增,可以采用序列(sequence)机制来生成唯一的主键值。以下是具体的操作方式: #### 创建序列 首先,在瀚高数据库中创建一个用于生成主键的序列。这可以通过执行如下SQL语句完成: ```sql CREATE SEQUENCE seq_hg_example START WITH 1 INCREMENT BY 1; ``` 此命令会建立名为 `seq_hg_example` 的序列,它将从1开始每次增加1。 #### 编写Java代码 接着编写Java程序中的DAO层逻辑,利用Spring框架下的 `NamedParameterJdbcTemplate` 来操作数据库。这里展示了一个简单的例子说明如何做: ```java import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; public class ExampleDao { private final NamedParameterJdbcTemplate jdbcTemplate; public void insertExampleRecord(String firstName, String lastName){ String sql = "INSERT INTO example_table (example_id, first_name, last_name) VALUES (:id,:firstName, :lastName)"; MapSqlParameterSource parameters = new MapSqlParameterSource(); Long idValue = getNextSequenceValue(); // 获取下一个序列号作为新记录的ID parameters.addValue("id", idValue); parameters.addValue("firstName", firstName); parameters.addValue("lastName", lastName); int rowsAffected = this.jdbcTemplate.update(sql,parameters); } private long getNextSequenceValue(){ String queryForNextVal = "SELECT seq_hg_example.NEXTVAL FROM DUAL"; return this.jdbcTemplate.queryForObject(queryForNextVal,Long.class); } } ``` 上述代码片段展示了怎样通过调用 `getNextSequenceValue()` 方法获得新的唯一标识符,并将其赋给即将被插入的新纪录。注意这里的表名和字段名称应根据实际应用情况进行调整[^5]。 对于某些场景下可能还需要考虑事务管理以及异常处理等问题,确保整个过程的安全性和可靠性。另外需要注意的是不同版本之间可能存在差异,因此建议查阅官方文档确认最新特性和支持情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值