• 咱們但願設計一個能夠實現對象和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(); } }
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; } } }
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); }
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); } }
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; } }
接口回調: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); }
package com.mikey.core; /** * @Program: ORM * @Author: 麥奇 * @Email: 1625017540@qq.com * @Create: 2019-04-06 17:10 * @Describe: **/ public class MySqlQuery extends Query { }
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; } }
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(); } }
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(); } } } } }
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()); } } }
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); } }
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(); } } }
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; } }
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; } }
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; } }
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
• 針對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; } }); }
• 使用工廠模式統計管理Query的建立
• 使用克隆模式提升Query對象的建立效率
• 鏈接池(Connection Pool)
– 就是將Connection對象放入List中,反覆重用!
– 鏈接池的初始化:
• 事先放入多個鏈接對象。
– 從鏈接池中取鏈接對象
• 若是池中有可用鏈接,則將池中最後一個返回。
同時,將該鏈接從池中remove,表示正在使用。
• 若是池中無可用鏈接,則建立一個新的。
– 關閉鏈接
• 不是真正關閉鏈接,而是將用完的鏈接放入池中。
• 市面上的鏈接池產品:
– DBCP
– c3p0
– proxool
代碼結構: