-------前篇:手寫DAO框架(四)-SQL執行---------html
經過上一篇,能夠經過傳入sql和對應的參數,能夠執行sql並返回結果。可是對於一個DAO框架來講,要儘可能的面向對象編程,也就是要實現ORM功能。因此本篇主要介紹DAO層的實現,主要是實現ORM。java
反射git
Class<T> entityClass = (Class<T>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
這一段代碼位於BaseDao中,至關因而整個ORM的開端,目的是獲取子類經過泛型制定的具體類型。github
舉個例子:sql
//父類
package me.lovegao.gdao.demo; import java.lang.reflect.ParameterizedType; public class ParentDemo<T> { private Class<T> entityClass; protected ParentDemo() { entityClass = (Class<T>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } public Class<T> getEntityClass() { return entityClass; } }
//子類 package me.lovegao.gdao.demo; public class ChildDemo extends ParentDemo<Integer> { public static void main(String[] args) { ParentDemo p = new ChildDemo(); System.out.println(p.getEntityClass()); } }
運行代碼,就能夠獲得子類在繼承父類時泛型定義的類型。數據庫
本例結果:編程
class java.lang.Integer
1 package me.lovegao.gdao.orm; 2 3 import java.io.Serializable; 4 import java.lang.reflect.ParameterizedType; 5 import java.util.List; 6 7 import me.lovegao.gdao.bean.GTableClassParseInfo; 8 import me.lovegao.gdao.bean.TwoTuple; 9 import me.lovegao.gdao.sqlexecute.ISqlExecutor; 10 import me.lovegao.gdao.util.GDaoCommonUtil; 11 import me.lovegao.gdao.util.GDaoOrmUtil; 12 import me.lovegao.gdao.util.GenerateSqlUtil; 13 14 /** 15 * 操做對象的dao 16 * @author simple 17 * 18 * @param <T> 19 * @param <PK> 20 */ 21 public class BaseDao<T, PK extends Serializable> { 22 private Class<T> entityClass; 23 private GTableClassParseInfo entityClassParseInfo; 24 private ISqlExecutor sqlExecutor; 25 26 @SuppressWarnings("unchecked") 27 protected BaseDao(ISqlExecutor sqlExecutor) { 28 entityClass = (Class<T>) ((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 29 this.sqlExecutor = sqlExecutor; 30 entityClassParseInfo = GDaoCommonUtil.parseClass(entityClass); 31 } 32 33 /** 34 * 新增 35 * @param entity 36 * @return 37 * @throws Exception 38 */ 39 public PK add(T entity) throws Exception { 40 PK id = null; 41 if(entity != null) { 42 TwoTuple<String, Object[]> sqlResult = GenerateSqlUtil.addSql(entityClassParseInfo, entity); 43 id = sqlExecutor.insert(sqlResult.a, sqlResult.b); 44 } 45 return id; 46 } 47 48 /** 49 * 批量新增 50 * @param list 51 * @throws Exception 52 */ 53 public void addBatch(List<T> list) throws Exception { 54 if(!GDaoCommonUtil.checkCollectionEmpty(list)) { 55 TwoTuple<String, List<Object[]>> sqlList = GenerateSqlUtil.addBatchSql(entityClassParseInfo, list); 56 sqlExecutor.insertOrUpdateBatch(sqlList.a, sqlList.b); 57 } 58 } 59 60 /** 61 * 根據主鍵刪除數據 62 * @param id 63 * @throws Exception 64 */ 65 public void deleteByPK(PK id) throws Exception { 66 TwoTuple<String, PK> sqlIdEntity = GenerateSqlUtil.deleteByPKSql(entityClassParseInfo, id); 67 sqlExecutor.update(sqlIdEntity.a, new Object[] {sqlIdEntity.b}); 68 } 69 70 /** 71 * 更新 72 * @param entity 73 * @throws Exception 74 */ 75 public void update(T entity) throws Exception { 76 TwoTuple<String, Object[]> tuple = GenerateSqlUtil.updateSql(entityClassParseInfo, entity); 77 sqlExecutor.update(tuple.a, tuple.b); 78 } 79 80 /** 81 * 根據主鍵查找 82 * @param id 83 * @return 84 * @throws Exception 85 */ 86 public T queryByPK(PK id) throws Exception { 87 TwoTuple<String, Object[]> tuple = GenerateSqlUtil.queryByPKSql(entityClassParseInfo, id); 88 TwoTuple<List<Object[]>, String[]> resultTuple = sqlExecutor.queryValueAndColumn(tuple.a, tuple.b); 89 List<T> list = GDaoOrmUtil.convertObject2T(resultTuple.a, resultTuple.b, entityClassParseInfo); 90 if(!GDaoCommonUtil.checkCollectionEmpty(list)) { 91 return list.get(0); 92 } 93 return null; 94 } 95 96 /** 97 * 查詢對象列表 98 * @param sql 查詢sql 99 * @param replaceValues sql中對應?的值 100 * @return 包裝類列表 101 * @throws Exception 102 */ 103 public List<T> list(String sql, Object... replaceValues) throws Exception { 104 TwoTuple<List<Object[]>, String[]> resultTuple = sqlExecutor.queryValueAndColumn(sql, replaceValues); 105 List<T> list = GDaoOrmUtil.convertObject2T(resultTuple.a, resultTuple.b, entityClassParseInfo); 106 return list; 107 } 108 109 /** 110 * 普通查詢,結果須要本身轉義 111 * @param sql 查詢sql 112 * @param replaceValues sql中對應?的值 113 * @return List<{列1, 列2}> 114 * @throws Exception 115 */ 116 public List<Object[]> normalList(String sql, Object... replaceValues) throws Exception { 117 List<Object[]> list = sqlExecutor.query(sql, replaceValues); 118 return list; 119 } 120 121 /** 122 * 統計個數 123 * @param sql 有且僅有count()的sql 124 * @param replaceValues sql中對應?的值 125 * @return 126 * @throws Exception 127 */ 128 public long count(String sql, Object... replaceValues) throws Exception { 129 List<Object[]> list = sqlExecutor.query(sql, replaceValues); 130 if(!GDaoCommonUtil.checkCollectionEmpty(list)) { 131 return (long) list.get(0)[0]; 132 } 133 return 0; 134 } 135 136 }
BaseDao的定義主要是用於被其餘類繼承的。後期會有示例代碼。 框架
在子類繼承BaseDao以後,進行初始化的時候,須要對定義的類進行解析,爲了不每次都解析類,因此對類的解析結果進行了一個保存,經過GTableClassParseInfo這個類來保存的。具體定義以下。post
1 package me.lovegao.gdao.bean; 2 3 import java.lang.reflect.Field; 4 import java.util.Map; 5 6 /** 7 * 被GTable註解的類解析後的信息 8 * @author simple 9 * 10 */ 11 public class GTableClassParseInfo { 12 /**類**/ 13 private Class<?> clazz; 14 /**表名**/ 15 private String tableName; 16 /**主鍵名稱**/ 17 private String pkName; 18 /**主鍵的變量**/ 19 private Field pkField; 20 /**主鍵自動生成**/ 21 private boolean pkAutoGenerate; 22 /**聲明瞭表字段的變量名列表,不含主鍵**/ 23 private Field[] fields; 24 /**聲明的數據庫表字段名列表,和fields順序對應,不含主鍵**/ 25 private String[] tableColumnNames; 26 /**數據庫字段和field對應關係,包含主鍵和非主鍵<columnName, Field>**/ 27 private Map<String, Field> allColumnFieldMap; 28 29 public Class<?> getClazz() { 30 return clazz; 31 } 32 public void setClazz(Class<?> clazz) { 33 this.clazz = clazz; 34 } 35 public String getTableName() { 36 return tableName; 37 } 38 public void setTableName(String tableName) { 39 this.tableName = tableName; 40 } 41 public Field[] getFields() { 42 return fields; 43 } 44 public void setFields(Field[] fields) { 45 this.fields = fields; 46 } 47 public String[] getTableColumnNames() { 48 return tableColumnNames; 49 } 50 public void setTableColumnNames(String[] tableColumnNames) { 51 this.tableColumnNames = tableColumnNames; 52 } 53 public String getPkName() { 54 return pkName; 55 } 56 public void setPkName(String pkName) { 57 this.pkName = pkName; 58 } 59 public boolean isPkAutoGenerate() { 60 return pkAutoGenerate; 61 } 62 public void setPkAutoGenerate(boolean pkAutoGenerate) { 63 this.pkAutoGenerate = pkAutoGenerate; 64 } 65 public Field getPkField() { 66 return pkField; 67 } 68 public void setPkField(Field pkField) { 69 this.pkField = pkField; 70 } 71 public Map<String, Field> getAllColumnFieldMap() { 72 return allColumnFieldMap; 73 } 74 public void setAllColumnFieldMap(Map<String, Field> allColumnFieldMap) { 75 this.allColumnFieldMap = allColumnFieldMap; 76 } 77 78 }
爲了把子類經過泛型定義的類轉化爲GTableClassParseInfo,須要經過一個轉換的方法。ui
1 package me.lovegao.gdao.util; 2 3 import java.lang.reflect.Field; 4 import java.util.ArrayList; 5 import java.util.Collection; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 import me.lovegao.gdao.bean.GTableClassParseInfo; 11 import me.lovegao.gdao.bean.annotation.GColumn; 12 import me.lovegao.gdao.bean.annotation.GId; 13 import me.lovegao.gdao.bean.annotation.GTable; 14 15 public class GDaoCommonUtil { 16 …… 17 /** 18 * 解析被表註解的類 19 * @param clazz 20 * @return 21 */ 22 public static GTableClassParseInfo parseClass(Class<?> clazz) { 23 GTable table = clazz.getAnnotation(GTable.class); 24 if(table == null) { 25 throw new NullPointerException("類沒有聲明GTable註解"); 26 } 27 String tableName = table.value(); 28 Field[] fields = clazz.getDeclaredFields(); 29 List<Field> fieldList = new ArrayList(); 30 List<String> fieldNames = new ArrayList(); 31 Map<String, Field> allColumnFieldMap = new HashMap(); 32 String pkName = ""; 33 Field pkField = null; 34 boolean pkAutoGenerate = false; 35 for(Field field : fields) { 36 if(field.isAnnotationPresent(GColumn.class)) { 37 GColumn column = field.getAnnotation(GColumn.class); 38 //主鍵聲明 39 if(field.isAnnotationPresent(GId.class)) { 40 if(pkField != null) { 41 throw new RuntimeException("=====錯誤:一個數據庫對象作多隻能定義一個主鍵======"); 42 } 43 GId pkColumn = field.getAnnotation(GId.class); 44 pkName = column.name(); 45 pkField = field; 46 pkAutoGenerate = pkColumn.isAutoIncrease(); 47 } else { 48 fieldList.add(field); 49 fieldNames.add(column.name()); 50 } 51 allColumnFieldMap.put(column.name(), field); 52 } 53 } 54 GTableClassParseInfo tableInfo = new GTableClassParseInfo(); 55 tableInfo.setClazz(clazz); 56 tableInfo.setTableName(tableName); 57 tableInfo.setPkName(pkName); 58 tableInfo.setPkField(pkField); 59 tableInfo.setPkAutoGenerate(pkAutoGenerate); 60 tableInfo.setFields(fieldList.toArray(new Field[0])); 61 tableInfo.setTableColumnNames(fieldNames.toArray(new String[0])); 62 tableInfo.setAllColumnFieldMap(allColumnFieldMap); 63 return tableInfo; 64 } 65 }
至此,整個DAO框架基本完成。
完整代碼參見git:https://github.com/shuimutong/gdao.git 歡迎關注