• 实现简单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("	private "+javaFieldType +" "+columnInfo.getName()+";
    ");
    
            //public String getUsername(){return username;}
            //生成get方法的源代码
            StringBuilder stringBuilde=new StringBuilder();
            stringBuilde.append("	public "+javaFieldType+" get"+StringUtil.firstChar2UpperCase(columnInfo.getName())+"(){
    ");
            stringBuilde.append("		return "+columnInfo.getName()+";
    ");
            stringBuilde.append("	}
    ");
            jfgs.setGetInfo(stringBuilde.toString());
    
            //public void setUsername(String username){this.username=username;}
            //生成set方法的源代码
            StringBuilder setSrc = new StringBuilder();
            setSrc.append("	public void set"+StringUtil.firstChar2UpperCase(columnInfo.getName())+"(");
            setSrc.append(javaFieldType+" "+columnInfo.getName()+"){
    ");
            setSrc.append("		this."+columnInfo.getName()+"="+columnInfo.getName()+";
    ");
            setSrc.append("	}
    ");
            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()+";
    
    ");
            //生成import
            stringBuilder.append("import java.sql.*;
    ");
            stringBuilder.append("import java.util.*;
    ");
            //生成类声明语句
            stringBuilder.append("public class "+StringUtil.firstChar2UpperCase(tableInfo.getTname())+" {
    
    ");
    
            //生成属性列表
            for (JavaFieldGetSet javaFieldGetSet:javaFields){
                stringBuilder.append(javaFieldGetSet.getFieldInfo());
            }
            stringBuilder.append("
    
    ");
            //生成get方法
            for (JavaFieldGetSet javaFieldGetSet:javaFields){
                stringBuilder.append(javaFieldGetSet.getGetInfo());
            }
            //生成set方法
            for (JavaFieldGetSet javaFieldGetSet:javaFields){
                stringBuilder.append(javaFieldGetSet.getSetInfo());
            }
    
            stringBuilder.append("}
    ");
            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 

    实现代码:

    代码结构:

     

    代码地址 

  • 相关阅读:
    VC++ 常用数学函数
    Skin++的使用 (成功在vs2008试过)
    解决switch使用String做参数 (jdk1.7新增),更改jdk版本后报错的问题
    [转]jdk1.7中 新增 switch 使用String 做参数 的实现
    [转]网页版Firebug
    [转]Eclipse导入工程后,XDoclet错误:Missing library: xdoclet1.2.1.jar. Select the home directory for XDoclet. 1.
    SAP related blogs
    [转]SAP FI/CO 模块设置
    如何调用BADI
    [转]一则关于ABAP程序员的趣谈
  • 原文地址:https://www.cnblogs.com/biaogejiushibiao/p/10661745.html
Copyright © 2020-2023  润新知