大部分網(wǎng)上的 Spring 教程大多講解的是 SSM 框架展东,其中的 M 現(xiàn)在指的是 MyBatis 這個第三方 ORM 框架,在我看來,MyBatis 有它的優(yōu)越性,如 SQL 語句與業(yè)務代碼分離俊抵,業(yè)務邏輯處理很靈活等。但是在小型業(yè)務系統(tǒng)開發(fā)時坐梯,由于 SSM 框架定義過于規(guī)范徽诲,開發(fā)具體功能時,會寫很多接口吵血,而真正的業(yè)務邏輯得不到較優(yōu)的處理谎替,呆板的框架應用反而適得其反。
本文主要介紹 SpringJDBC 的基礎操作践瓷,方便研發(fā)人員快速的實現(xiàn)數(shù)據(jù)的增刪改查院喜,而不僅僅拘泥于繁重的、各種框架組合而成的項目之中晕翠。
SpringJDBC 封裝了基礎的 JDBC 操作喷舀,讓我們不用去關心 獲取驅動、建立連接淋肾、關閉連接等非業(yè)務操作硫麻,讓我們更加專注于業(yè)務的實現(xiàn)。
本文將對 SpringJDBC 的用法進行介紹樊卓,文主要內容如下:
- 基本的數(shù)據(jù)操作
- 自增主鍵的獲取
1. 基本的數(shù)據(jù)操作
1.1 更改
更改 主要使用的是 update 方法
- 重載方法:主要包括三種拿愧,按需選擇,下面展示的從簡單到復雜碌尔。
sql = "insert into customer(name,age)values (?,?)";
int rows = jdbcTemplate.update(sql,"周杰倫",35);
int rows1 = jdbcTemplate.update(sql,new Object[]{"周杰倫",35});
int rows2 = jdbcTemplate.update(sql,new Object[]{"周杰倫",35},new int[]{Types.VARCHAR,Types.DECIMAL}); // 顯式指定數(shù)據(jù)類型
- 批量更改:一次性執(zhí)行多條 update 語句浇辜,使用 batchUpdate 方法
- jdbcTemplate.batchUpdate(String[] sql); 固定參數(shù)值
- jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter()); 可變參數(shù)值
String sql1 = "insert into customer(NAME,AGE) values (1,1)";
String sql2 = "insert into customer(NAME,AGE) values (1,1)";
String sql3 = "insert into customer(NAME,AGE) values (1,1)";
String[] strings = new String[]{sql1,sql2,sql3};
int[] a = jdbcTemplate.batchUpdate(strings); // 固定參數(shù)的多條 SQL 語句組成一個數(shù)組傳入
System.out.println(Arrays.toString(a));
sql = "insert into customer(NAME,AGE) values (?,?)";
final List<String> list = new ArrayList<String>(){};
list.add("1");list.add("2");list.add("3");
int[] b = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { // 帶可變參數(shù)的 SQL 語句傳入
public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
preparedStatement.setString(1,list.get(i));
preparedStatement.setString(2,list.get(i));
}
public int getBatchSize() {
return list.size();
}
});
System.out.println(Arrays.toString(b));
1.2 查詢
查詢 主要使用的是 query、queryForXX 等函數(shù)唾戚,而 queryForXX 系列底層其實調用的是 query 方法柳洋,故這里只介紹通過 query 方法查詢數(shù)據(jù)。
query 有多個重載方法叹坦,例如傳入固定參數(shù)的 SQL 語句熊镣,傳入可變參數(shù)的 SQL 語句等等,語法類似上面介紹的 update 方法募书,這里介紹兩種帶回調方法的查詢語句:
(1) void query(String sql, RowCallbackHandler rch)
使用 RowCallbackHandler 既可以返回單行結果绪囱,也可以返回多行結果。Spring 會對查詢的結果集逐行調用 processRow 方法莹捡,用戶不用關心怎么讀取下一行數(shù)據(jù)的問題鬼吵。
sql = "select CUST_ID,NAME,AGE from customer where CUST_ID = ?";
final Customer customer = new Customer();
// 查詢單行數(shù)據(jù)
jdbcTemplate.query(sql, new Object[]{1}, new RowCallbackHandler() {
public void processRow(ResultSet resultSet) throws SQLException {
customer.setCUST_ID(Integer.parseInt(resultSet.getString("CUST_ID")));
customer.setNAME(resultSet.getString("NAME"));
customer.setAGE(Integer.parseInt(resultSet.getString("AGE")));
}
});
System.out.println(customer.toString()); // Customer{CUST_ID=1, NAME='張三', AGE=12}
sql = "select CUST_ID,NAME,AGE from customer";
final List<Customer> customerList = new ArrayList<Customer>();
final Customer customer1 = new Customer();
// 查詢到多行數(shù)據(jù),代碼與上面沒有區(qū)別道盏,唯一的不同就是將結果集存入 List
jdbcTemplate.query(sql, new RowCallbackHandler() {
public void processRow(ResultSet resultSet) throws SQLException {
customer1.setCUST_ID(Integer.parseInt(resultSet.getString("CUST_ID")));
customer1.setNAME(resultSet.getString("NAME"));
customer1.setAGE(Integer.parseInt(resultSet.getString("AGE")));
customerList.add(customer1);
}
});
System.out.println(customerList);// [Customer{CUST_ID=38, NAME='3', AGE=3}, Customer{CUST_ID=38, NAME='3', AGE=3}]
(2) <T> T queryForObject(String sql, RowMapper<T> rowMapper)
使用 RowMapper 處理結果集而柑,它直接返回的是 List文捶,相比于上面荷逞,我們不用手動將對象添加到 List 中
sql = "select CUST_ID,NAME,AGE from customer";
List<Customer> customerList = jdbcTemplate.query(sql, new RowMapper<Customer>() {
public Customer mapRow(ResultSet resultSet, int i) throws SQLException {
Customer customer = new Customer();
customer.setCUST_ID(Integer.parseInt(resultSet.getString("CUST_ID")));
customer.setNAME(resultSet.getString("NAME"));
customer.setAGE(Integer.parseInt(resultSet.getString("AGE")));
return customer;
}
});
System.out.println(customerList); // [Customer{CUST_ID=38, NAME='3', AGE=3}, Customer{CUST_ID=38, NAME='3', AGE=3}]
(3) 方法 a 與方法 b 的使用場景與注意事項
- RowCallbackHandler 接口的實現(xiàn)類是可以有狀態(tài)媒咳,即在多線程環(huán)境下,可能會有線程安全的問題种远。
下面代碼就展示了其實現(xiàn)類 RowCountCallbackHandler 打印結果集行數(shù)的示例涩澡,在多線程環(huán)境中,若行數(shù)發(fā)生變化坠敷,下面的結果可能不會一致妙同。而 RowMapper 實現(xiàn)類沒有這種情況。
RowCountCallbackHandler countCallbackHandler = new RowCountCallbackHandler();
jdbcTemplate.query("select * from customer",countCallbackHandler);
System.out.println(countCallbackHandler.getRowCount());
- 當處理大結果集時膝迎, RowMapper 是將結果集所有數(shù)據(jù)放到 List<T> 中粥帚,這會占用大量 JVM 內存。RowCallbackHandler 接口內的 processRow() 方法則是一邊獲取數(shù)據(jù)一邊處理限次。RowMapper 是先獲取再處理芒涡,RowCallbackHandler 邊獲取邊處理。
2. 自增主鍵的獲取
在數(shù)據(jù)庫層面卖漫,一個表往往會有一個主鍵來唯一標識這一行數(shù)據(jù)费尽。
新增記錄時,返回新增記錄對應的自增主鍵值羊始,即返回的該列屬性包含兩個旱幼,一個是自增,另一個是主鍵突委。
SpringJDBC 提供了對自增主鍵獲取的方法柏卤,插入數(shù)據(jù)時,返回插入數(shù)據(jù)的主鍵匀油。
定義 KeyHolder 對象即可完成上述功能缘缚,步驟如下:
- 執(zhí)行 statement 語句時,指定綁定主鍵
connection.prepareStatement(sql1,PreparedStatement.RETURN_GENERATED_KEYS)
final String sql1 = "insert into customer(name,age)values(?,?)";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(sql1,PreparedStatement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1,"suiyia");
preparedStatement.setString(2,"30");
return preparedStatement;
}
},keyHolder);
System.out.println(keyHolder.getKey().toString());
- keyHolder 的返回形式
- Number getKey() 主鍵是數(shù)值類型钧唐,單列忙灼、一行
- Map<String,Object> getKeys復合類型,多列钝侠、一行
- List<Map<String,Object>> getKeyList 復合類型该园、多列、多行
3. 小結
本文只是對 SpringJDBC 的基本常用操作做了簡單介紹帅韧,之所以介紹 SpringJDBC里初,是因為在快速開發(fā)的后臺系統(tǒng)中,沒有足夠的時間去寫接口等忽舟,這種方式在小型簡單的系統(tǒng)開發(fā)時效率更高双妨。但在大型復雜的系統(tǒng)研發(fā)中淮阐,踏實寫接口,遵守框架的開發(fā)規(guī)范是很有必要的刁品。