實現簡單ORM案例

ORM框架:

• 咱們但願設計一個能夠實現對象和SQL自動映射的框架,可是總體用法和設計比Hibernate簡單。砍掉沒必要要的功能。
• 會穿插使用設計模式
• 增長java

– 將對象對應成sql語句,執行sql,插入數據庫中

• 刪除mysql

– 根據對象主鍵的值,生成sql,執行,從庫中刪除

• 修改git

– 根據對象須要修改屬性的值,生成sql,執行• 查詢
– 根據結果分類:

• 多行多列:List<Javabean>
• 一行多列:Javabean
• 一行一列:github

– 普通對象:Object
– 數字:Number

基本思路:

獲取db.properties配置的相關配置信息

將數據庫的錶轉爲對應的java實體類

封裝表的信息及對應的java類型

利用反射獲取類的相關信息/調用get/set方法

Class實例化對象

建立鏈接池

封裝查詢語句

 

 

核心架構:

Query接口:sql

負責查詢(對外提供服務的核心類
package com.mikey.core;

import com.mikey.bean.ColumnInfo;
import com.mikey.bean.TableInfo;
import com.mikey.util.JDBCUtil;
import com.mikey.util.RefUtil;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:30
 * @Describe:
 **/
public abstract class Query implements Cloneable{
    /**
     * 採用模板方法模式將JDBC操做封裝成模板,便於重用
     * @param sql
     * @param params
     * @param clazz
     * @param callBack
     * @return
     */
    public Object executeQueryTemplate(String sql, Object[] params, Class clazz, CallBack callBack){

        Connection connection=DBManager.getConnection();

        PreparedStatement preparedStatement=null;

        ResultSet resultSet=null;

        try {
            preparedStatement=connection.prepareStatement(sql);
            JDBCUtil.handleParams(preparedStatement,params);
            System.out.println(preparedStatement);
            resultSet=preparedStatement.executeQuery();
            return callBack.doExecute(connection,preparedStatement,resultSet);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            DBManager.close(preparedStatement,connection);
        }
    }

    /**
     * 執行一個DML語句
     * @param sql
     * @param params
     * @return 執行sql語句後影響的行數
     */
    public int executeDML(String sql,Object[] params){
        Connection connection=DBManager.getConnection();
        int count=0;
        PreparedStatement preparedStatement=null;
        try {
            preparedStatement=connection.prepareStatement(sql);
            JDBCUtil.handleParams(preparedStatement,params);
            System.out.println(preparedStatement);
            count=preparedStatement.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DBManager.close(preparedStatement,connection);
        }
        return count;
    }

    /**
     * 將一個對象存儲到數據庫中
     * @param obj
     */
    public void insert(Object obj){
        /**
         * 獲取傳入對象的Class
         */
        Class clazz=obj.getClass();
        /**
         * 存儲sql的參數對象
         */
        ArrayList<Object> params = new ArrayList<>();
        /**
         * 表信息
         */
        TableInfo tableInfo=TableContext.poClassTableMap.get(clazz);
        /**
         * 構建sql
         */
        StringBuilder sql = new StringBuilder("insert into " + tableInfo.getTname() + " (");
        /**
         * 計算不爲null的屬性值
         */
        int countNotNullField=0;
        /**
         * 經過反射獲取全部屬性
         */
        Field[] fileds=clazz.getDeclaredFields();
        /**
         * 遍歷構建SQL
         */
        for (Field field:fileds) {
            String fieldName=field.getName();
            Object fieldValue= RefUtil.invokeGet(fieldName,obj);

            if(fieldValue!=null){
                countNotNullField++;
                sql.append(fieldName+",");
                params.add(fieldValue);
            }
        }
        sql.setCharAt(sql.length()-1,')');
        sql.append(" values (");
        for (int i = 0; i < countNotNullField; i++) {
            sql.append("?,");
        }
        sql.setCharAt(sql.length()-1,')');
        executeDML(sql.toString(),params.toArray());
    }

    /**
     * 刪除clazz表示類對應的表中的記錄(指定主鍵值id的記錄)
     * @param clazz
     * @param id
     */
    public void delete(Class clazz,Object id){
        //Emp.class,2-->delete from emp where id=2
        //經過Class對象找TableInfo
        TableInfo tableInfo=TableContext.poClassTableMap.get(clazz);
        //獲取主鍵
        ColumnInfo onlyPriKey=tableInfo.getOnlyPrikey();
        //sql
        String sql = "delete from "+tableInfo.getTname()+ " where "+onlyPriKey.getName()+"=?";
        //execute
        executeDML(sql,new Object[]{id});
    }

    /**
     * 刪除對象在數據庫中對應的記錄(對象所在的類對應到表,對象的主鍵的值對應到記錄)
     * @param obj
     */
    public void delete(Object obj){
        Class clazz=obj.getClass();

        TableInfo tableInfo=TableContext.poClassTableMap.get(clazz);

        ColumnInfo onlyPrikey=tableInfo.getOnlyPrikey();

        Object prikeyValue=RefUtil.invokeGet(onlyPrikey.getName(),obj);

        delete(clazz,prikeyValue);
    }

    /**
     * 更新對象對應的記錄
     * @param obj
     * @param fieldNames
     * @return
     */
    public int update(Object obj,String[] fieldNames){
        //obj{"uanme","pwd"}-->update 表名  set uname=?,pwd=? where id=?

        Class clazz=obj.getClass();

        List<Object> params=new ArrayList<>();

        TableInfo tableInfo=TableContext.poClassTableMap.get(clazz);

        ColumnInfo onlyPrikey = tableInfo.getOnlyPrikey();

        StringBuilder sql = new StringBuilder("update "+tableInfo.getTname()+ " set ");

        for (String fname: fieldNames) {
            Object fvalue=RefUtil.invokeGet(fname,obj);
            params.add(fvalue);
            sql.append(fname+"=?,");
        }
        sql.setCharAt(sql.length()-1,' ');
        sql.append(" where ");
        sql.append(onlyPrikey.getName()+"=? ");

        params.add(RefUtil.invokeGet(onlyPrikey.getName(),obj));
        return executeDML(sql.toString(),params.toArray());
    }

    /**
     * 查詢返回多行記錄,並將每行記錄封裝到clazz指定的類的對象中
     * @param sql
     * @param clazz
     * @param params
     * @return
     */
    public List queryRows(String sql,Class clazz,Object[] params){
        return (List)executeQueryTemplate(sql,params,clazz, new CallBack() {
            @Override
            public Object doExecute(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {

                List list=null;

                try {
                    ResultSetMetaData metaData= resultSet.getMetaData();
                    //多行
                    while (resultSet.next()){
                        if (list==null){
                            list=new ArrayList();
                        }
                        /**
                         * 調用無參構造方法
                         */
                        Object rowObj=clazz.newInstance();

                        for (int i = 0; i < metaData.getColumnCount(); i++) {
                            String columnName=metaData.getColumnLabel(i+1);
                            Object columnValue=resultSet.getObject(i+1);

                            RefUtil.invokeSet(rowObj,columnName,columnValue);
                        }
                        list.add(rowObj);
                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
                return list;
            }
        });
    }

    /**
     * 查詢一行記錄
     * 查詢返回一行記錄,並將該記錄封裝到clazz指定的類的對象中
     * @param sql
     * @param clazz
     * @param params
     * @return
     */
    public Object queryUniqueRow(String sql,Class clazz,Object[] params){

        List list=queryRows(sql,clazz,params);

        return (list!=null&&list.size()>0?list.get(0):null);
    }

    /**
     * 查詢一個值
     * 根據主鍵的值直接查找對應的對象
     * @param sql
     * @param params
     * @return
     */
    public Object queryVlaue(String sql,Object[] params){
        return executeQueryTemplate(sql, params, null, new CallBack() {
            @Override
            public Object doExecute(Connection conn, PreparedStatement ps, ResultSet rs) {
                Object value = null;
                try {
                    while(rs.next()){
                        value = rs.getObject(1);
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return value;
            }
        });
    }

    /**
     * 查詢一個數值
     * 查詢返回一個數字(一行一列),並將該值返回
     * @param sql
     * @param clazz
     * @param params
     * @return
     */
    public Number queryNumber(String sql,Class clazz,Object[] params){
        return (Number)queryVlaue(sql,params);
    }
    /**
     * 分頁查詢
     * @param pageNum 第幾頁數據
     * @param size 每頁顯示多少記錄
     * @return
     */
    public abstract Object queryPagenate(int pageNum,int size);

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
Query

 

QueryFactory類:數據庫

負責根據配置信息建立query對象
package com.mikey.core;

import com.sun.org.apache.regexp.internal.RE;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:42
 * @Describe:
 **/
public class QueryFactory {

//    public QueryFactory() {
//    }

    //原型對象
    private static Query prototypeObj;

    static {

        try {

            Class clazz=Class.forName(DBManager.getConf().getQueryClass());

            prototypeObj=(Query)clazz.newInstance();

        }catch (Exception e){

            e.printStackTrace();

        }

        TableContext.loadPOTables();
    }

    /**
     * 私有化構造器
     */
    private QueryFactory(){

    }
    /**
     * createQuery
     * @return
     */
    private static Query createQuery(){
        try {
            return (Query)prototypeObj.clone();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
QueryFactory

TypeConvertor接口:apache

負責類型轉換
package com.mikey.core;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:43
 * @Describe:
 **/
public interface TypeConvertor {

    /**
     * 將數據庫類型轉換爲java類型
     * @param columnType
     * @return
     */
    public String databaseType2JavaType(String columnType);

    /**
     * 將java類型轉換爲數據庫類型
     * @param javaDataType
     * @return
     */
    public String javaType2DatabaseType(String javaDataType);



}
TypeConvertor

TableContext類:設計模式

負責獲取管理數據庫全部表結構和類結構的關係,並能夠根據表結構生成類結構。
package com.mikey.core;

import com.mikey.bean.ColumnInfo;
import com.mikey.bean.TableInfo;
import com.mikey.util.JavaFileUtil;
import com.mikey.util.StringUtil;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:49
 * @Describe:
 * 負責獲取管理數據庫全部表結構和類結構的關係,
 * 並能夠根據表結構生成類結構。
 **/
public class TableContext {
    /**
     * 表名Key   表信息對象爲value
     */
    public static Map<String, TableInfo> tables=new HashMap<String, TableInfo>();
    /**
     * 將po的class的對象和表信息對象關聯起來便於重用!
     */
    public static Map<Class,TableInfo> poClassTableMap=new HashMap<Class, TableInfo>();

    private TableContext(){}

    static {
        try {
            Connection connection=DBManager.getConnection();
            DatabaseMetaData metaData=connection.getMetaData();

            ResultSet tableRet=metaData.getTables(null,"%","%",new String[]{"TABLE"});

            while (tableRet.next()){
                String tableName=(String)tableRet.getObject("TABLE_NAME");
                TableInfo tableInfo=new TableInfo(tableName,new HashMap<String,ColumnInfo>(),new ArrayList<ColumnInfo>());
                tables.put(tableName,tableInfo);

                ResultSet set=metaData.getColumns(null,"%",tableName,"%");
                while(set.next()){
                    ColumnInfo ci = new ColumnInfo(set.getString("COLUMN_NAME"),
                            set.getString("TYPE_NAME"), 0);
                    tableInfo.getColumnInfoMap().put(set.getString("COLUMN_NAME"), ci);
                }

                ResultSet set2=metaData.getPrimaryKeys(null,"%",tableName);
                while (set2.next()){
                    ColumnInfo ci2=(ColumnInfo)tableInfo.getColumnInfoMap().get(set2.getObject("COLUMN_NAME"));
                    ci2.setKeyType(0);
                    tableInfo.getPriKeys().add(ci2);
                }

                if (tableInfo.getPriKeys().size()>0){
                    tableInfo.setOnlyPrikey(tableInfo.getPriKeys().get(0));
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 根據表結構,更新配置的po包下面的java類
     * 實現了從表結構轉化到類結構
     */
    public static void updateJavaPOFile(){
        Map<String,TableInfo> map=TableContext.tables;
        for (TableInfo t:map.values()) {
            JavaFileUtil.createJavaPOFile(t,new MySqlTypeConvertor());
        }
    }

    public static void loadPOTables() {
        for (TableInfo tableInfo : tables.values()) {
            try {
                Class clazz = Class.forName(DBManager.getConf().getPoPackage()
                        + "." + StringUtil.firstChar2UpperCase(tableInfo.getTname()));
                poClassTableMap.put(clazz, tableInfo);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

        public static void main(String[] args){

            Map<String, TableInfo> tables = TableContext.tables;

            System.out.println(tables);

        }
    }
TableContext

DBManager類:架構

根據配置信息,維持鏈接對象的管理(增長鏈接池功能) 
package com.mikey.core;

import com.mikey.bean.Configuration;
import com.mikey.pool.DBConnPool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:50
 * @Describe: 根據配置信息
 **/
public class DBManager {

    /**
     * 配置信息類
     */
    private static Configuration conf;

    /**
     * 鏈接對象
     */
    private static DBConnPool pool;

    static {
        Properties pros=new Properties();
        try {
            pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
        }catch (Exception e){
            e.printStackTrace();
        }

        conf=new Configuration();

        conf.setDriver(pros.getProperty("driver"));
        conf.setPoPackage(pros.getProperty("poPackage"));
        conf.setPwd(pros.getProperty("pwd"));
        conf.setSrcPath(pros.getProperty("srcPath"));
        conf.setUrl(pros.getProperty("url"));
        conf.setUser(pros.getProperty("user"));
        conf.setUsingDB(pros.getProperty("usingDB"));
        conf.setQueryClass(pros.getProperty("queryClass"));
        conf.setPoolMaxSize(Integer.parseInt(pros.getProperty("poolMaxSize")));
        conf.setPoolMinSize(Integer.parseInt(pros.getProperty("poolMinSize")));
    }

    /**
     * 獲取鏈接對象
     * @return
     */
    public static Connection getConnection(){
        if (pool==null){
            pool=new DBConnPool();
        }
        return pool.getConnection();
    }

    /**
     * 建立鏈接
     * @return
     */
    public static Connection createConnection(){
        try {
            Class.forName(conf.getDriver());
            return DriverManager.getConnection(conf.getUrl(),conf.getUser(),conf.getPwd());
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 關閉傳入的相關資源對象
     * @param resultSet
     * @param statement
     * @param connection
     */
    public static void close(ResultSet resultSet, Statement statement,Connection connection){
        try {
            if (resultSet!=null){
                resultSet.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        try {
            if (statement!=null){
                statement.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        pool.close(connection);
    }

    /**
     * 關閉Statement返回鏈接對象到鏈接池
     * @param statement
     * @param connection
     */
    public static void close(Statement statement,Connection connection){
        try {
            if (statement!=null){
                statement.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        pool.close(connection);
    }

    /**
     * 返回鏈接對象到鏈接池
     * @param connection
     */
    public static void close(Connection connection){
        pool.close(connection);
    }

    /**
     * 返回Configuration對象
     * @return
     */
    public static Configuration getConf(){
        return conf;
    }


}
DBManager

接口回調:app

package com.mikey.core;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 16:46
 * @Describe:
 **/
public interface CallBack {
    public Object doExecute(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet);
}
CallBack
package com.mikey.core;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 17:10
 * @Describe:
 **/
public class MySqlQuery extends Query {
}
MySqlQuery
package com.mikey.core;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 18:04
 * @Describe:
 **/
public class MySqlTypeConvertor implements TypeConvertor{
    @Override
    public String databaseType2JavaType(String columnType) {

        //varchar-->String
        if("varchar".equalsIgnoreCase(columnType)||"char".equalsIgnoreCase(columnType)){
            return "String";
        }else if("int".equalsIgnoreCase(columnType)
                ||"tinyint".equalsIgnoreCase(columnType)
                ||"smallint".equalsIgnoreCase(columnType)
                ||"integer".equalsIgnoreCase(columnType)
        ){
            return "Integer";
        }else if("bigint".equalsIgnoreCase(columnType)){
            return "Long";
        }else if("double".equalsIgnoreCase(columnType)||"float".equalsIgnoreCase(columnType)){
            return "Double";
        }else if("clob".equalsIgnoreCase(columnType)){
            return "java.sql.CLob";
        }else if("blob".equalsIgnoreCase(columnType)){
            return "java.sql.BLob";
        }else if("date".equalsIgnoreCase(columnType)){
            return "java.sql.Date";
        }else if("time".equalsIgnoreCase(columnType)){
            return "java.sql.Time";
        }else if("timestamp".equalsIgnoreCase(columnType)){
            return "java.sql.Timestamp";
        }

        return null;

    }

    @Override
    public String javaType2DatabaseType(String javaDataType) {
        return null;
    }
}
MySqlTypeConvertor

 鏈接池:

package com.mikey.pool;

import com.mikey.core.DBManager;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 19:39
 * @Describe:鏈接池
 **/
public class DBConnPool {
    /**
     * 鏈接池對象
     */
    private List<Connection> pool;
    /**
     * 最大鏈接數
     */
    public static final int POOL_MAX_SIZE= DBManager.getConf().getPoolMaxSize();
    /**
     * 最小鏈接數
     */
    public static final int POOL_MIN_SIZE=DBManager.getConf().getPoolMinSize();
    /**
     * 初始化鏈接池,使池中的鏈接數達到最小值
     */
    public void initPool(){
        if (pool==null){
            pool=new ArrayList<Connection>();
        }
        while (pool.size() < DBConnPool.POOL_MIN_SIZE){
            pool.add(DBManager.createConnection());
            System.out.println("初始化數據庫鏈接池:"+pool.size());
        }

    }
    /**
     * 從鏈接池中取出一個鏈接
     * @return
     */
    public synchronized Connection getConnection(){
        int last_index=pool.size()-1;
        Connection connection=pool.get(last_index);
        pool.remove(last_index);
        return connection;
    }

    /**
     * 將鏈接放回池中
     * @param connection
     */
    public synchronized void close(Connection connection){
        if (pool.size()>=POOL_MAX_SIZE){
            try {
                if (connection!=null){
                    connection.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }else {
            pool.add(connection);
        }
    }

    /**
     * 構造器初始化
     */
    public DBConnPool(){
        initPool();
    }

}
DBConnPool

工具類:

JDBCUtils封裝經常使用JDBC操做 
package com.mikey.util;

import java.sql.PreparedStatement;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:50
 * @Describe:封裝了JDBC查詢經常使用的操做
 **/
public class JDBCUtil {

    public static void handleParams(PreparedStatement preparedStatement,Object[] params) {
        if (params!=null){
            for (int i = 0; i < params.length; i++) {
                try {
                    preparedStatement.setObject(1+i,params[i]);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

}
JDBCUtil 
JavaFileUtils封裝java文件操做
package com.mikey.util;

import com.mikey.bean.ColumnInfo;
import com.mikey.bean.JavaFieldGetSet;
import com.mikey.bean.TableInfo;
import com.mikey.core.DBManager;
import com.mikey.core.MySqlTypeConvertor;
import com.mikey.core.TableContext;
import com.mikey.core.TypeConvertor;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:52
 * @Describe:封裝了生成Java文件(源代碼)經常使用的操做
 **/
public class JavaFileUtil {
    /**
     * 根據字段信息生成java屬性信息。如:varchar username-->private String username;以及相應的set和get方法源碼
     * @param columnInfo
     * @param typeConvertor
     * @return
     */
    public static JavaFieldGetSet createFieldGetSetSRC(ColumnInfo columnInfo, TypeConvertor typeConvertor){

        JavaFieldGetSet jfgs = new JavaFieldGetSet();

        String javaFieldType = typeConvertor.databaseType2JavaType(columnInfo.getDataType());

        jfgs.setFieldInfo("\tprivate "+javaFieldType +" "+columnInfo.getName()+";\n");

        //public String getUsername(){return username;}
        //生成get方法的源代碼
        StringBuilder stringBuilde=new StringBuilder();
        stringBuilde.append("\tpublic "+javaFieldType+" get"+StringUtil.firstChar2UpperCase(columnInfo.getName())+"(){\n");
        stringBuilde.append("\t\treturn "+columnInfo.getName()+";\n");
        stringBuilde.append("\t}\n");
        jfgs.setGetInfo(stringBuilde.toString());

        //public void setUsername(String username){this.username=username;}
        //生成set方法的源代碼
        StringBuilder setSrc = new StringBuilder();
        setSrc.append("\tpublic void set"+StringUtil.firstChar2UpperCase(columnInfo.getName())+"(");
        setSrc.append(javaFieldType+" "+columnInfo.getName()+"){\n");
        setSrc.append("\t\tthis."+columnInfo.getName()+"="+columnInfo.getName()+";\n");
        setSrc.append("\t}\n");
        jfgs.setSetInfo(setSrc.toString());
        return jfgs;
    }


    public static String createJavaSrc(TableInfo tableInfo,TypeConvertor convertor){
        Map<String,ColumnInfo> columns = tableInfo.getColumnInfoMap();
        List<JavaFieldGetSet> javaFields = new ArrayList<JavaFieldGetSet>();

        for (ColumnInfo columnInfo:columns.values()){
            javaFields.add(createFieldGetSetSRC(columnInfo,convertor));
        }

        StringBuilder stringBuilder = new StringBuilder();

        //生成package
        stringBuilder.append("package "+ DBManager.getConf().getPoPackage()+";\n\n");
        //生成import
        stringBuilder.append("import java.sql.*;\n");
        stringBuilder.append("import java.util.*;\n");
        //生成類聲明語句
        stringBuilder.append("public class "+StringUtil.firstChar2UpperCase(tableInfo.getTname())+" {\n\n");

        //生成屬性列表
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            stringBuilder.append(javaFieldGetSet.getFieldInfo());
        }
        stringBuilder.append("\n\n");
        //生成get方法
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            stringBuilder.append(javaFieldGetSet.getGetInfo());
        }
        //生成set方法
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            stringBuilder.append(javaFieldGetSet.getSetInfo());
        }

        stringBuilder.append("}\n");
        return stringBuilder.toString();


    }

    public static void createJavaPOFile(TableInfo tableInfo,TypeConvertor convertor){
        String src = createJavaSrc(tableInfo,convertor);

        String srcPath = DBManager.getConf().getSrcPath()+"\\";

        String packagePath = DBManager.getConf().getPoPackage().replaceAll("\\.","/");

        File file=new File(srcPath+packagePath);

        if (!file.exists()){
            file.mkdirs();
        }

        BufferedWriter bufferedWriter = null;

        try {
            bufferedWriter=new BufferedWriter(new FileWriter(file.getAbsoluteFile()+"/"+StringUtil.firstChar2UpperCase(tableInfo.getTname())+".java"));
            bufferedWriter.write(src);
            System.out.println("創建表:"+tableInfo.getTname()+"對應的java類:"+StringUtil.firstChar2UpperCase(tableInfo.getTname()+".java"));

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (bufferedWriter!=null){
                    bufferedWriter.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }


    }

    public static void main(String[] args){

        Map<String,TableInfo> map = TableContext.tables;

        for (TableInfo tableInfo:map.values()){
            createJavaPOFile(tableInfo,new MySqlTypeConvertor());
        }

    }
}
JavaFileUtil 
StringUtils封裝經常使用字符串操做
package com.mikey.util;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:51
 * @Describe:封裝了字符串經常使用的操做
 **/
public class StringUtil {
    /**
     * 將目標字符串首字母變爲大寫
     * @param str
     * @return
     */
    public static String firstChar2UpperCase(String str){
        //abcd--->Abcd
        //abcd--->ABCD--->Abcd
        return str.toUpperCase().substring(0,1)+str.substring(1);
    }
}
StringUtil
ReflectUtils封裝經常使用反射操做
package com.mikey.util;

import java.lang.reflect.Method;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:51
 * @Describe:反射工具類
 **/
public class RefUtil {
    /**
     * 調用obj對象對應屬性fieldName的get方法
     * @param fieldName
     * @param obj
     * @return
     */
    public static Object invokeGet(String fieldName,Object obj){
        try {
            Class clazz=obj.getClass();
            Method method=clazz.getMethod("get"+StringUtil.firstChar2UpperCase(fieldName),null);
            return method.invoke(obj,null);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 調用obj對象對應屬性fieldName的set方法
     * @param obj
     * @param columnName
     * @param columnValue
     */
    public static void invokeSet(Object obj,String columnName,Object columnValue) {
        try {
            if (columnValue!=null){
                Method method=obj.getClass().getDeclaredMethod("set"+StringUtil.firstChar2UpperCase(columnName),null);
                method.invoke(obj,columnValue);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
RefUtil 

核心bean,封裝相關數據:

ColumnInfo:封裝表中一個字段的信息(字段類型、字段名、鍵類型)

package com.mikey.bean;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:52
 * @Describe:
 * 封裝一個字段的信息
 **/
public class ColumnInfo {

    private String name;
    //字段名稱
    private String dataType;
    //數據類型
    private int keyType;
    //字段的健類型


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDataType() {
        return dataType;
    }

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public int getKeyType() {
        return keyType;
    }

    public void setKeyType(int keyType) {
        this.keyType = keyType;
    }

    public ColumnInfo(String name, String dataType, int keyType) {
        this.name = name;
        this.dataType = dataType;
        this.keyType = keyType;
    }
}
ColumnInfo

 Configuration:封裝配置文件信息

package com.mikey.bean;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:55
 * @Describe:管理配置信息
 **/
public class Configuration {
    /**
     * 驅動類
     */
    private String driver;

    /**
     * jdbc的url
     */
    private String url;

    /**
     * 數據庫用戶名
     */
    private String user;
    /**
     * 數據庫密碼
     */
    private String pwd;
    /**
     * 正在使用哪一個數據庫
     */
    private String usingDB;
    /**
     * 項目的源碼路徑
     */
    private String srcPath;
    /**
     * 掃描生成的java類的包(持久畫對象)
     */
    private String poPackage;
    /**
     * 項目使用的查詢類的包
     */
    private String queryClass;
    /**
     * 鏈接池中最小的鏈接數
     */
    private int poolMinSize;
    /**
     * 鏈接池中最大鏈接數
     */
    private int poolMaxSize;

    public Configuration() {
    }

    public Configuration(String driver, String url, String user, String pwd, String usingDB, String srcPath, String poPackage, String queryClass, int poolMinSize, int poolMaxSize) {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.pwd = pwd;
        this.usingDB = usingDB;
        this.srcPath = srcPath;
        this.poPackage = poPackage;
        this.queryClass = queryClass;
        this.poolMinSize = poolMinSize;
        this.poolMaxSize = poolMaxSize;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getUsingDB() {
        return usingDB;
    }

    public void setUsingDB(String usingDB) {
        this.usingDB = usingDB;
    }

    public String getSrcPath() {
        return srcPath;
    }

    public void setSrcPath(String srcPath) {
        this.srcPath = srcPath;
    }

    public String getPoPackage() {
        return poPackage;
    }

    public void setPoPackage(String poPackage) {
        this.poPackage = poPackage;
    }

    public String getQueryClass() {
        return queryClass;
    }

    public void setQueryClass(String queryClass) {
        this.queryClass = queryClass;
    }

    public int getPoolMinSize() {
        return poolMinSize;
    }

    public void setPoolMinSize(int poolMinSize) {
        this.poolMinSize = poolMinSize;
    }

    public int getPoolMaxSize() {
        return poolMaxSize;
    }

    public void setPoolMaxSize(int poolMaxSize) {
        this.poolMaxSize = poolMaxSize;
    }
}
Configuration 

TableInfo:封裝一張表的信息

package com.mikey.bean;

import java.util.List;
import java.util.Map;

/**
 * @Program: ORM
 * @Author: 麥奇
 * @Email: 1625017540@qq.com
 * @Create: 2019-04-06 15:56
 * @Describe:表信息
 **/
public class TableInfo {
    //表名
    private String tname;
    //表的全部字段
    private Map<String,ColumnInfo> columnInfoMap;
    //惟一主健
    private ColumnInfo onlyPrikey;
    //聯合主鍵
    private List<ColumnInfo> priKeys;

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname;
    }

    public Map<String, ColumnInfo> getColumnInfoMap() {
        return columnInfoMap;
    }

    public void setColumnInfoMap(Map<String, ColumnInfo> columnInfoMap) {
        this.columnInfoMap = columnInfoMap;
    }

    public ColumnInfo getOnlyPrikey() {
        return onlyPrikey;
    }

    public void setOnlyPrikey(ColumnInfo onlyPrikey) {
        this.onlyPrikey = onlyPrikey;
    }

    public List<ColumnInfo> getPriKeys() {
        return priKeys;
    }

    public void setPriKeys(List<ColumnInfo> priKeys) {
        this.priKeys = priKeys;
    }

    public TableInfo() {
    }

    public TableInfo(String tname, Map<String, ColumnInfo> columnInfoMap, ColumnInfo onlyPrikey) {
        this.tname = tname;
        this.columnInfoMap = columnInfoMap;
        this.onlyPrikey = onlyPrikey;
    }

    public TableInfo(String tname, Map<String, ColumnInfo> columnInfoMap, List<ColumnInfo> priKeys) {
        this.tname = tname;
        this.columnInfoMap = columnInfoMap;
        this.priKeys = priKeys;
    }
}
TableInfo

 

driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/sorm
user=root
pwd=123456
usingDB=mysql
srcPath=D\:\\workspace\\SORM\\src
poPackage=com.mikey.po
queryClass=com.mikey.sorm.core.MySqlQuery
poolMinSize=10
poolMaxSize=100
db.properties

 

架構圖:

 

• 針對SORM框架的說明:
核心思想:使用簡單、性能高、極易上手!
– 配置文件
• 目前使用資源文件、後期項目複雜後能夠增長XML文件配置和註解。
– 類名由表名生成,只有首字母大寫有區別,其餘無區別
– Java對象的屬性由表中字段生成,徹底對應
– 目前,只支持表中只有一個主鍵,聯合主鍵不支持

回調接口

public interface CallBack {
public Object doExecute(Connection conn,PreparedStatement ps,ResultSet rs);
}

模板方法

public Object executeQueryTemplate(String sql,Object[] params,Class clazz,CallBack back){
Connection conn = DBManager.getConn();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
//給sql設參
JDBCUtils.handleParams(ps, params);
System.out.println(ps);
rs = ps.executeQuery();
return back.doExecute(conn, ps, rs);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}finally{
DBManager.close(ps, conn);
}• 調用示例
public Object queryValue(String sql,Object[] params){
return executeQueryTemplate(sql, params, null, new CallBack() {
@Override
public Object doExecute(Connection conn, PreparedStatement ps, ResultSet rs) {
Object value = null;
try {
while(rs.next()){
value = rs.getObject(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return value;
}
});
}
executeQueryTemplate

• 使用工廠模式統計管理Query的建立
• 使用克隆模式提升Query對象的建立效率

• 鏈接池(Connection Pool)
– 就是將Connection對象放入List中,反覆重用!
– 鏈接池的初始化:
• 事先放入多個鏈接對象。
– 從鏈接池中取鏈接對象
• 若是池中有可用鏈接,則將池中最後一個返回。
同時,將該鏈接從池中remove,表示正在使用。
• 若是池中無可用鏈接,則建立一個新的。
– 關閉鏈接
• 不是真正關閉鏈接,而是將用完的鏈接放入池中。

• 市面上的鏈接池產品:

– DBCP
– c3p0
– proxool 

實現代碼:

代碼結構:

 

代碼地址 

相關文章
相關標籤/搜索