手寫DAO框架(五)-DAO層實現

-------前篇:手寫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

 BaseDao實現

  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的定義主要是用於被其餘類繼承的。後期會有示例代碼。 框架

GTableClassParseInfo實現

在子類繼承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 }

GDaoCommonUtil實現

爲了把子類經過泛型定義的類轉化爲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  歡迎關注

 

下期:手寫DAO框架(六)-框架使用示例

相關文章
相關標籤/搜索