Live2d Test Env

实现简单ORM案例

ORM框架:

• 我们希望设计一个可以实现对象和SQL自动映射的框架,但是整体用法和设计比Hibernate简单。砍掉不必要的功能。
• 会穿插使用设计模式
• 增加

– 将对象对应成sql语句,执行sql,插入数据库中

• 删除

– 根据对象主键的值,生成sql,执行,从库中删除

• 修改

– 根据对象需要修改属性的值,生成sql,执行• 查询
– 根据结果分类:

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

– 普通对象:Object
– 数字:Number

基本思路:

获取db.properties配置的相关配置信息

将数据库的表转为对应的java实体类

封装表的信息及对应的java类型

利用反射获取类的相关信息/调用get/set方法

Class实例化对象

创建连接池

封装查询语句

 

 

核心架构:

Query接口:

负责查询(对外提供服务的核心类
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接口:

负责类型转换
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

接口回调:

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 

实现代码:

代码结构:

 

代码地址 

posted @ 2019-04-06 14:59  麦奇  阅读(601)  评论(1编辑  收藏  举报