最近在项目中使用到了 Spring 的 JdbcTemplate, 中间遇到了好多坑, 所以花一些时间对 JdbcTemplate 的使用做了一个总结, 方便以后自己的查看。文章中贴出来的API都是经过测试的, 可以放心大胆的拿去用。
概述
JdbcTemplate主要提供4种方法:
- call()方法: 用于执行存储过程、存储函数
- execute()方法: 可以执行任何SQL语句, 一般用于DDL语句
- update()和batchUpdate()方法: 分别对应单个更新、批量更新的语句执行
- query()和queryForXXX()方法: 用于单查、列表查询
前两种使用的一般较少, 本次主要介绍后两种方法的使用。
单个更新
@Test public void insert() { String sql = "insert into pass_user (name,age,gender,birthday,create_time,update_time) values (?,?,?,?,?,?)"; jdbcTemplate.update(sql, "张三丰", 18, "male", Instant.now().toEpochMilli(), Instant.now().toEpochMilli(), Instant.now().toEpochMilli()); }
JdbcTemplate的大部分方法都和上面类似, 参数列表的最右边经常是一个可变参。
批量更新
@Test public void batchInsert() { String sql = "insert into pass_user (name,age,gender,birthday,create_time,update_time) values (?,?,?,?,?,?)"; List<Object[]> args = new ArrayList<>(); for (int i = 0; i < 5; i++) { args.add(new Object[]{"张三丰", 18, "male", Instant.now().toEpochMilli(), Instant.now().toEpochMilli(), Instant.now().toEpochMilli()}); } jdbcTemplate.batchUpdate(sql, args); }
获取count、sum等聚合函数返回的唯一值
/** * 只能接受String,Integer这种单列类型的实体,否则汇报异常 */ @Test public void queryForCount1() { String sql = "select count(1) from pass_user where id > ?"; Integer count = jdbcTemplate.queryForObject(sql, Integer.class, 300000); LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", count); }
在JdbcTemplate中 queryForObject() 方法的文档说明中, 指定了该方法只能接受单个记录的某一列值, 否则报 IncorrectResultSizeDataAccessException 异常。
获取单个记录的某一列值
/** * 只能接受String,Integer这种单列类型的实体,否则汇报异常 */ @Test public void queryForObject1() { String sql = "select NAME from pass_user where id = ?"; String name = jdbcTemplate.queryForObject(sql, String.class, 30);//查询结果空集时会报EmptyResultDataAccessException异常 LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", name); }
另外 queryForObject() 方法在查询结果集为空集也就是null值时, 会报 EmptyResultDataAccessException 异常。
获取单个记录的所有列值
通过RowMapper映射, 我们可以通过 queryForObject() 方法获取单个记录的所有列值, 映射方法有两种。
如下, PassUser实体类不用实现RowMapper接口, 但是实体类的属性名必须和表中的列名符合驼峰命名匹配,能一一对应起来, 如果两者不一致,则需要在sql语句中给对应的列取一个别名。
public class PassUser { private Long id; private String name; private Integer age; private String gender; private Long birthday; private Long createTime; private Long updateTime; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Long getBirthday() { return birthday; } public void setBirthday(Long birthday) { this.birthday = birthday; } public Long getCreateTime() { return createTime; } public void setCreateTime(Long createTime) { this.createTime = createTime; } public Long getUpdateTime() { return updateTime; } public void setUpdateTime(Long updateTime) { this.updateTime = updateTime; } @Override public String toString() { return "PassUser{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", birthday=" + birthday + ", createTime=" + createTime + ", updateTime=" + updateTime + '}'; } }
/** * 可以自动进行驼峰匹配 */ @Test public void queryForObject2() { String sql = "select * from pass_user where id = ?"; RowMapper<PassUser> rowMapper = new BeanPropertyRowMapper<>(PassUser.class); PassUser passUser = jdbcTemplate.queryForObject(sql, rowMapper, 180);//查询结果空集时会报EmptyResultDataAccessException异常 LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", passUser); }
第二种方式需要实体类实现RowMapper接口,覆写 mapRow() 方法
public class UserEntity implements RowMapper<UserEntity> { private Long id; private String name; private Integer age; private String gender; private Long birthday; private Long createTime; private Long updateTime; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Long getBirthday() { return birthday; } public void setBirthday(Long birthday) { this.birthday = birthday; } public Long getCreateTime() { return createTime; } public void setCreateTime(Long createTime) { this.createTime = createTime; } public Long getUpdateTime() { return updateTime; } public void setUpdateTime(Long updateTime) { this.updateTime = updateTime; } @Override public String toString() { return "UserEntity{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + ", birthday=" + birthday + ", createTime=" + createTime + ", updateTime=" + updateTime + '}'; } @Override public UserEntity mapRow(ResultSet rs, int rowNum) throws SQLException { UserEntity userEntity = new UserEntity(); userEntity.setName(rs.getString("name")); userEntity.setAge(rs.getInt("age")); userEntity.setGender(rs.getString("gender")); userEntity.setBirthday(rs.getLong("birthday")); userEntity.setCreateTime(rs.getLong("create_time")); userEntity.setUpdateTime(rs.getLong("update_time")); return userEntity; } }
/** * 实体类需要实现接口,覆写方法 */ @Test public void queryForObject3() { String sql = "select * from pass_user where id = ?"; UserEntity userEntity = jdbcTemplate.queryForObject(sql, new UserEntity(), 180);//查询结果空集时会报EmptyResultDataAccessException异常 LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", userEntity); }
获取多个记录的某一列值
/** * 实体类需要实现接口,覆写方法 */ @Test public void queryForList1() { String sql = "select name from pass_user where id < ?"; List<String> names = jdbcTemplate.queryForList(sql, String.class, 50);//只能查询单列属性值集合 LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", names); }
获取多个记录的所有列值
/** * 实体类需要实现接口,覆写方法 */ @Test public void queryForList2() { String sql = "select * from pass_user where id < ?"; List<UserEntity> userEntityList = jdbcTemplate.query(sql, new UserEntity(), 0); LOGGER.info("[" + Thread.currentThread().getStackTrace()[1].getMethodName() + "] {}", userEntityList); }