詳解Java注解實現(xiàn)自己的ORM
搞過Java的碼農(nóng)都知道,在J2EE開發(fā)中一個(確切地說,應(yīng)該是一類)很重要的框架,那就是ORM(Object Relational Mapping,對象關(guān)系映射)。它把Java中的類和數(shù)據(jù)庫中的表關(guān)聯(lián)起來,可以像操作對象那樣操作數(shù)據(jù)表,十分方便。給碼農(nóng)們節(jié)約了大量的時間去摸魚。其實它的本質(zhì)一點都不復(fù)雜,而最核心的就是怎么實現(xiàn)對象和表之間的轉(zhuǎn)換。之前對反射和注解有了一點了解,所以就試著來實現(xiàn)咱們自己的縫合怪。
首先,需要建立一個「表格」:
/** * 類注解,將類注解成數(shù)據(jù)庫表 * * @author xiangwang */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DBTable { String name() default ""; }
然后,定義需要的數(shù)據(jù)庫數(shù)據(jù)類型:
/** * 字段類型枚舉 * * @author xiangwang */ public enum Type { CHAR, STRING, BOOLEAN, INTEGER, LONG, FLOAT, DOUBLE, DATETIME } /** * 數(shù)據(jù)庫字段類型 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ColumnType { Type value() default Type.INTEGER; }
再來完善字段相關(guān)信息:
/** * 字段信息 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface ExtraInfo { String name() default ""; int length() default 0; } /** * 明確字段約束 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; // 還可以增加默認(rèn)值 }
把他們拼起來,成為完整的字段描述:
/** * 拼裝注解,形成完整的字段嵌套注解 * * @author xiangwang */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TableColumn { ColumnType columntype() default @ColumnType; ExtraInfo extrainfo() default @ExtraInfo; Constraints constraints() default @Constraints; }
最后,創(chuàng)建實體類,應(yīng)用剛才寫好的這些注解:
/** * 用戶實體類 * * @author xiangwang */ @DBTable(name = "User") public class User { @TableColumn( columntype = @ColumnType(Type.INTEGER), extrainfo = @ExtraInfo(name = "id", length = 4), constraints = @Constraints(primaryKey = true)) private String id; @TableColumn( columntype = @ColumnType(Type.STRING), extrainfo = @ExtraInfo(name = "name", length = 32), constraints = @Constraints(primaryKey = false, allowNull = false, unique = true)) private String name; @TableColumn( columntype = @ColumnType(Type.INTEGER), extrainfo = @ExtraInfo(name = "age", length = 4), constraints = @Constraints(primaryKey = false)) private Integer age; public String getId() { return id; } public void setId(String 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; } @Override public String toString() { return "User [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
來看看ORM是怎么工作的吧:
/** * 解析類型注解 */ private static String getColumnType(ColumnType columntype) { String type = ""; switch (columntype.value()) { case CHAR: type += "CHAR"; break; case STRING: type += "VARCHAR"; break; case BOOLEAN: type += "BIT"; break; case INTEGER: type += "INT"; break; case LONG: type += "BIGINT"; break; case FLOAT: type += "FLOAT"; break; case DOUBLE: type += "DOUBLE"; break; case DATETIME: type += "DATETIME"; break; default: type += "VARCHAR"; break; } return type; } /** * 解析信息注解 */ private static String getExtraInfo(ExtraInfo extrainfo) { String info = ""; if (null != extrainfo.name()) { info = extrainfo.name(); } else { return null; } if (0 < extrainfo.length()) { info += " (" + extrainfo.length() + ")"; } else { return null; } return info; } /** * 解析約束注解 */ private static String getConstraints(Constraints con) { String constraints = ""; if (con.primaryKey()) { constraints += " PRIMARY KEY"; } if (!con.allowNull()) { constraints += " NOT NULL"; } if (con.unique()) { constraints += " UNIQUE"; } return constraints; }
做了那么多的鋪墊,終于到了臨門一腳了,實現(xiàn)一個縫合怪了:
/** * 臨門一腳:實現(xiàn)一個縫合怪 */ private static void createTable(List<String> list) { for (String className : list) { Class<?> clazz; try { clazz = Class.forName(className); DBTable dbTable = clazz.getAnnotation(DBTable.class); if (dbTable == null) {// 無DBTable注解 continue; } // 轉(zhuǎn)大寫 String tableName = clazz.getSimpleName().toUpperCase(); StringBuilder sql = new StringBuilder("CREATE TABLE " + tableName + "("); for (Field field : clazz.getDeclaredFields()) { // 反射得到注解 Annotation[] anns = field.getDeclaredAnnotations(); if (anns.length < 1) { continue; } String columnInfo = ""; // 類型判斷 if (anns[0] instanceof TableColumn) { TableColumn column = (TableColumn) anns[0]; String type = getColumnType(column.columntype()); columnInfo = getExtraInfo(column.extrainfo()); // 代替( columnInfo = columnInfo.replace("(", type + "("); columnInfo += getConstraints(column.constraints()); } sql.append("\n " + columnInfo + ","); } // 刪除尾部的逗號 String tableCreate = sql.substring(0, sql.length() - 1) + "\n);"; System.out.println(tableCreate); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
驗證效果的時候到了:
public static void main(String[] args) { Class<?> clazz = User.class; List<String> list = new ArrayList<>(); list.add(clazz.getName()); createTable(list); }
當(dāng)然,實際的運營于生產(chǎn)環(huán)境中的ORM框架可要比這個小玩意復(fù)雜多了。但千變?nèi)f變,原理不變,ORM的核心——反射+ 注解——就是這么玩的。
到此這篇關(guān)于Java注解實現(xiàn)自己的ORM的文章就介紹到這了,更多相關(guān)Java注解ORM內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot加載應(yīng)用事件監(jiān)聽器代碼實例
這篇文章主要介紹了SpringBoot加載應(yīng)用事件監(jiān)聽器代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06IDEA 2019.2.2配置Maven3.6.2打開Maven項目出現(xiàn) Unable to import Maven
這篇文章主要介紹了IDEA 2019.2.2配置Maven3.6.2打開Maven項目出現(xiàn) Unable to import Maven project的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12MyBatis-Plus 使用枚舉自動關(guān)聯(lián)注入
本文主要介紹了MyBatis-Plus 使用枚舉自動關(guān)聯(lián)注入,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06