Spring數據訪問之自定義ORM框架
1.目標
理解什麼是ORM框架,並簡單自定義一個ORM。
2.定義
什麼是ORM框架?
對象關係映射(Object Relational Mapping,簡稱ORM)模式是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。簡單的說,ORM是通過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關係數據庫中。
我們接觸過的各大框架都實現了ORM,我們拿3個框架做個比較:
Hibernate 全自動擋的汽車 新手全自動,門檻低,性能低
MyBatis 手自一體的汽車(半自動) 適中,輕量級
SpringJdbc 全手動擋的汽車 高手全手動,門檻高,性能高
3.源碼實現
3.1 mysql表
DROP TABLE IF EXISTS `t_member`;
CREATE TABLE `t_member` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
`addr` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
3.2 定義實體類
@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 +
'}';
}
}
3.3 簡單實現ORM
public class JdbcTest {
public static void main(String[] args) {
//這就是OO編程,ORM
Member condition = new Member();
condition.setName("TomCat");
condition.setAge(2);
//"select * from t_member where name = 'Tom' and age = 19"
List<?> result = select(condition);
System.out.println(Arrays.toString(result.toArray()));
}
public static List<?> select(Object condition) {
List<Object> result = new ArrayList<>();
Class<?> entityClass = condition.getClass();
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");
Map<String,String> getFieldNameByColumn = new HashMap<String,String>();
Map<String,String> getColumnByFieldName = new HashMap<String,String>();
Field[] fields = entityClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
if(field.isAnnotationPresent(Column.class)){
Column column = field.getAnnotation(Column.class);
String columnName = column.name();
getFieldNameByColumn.put(columnName,fieldName);
getColumnByFieldName.put(fieldName,columnName);
}else{
//默認屬性名就是列名
getFieldNameByColumn.put(fieldName,fieldName);
getColumnByFieldName.put(fieldName,fieldName);
}
}
StringBuffer sql = new StringBuffer();
//3、創建語句集
Table table = entityClass.getAnnotation(Table.class);
sql.append("select * from " + table.name() + " where 1=1 ");
for (Field field : fields) {
Object value = field.get(condition);
if(null != value){
if(String.class == field.getType()){
sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = '" + value + "'");
}else{
sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = " + value);
}
//其他依次類推
}
}
pstm = con.prepareStatement(sql.toString());
//4、執行,獲取結果集
rs = pstm.executeQuery();
int columnCounts = rs.getMetaData().getColumnCount();
while (rs.next()){
Object instance = entityClass.newInstance();
for (int i = 1; i <= columnCounts; i++) {
String columnName = rs.getMetaData().getColumnName(i);
Field field = entityClass.getDeclaredField(getFieldNameByColumn.get(columnName));
field.setAccessible(true);
field.set(instance,rs.getObject(columnName));
}
result.add(instance);
}
}catch (Exception e){
e.printStackTrace();
}
//6、關閉結果集、關閉語句集、關閉連接
finally {
try {
rs.close();
pstm.close();
con.close();
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
}
4. 總結
通過這些代碼可以看出,Spring提供了一個未完成的模板Template,我們可以根據業務需要,使用這個Template來實現任何自定義的對象映射。同時,這個思想也同樣適用於其他數據庫如:Redis、MongoDB、HBase、ElasticSearch等。