最近在專案中使用到了 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); }