帶你手寫一個簡單的ORM框架領悟mybatis,hibernate,jpa物件關係對映的祕密
阿新 • • 發佈:2018-12-10
1、ORM介紹 物件關係對映 解決了一個問題: 物件模型和關係模型之間阻抗。 物件模型 關係模型 物件名稱 Student 表 t_student 物件屬性型別 Integer 列的值的型別 int 物件屬性名稱 stuId 列名 student_id 1、ORM思想就誕生=>Java是一門面向物件的語言。 2、操作物件中屬性的值間接操作資料庫中表。 實現方式:hibernate框架 Student.hbm.xml
springBoot(mybatis,spring-data-jpa,hibernate)=>微框架
2、ORM框架的核心反射 反射:API 自定義註解:核心語法和使用方式
3、模擬ORM的框架的部分實現
首先需要連線到JDBC,匯入我們的驅動包以及手寫一個工具類
手動實現增刪改執行返回影響行數的方法
package com.orm.demo.db; /** * @author longhai * @date 2018/9/19 - 14:06 */ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; /** * 操作資料的通過方法 */ public class DBUtils { private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver"; private static final String URL = "jdbc:mysql://localhost:3306/practice?useSSL=true"; private static final String USERNAME = "root"; private static final String PASSWORD = "123456"; static { try { Class.forName(DRIVER_CLASS); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 獲取連線物件的方法 * * @return */ private static Connection getConnection() { try { return DriverManager.getConnection(URL, USERNAME, PASSWORD); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 編寫一個執行通過的增,刪,改的方法, 返回受影響的行數 */ public static int executeUpdate(String sql, Object...parameters) { try ( Connection connection = getConnection(); PreparedStatement pst = connection.prepareStatement(sql); ) { //在sql語句裡面新增所對應的引數 // 是否設定引數呢 if (parameters.length > 0 ) { for (int i = 0; i < parameters.length; i++) { // 迴圈設定引數 pst.setObject(i + 1, parameters[i]);//注意:此方法在API裡面寫到, // 第一個引數不是零,是1,所以要i+1 } } return pst.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } return 0; } }
然後建立一個學生物件
package com.orm.demo.model; import com.orm.demo.annoation.Colum; import com.orm.demo.annoation.Table; /** * @author longhai * @date 2018/9/19 - 14:29 */ @Table("t_student") public class StudentInfo { @Colum("student_id") private Integer studentId; @Colum("student_name") private String studentName; @Colum("student_sex") private String studentSex; @Colum("student_age") private int studentAge; public StudentInfo(Integer studentId, String studentName, String studentSex, int studentAge) { this.studentId = studentId; this.studentName = studentName; this.studentSex = studentSex; this.studentAge = studentAge; } public Integer getStudentId() { return studentId; } public void setStudentId(Integer studentId) { this.studentId = studentId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public String getStudentSex() { return studentSex; } public void setStudentSex(String studentSex) { this.studentSex = studentSex; } public int getStudentAge() { return studentAge; } public void setStudentAge(int studentAge) { this.studentAge = studentAge; } }
自定義註解Colum和Table
package com.orm.demo.annoation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author longhai * @date 2018/9/19 - 13:53 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Colum { String value() default "";//屬性對映的欄位名稱 }
package com.orm.demo.annoation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author longhai * @date 2018/9/19 - 13:52 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Table { String value() default "";//註解對映的表名稱 }
具體實現類
注:由於註解比較詳細,思路我就不多說了,非常易懂
package com.orm.demo;
import com.orm.demo.annoation.Colum;
import com.orm.demo.annoation.Table;
import com.orm.demo.db.DBUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @author longhai
* @date 2018/9/19 - 14:36
*
*
* javabean操作的通用工具類
* <pre>
* 目標: 把entity物件傳入到方法中完成該物件的持久化。
* 核心: 反射
* </pre>
*
*/
public class BeanUtil {
public static <T> int save(T entity){
// 定義儲存SQL語句佔位符對應值的集合(也就是屬性欄位所對應的值)
List<Object> parameters = new ArrayList<>();
StringBuilder sqlBuilder = new StringBuilder(256);//springbuffer方便組合sql語句
// 獲取到當前操作類的Class物件
Class<?> aClass = entity.getClass();
// 問題1: 表名稱和類名稱不一致怎麼辦?
String tableName = aClass.getSimpleName();
// 判斷aClass是否有Table註解
if (aClass.isAnnotationPresent(Table.class)) {
Table table = aClass.getAnnotation(Table.class);
if (!"".equals(table.value())) {
tableName = table.value().toUpperCase();//如果寫了別名
// 就將表的名字設為別名的大寫
}
}
// 構建前面半部分SQL
sqlBuilder.append("INSERT INTO ").append(tableName).append(" (");
//////////////////////// 確定哪些欄位需要參與SQL語句中 /////////////
Field[] fields = aClass.getDeclaredFields();
try {//通過此物件獲取到其所有欄位以及屬性
if (fields != null && fields.length > 0) {
for (Field field : fields) {
// 獲取列名
String columName = field.getName();
//判斷是否有表字段和此類屬性名稱對不上的情況
if (field.isAnnotationPresent(Colum.class)) {
Colum column = field.getAnnotation(Colum.class);
if (!"".equals(column.value())) {
columName = column.value().toUpperCase();
}
}
// 獲取當前這個欄位的值
field.setAccessible(true);
Object value = field.get(entity);
if (value != null) {
sqlBuilder.append(columName).append(",");
parameters.add(value);
//每個欄位值追加逗號
}
}
sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(") VALUES (");
//擷取最後一個逗號
}
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < parameters.size(); i++) {
sqlBuilder.append("?,");
}
//構建sql語句後半段(?,?,?,?,
sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(")");
//(?,?,?,?)
System.out.println(sqlBuilder);//列印sql語句
System.out.println(parameters);//列印引數
return DBUtils.executeUpdate(sqlBuilder.toString(),parameters.toArray());
//由於parameters是集合所以將他toArrary一下
}
}
import com.orm.demo.model.StudentInfo;
/**
* @author longhai
* @date 2018/9/19 - 14:53
*/
public class TestORM {
public static void main(String[] args) {
// 建立一個學生物件
StudentInfo studentInfo = new StudentInfo(1001, "寒梅", "男", 20);
int row = BeanUtil.save(studentInfo);
System.out.println(row > 0 ? "成功" : "失敗");
}
}
我的資料庫是這樣的 :表名T_STUDENT 欄位:STUDENT_ID,STUDENT_NAME,STUDENT_AGE,STUDENT_SEX
測試一下,我們已經將這一條資訊新增到資料庫中了!
大家理解了大概的過程了嗎? 去動手吧,寫出自己想要的功能!框架其實並沒有那麼困難,要多動手多動腦!
對你有幫助的就點個贊,讓天下沒有難學的程式設計