本文节选自《Spring 5核心原理》
1 实现思路概述
1.1 从ResultSet说起
说到ResultSet,有Java开发经验的“小伙伴”自然最熟悉不过了,不过我相信对于大多数人来说也算是“最熟悉的陌生人”。从ResultSet取值操作大家都会,比如:
private static List select(String sql) {
List result = new ArrayList<>();
Connection con = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
//1. 加载驱动类
Class.forName("com.mysql.jdbc.Driver");
//2. 建立连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");
//3. 创建语句集
pstm = con.prepareStatement(sql);
//4. 执行语句集
rs = pstm.executeQuery();
while (rs.next()){
Member instance = new Member();
instance.setId(rs.getLong("id"));
instance.setName(rs.getString("name"));
instance.setAge(rs.getInt("age"));
instance.setAddr(rs.getString("addr"));
result.add(instance);
}
//5. 获取结果集
}catch (Exception e){
e.printStackTrace();
}
//6. 关闭结果集、关闭语句集、关闭连接
finally {
try {
rs.close();
pstm.close();
con.close();
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
以上我们在没有使用框架以前的常规操作。随着业务和开发量的增加,在数据持久层这样的重复代码出现频次非常高。因此,我们就想到将非功能性代码和业务代码进行分离。我们首先想到将ResultSet封装数据的代码逻辑分离,增加一个mapperRow()方法,专门处理对结果的封装,代码如下:
private static List select(String sql) {
List result = new ArrayList<>();
Connection con = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
//1. 加载驱动类
Class.forName("com.mysql.jdbc.Driver");
//2. 建立连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");
//3. 创建语句集
pstm = con.prepareStatement(sql);
//4. 执行语句集
rs = pstm.executeQuery();
while (rs.next()){
Member instance = mapperRow(rs,rs.getRow());
result.add(instance);
}
//5. 获取结果集
}catch (Exception e){
e.printStackTrace();
}
//6. 关闭结果集、关闭语句集、关闭连接
finally {
try {
rs.close();
pstm.close();
con.close();
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
private static Member mapperRow(ResultSet rs, int i) throws Exception {
Member instance = new Member();
instance.setId(rs.getLong("id"));
instance.setName(rs.getString("name"));
instance.setAge(rs.getInt("age"));
instance.setAddr(rs.getString("addr"));
return instance;
}
但在真实的业务场景中,这样的代码逻辑重复率实在太高,上面的改造只能应用Member类,换一个实体类又要重新封装,聪明的程序员肯定不会通过纯体力劳动给每一个实体类写一个mapperRow()方法,一定会想到代码复用方案。我们不妨来做这样一个改造。
先创建Member类:
package com.gupaoedu.vip.orm.demo.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Entity
@Table(name="t_member")
@Data
public class Member implements Serializable {
@Id private Long id;
private String name;
private String addr;
private Integer age;
@Override
public String toString() {
return "Member{" +
"id=" + id +
", name='" + name + '\'' +
", addr='" + addr + '\'' +
", age=" + age +
'}';
}
}
优化JDBC操作:
public static void main(String[] args) {
Member condition = new Member();
condition.setName("Tom");
condition.setAge(19);
List<?> result = select(condition);
System.out.println(Arrays.toString(result.toArray()));
}
private static List<?> select(Object condition) {
List