手写ORM持久层框架(转)
工程结构:
本文测试的数据库为:
其中student的表结构为:
表数据:
配置文件 DB2.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://127.0.0.1\:3306/test
user=root
password=123456
usingDB=mysql
srcPath=E:/eclipse_workspace/Test/src
poPackage=com.frank.po
queryClass=com.frank.stom.core.imp.MySqlQuery
poolMinSize=10
poolMaxSize=100
只支持mysql数据库.poPackage为框架根据数据库表自动生成的domain类的包名
下面堆代码:
package com.frank.stom.bean; /**
* 封装表中一个字段的信息
*
*/
public class ColumnInfo { public static final int NORMAL_KEY=0;
public static final int PRIMARY_KEY=1;
public static final int FOREIGN_KEY=2; /**
* 字段名称
*/
private String colName; /**
* 字段类型
*/
private String dataType; /**
* 字段的键类型
* 0:普通键 1:主键 2:外键
*/
private int keyType; public ColumnInfo(String colName, String dataType, int keyType) {
super();
this.colName = colName;
this.dataType = dataType;
this.keyType = keyType;
} public ColumnInfo() { } public String getColName() {
return colName;
} public void setColName(String colName) {
this.colName = colName;
} 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;
} }
package com.frank.stom.bean; /**
* 管理配置信息
*
*/
public class Configuration {
/**
* 驱动类
*/
private String driver;
/**
* jdbc-url
*/
private String url;
/**
* 数据库用户名
*/
private String user;
/**
* 数据库密码
*/
private String password;
/**
* 使用的数据库
*/
private String usingDB;
/**
* 项目的源码路径
*/
private String srcPath;
/**
* 扫描生成java类的包
* persistence object
*/
private String poPackage; /**
* 连接池中最小的连接数
*/
private int poolMinSize;
/**
* 连接池中最大的连接数
*/
private int poolMaxSize; /**
* 项目使用的查询类
*/
private String queryClass; public String getQueryClass() {
return queryClass;
}
public void setQueryClass(String queryClass) {
this.queryClass = queryClass;
}
public Configuration(String driver, String url, String user,
String password, String usingDB,
String srcPath, String poPackage) {
super();
this.driver = driver;
this.url = url;
this.user = user;
this.password = password;
this.usingDB = usingDB;
this.srcPath = srcPath;
this.poPackage = poPackage;
} 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;
}
public Configuration() {
super();
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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;
} }
package com.frank.stom.bean; /**
* 封装了java属性和set/get源码信息
*
* @author frank
*
*/
public class JavaFieldGetSet {
/**
* 属性的源码信息
*/
private String fieldInfo;
/**
* get的源码信息
*/
private String getInfo;
/**
* set的源码信息
*/
private String setInfo; public JavaFieldGetSet(String fieldInfo, String getInfo, String setInfo) {
super();
this.fieldInfo = fieldInfo;
this.getInfo = getInfo;
this.setInfo = setInfo;
} public JavaFieldGetSet() {
super();
} public String getFieldInfo() {
return fieldInfo;
} public void setFieldInfo(String fieldInfo) {
this.fieldInfo = fieldInfo;
} public String getGetInfo() {
return getInfo;
} public void setGetInfo(String getInfo) {
this.getInfo = getInfo;
} public String getSetInfo() {
return setInfo;
} public void setSetInfo(String setInfo) {
this.setInfo = setInfo;
} @Override
public String toString() {
System.out.println(fieldInfo);
System.out.println(getInfo);
System.out.println(setInfo);
return super.toString();
} }
package com.frank.stom.bean; import java.util.List;
import java.util.Map; /**
* 封装表结构信息
* @author frank
*
*/
public class TableInfo { /**
* 表名
*/
private String tabName; /**
* 所以字段信息
*/
private Map<String,ColumnInfo> columns; /**
* 主键
*/
private ColumnInfo priKey; /**
*联合主键
*
*/
private List<ColumnInfo> priKeys; public TableInfo(String tabName, Map<String, ColumnInfo> columns, ColumnInfo priKey) {
super();
this.tabName = tabName;
this.columns = columns;
this.priKey = priKey;
} public TableInfo(String tabName, Map<String, ColumnInfo> columns,
List<ColumnInfo> priKeys) {
super();
this.tabName = tabName;
this.columns = columns;
this.priKeys = priKeys;
} public TableInfo() {
super();
} public List<ColumnInfo> getPriKeys() {
return priKeys;
} public void setPriKeys(List<ColumnInfo> priKeys) {
this.priKeys = priKeys;
} public String getTabName() {
return tabName;
} public void setTabName(String tabName) {
this.tabName = tabName;
} public Map<String, ColumnInfo> getColumns() {
return columns;
} public void setColumns(Map<String, ColumnInfo> columns) {
this.columns = columns;
} public ColumnInfo getPriKey() {
return priKey;
} public void setPriKey(ColumnInfo priKey) {
this.priKey = priKey;
} }
package com.frank.stom.connPool; import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import com.frank.stom.core.DBManager; /**
* 连接池
* @author frank
*
*/
public class DBconnPool {
/**
* 连接池对象
*/
private List<Connection> pool;
/**
* 最大连接数
*/
private static final int POOL_MAX_SIZE=DBManager.getConf().getPoolMaxSize();
/**
* 最小连接数
*/
private static final int POOL_MIN_SIZE=DBManager.getConf().getPoolMinSize(); public DBconnPool(){
initPool();
} /**
* 初始化连接池
*/
public void initPool(){
if(pool==null){
pool=new ArrayList<Connection>();
}
while(pool.size()<POOL_MIN_SIZE){
pool.add(DBManager.createConnection());
}
} /**
* 从连接池中取出一个连接
* @return 连接
*/
public synchronized Connection getConnection(){
int last_index=pool.size()-1;
Connection conn = pool.get(last_index);
pool.remove(last_index);
return conn;
} /**
* 将连接放回池中
* @param conn 连接
*/
public synchronized void close(Connection conn){
if(pool.size()>=POOL_MAX_SIZE)
try {
if(conn!=null)
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else
pool.add(conn); } }
package com.frank.stom.core.imp; import com.frank.stom.core.Query; /**
* 负责mysql数据库的操作
* @author frank
*
*/
public class MySqlQuery extends Query { // @Override
// public Object queryPagenate(int pageNum, int pageSize) {
// return null;
// }
}
package com.frank.stom.core.imp; import com.frank.stom.core.TypeConvertor; /**
* mysql数据库类型和java类型的转换
*
* @author frank
*
*/
public class MysqlTypeConvertor implements TypeConvertor { @Override
public String databaseType2JavaType(String columnType) {
// TODO Auto-generated method stub
// 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 javaType) {
return null;
} }
package com.frank.stom.core; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet; public interface CallBack {
public Object doExecute(Connection conn, PreparedStatement ps,ResultSet rs);
}
package com.frank.stom.core; import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties; import com.frank.stom.bean.Configuration;
import com.frank.stom.connPool.DBconnPool; /**
* 根据配置信息,维持连接对象的管理
* @author frank
*
*/
public class DBManager { /**
* 配置信息
*/
private static Configuration conf;
/**
* 连接池对象
*/
private static DBconnPool pool ;
public static Configuration getConf() {
return conf;
}
static{
Properties pros=new Properties(); try {
pros.load(DBManager.class.getClassLoader().getResourceAsStream("DB2.properties"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
conf = new Configuration();
conf.setDriver(pros.getProperty("driver"));
conf.setPoPackage(pros.getProperty("poPackage"));
conf.setPassword(pros.getProperty("password"));
conf.setUrl(pros.getProperty("url"));
conf.setUser(pros.getProperty("user"));
conf.setSrcPath(pros.getProperty("srcPath"));
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 createConnection(){
try {
Class.forName(conf.getDriver());
return DriverManager.getConnection(conf.getUrl(), conf.getUser(), conf.getPassword());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* 从连接池中获得数据库连接
* @return 连接
*/
public static Connection getConnection(){
// try {
// Class.forName(conf.getDriver());
// return DriverManager.getConnection(conf.getUrl(), conf.getUser(), conf.getPassword());
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// return null;
if(pool==null)
pool = new DBconnPool();
return pool.getConnection(); }
/**
* 关闭资源
* @param rs
* @param ps
* @param conn
*/
public static void close(ResultSet rs,Statement ps,Connection conn){
try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
pool.close(conn);
}
}
package com.frank.stom.core; import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import com.frank.stom.bean.ColumnInfo;
import com.frank.stom.bean.TableInfo;
import com.frank.stom.util.JDBCUtil;
import com.frank.stom.util.ReflectUtil; /**
* 负责查询 对外提供服务的核心类
* @author frank
*/
public abstract class Query implements Cloneable{ /**
* 采用模板方法模式将JDBC操作封装成模板
* @param sql sql语句
* @param params sql参数
* @param clazz 记录要封装到的java类
* @param back CallBack的实现类 回调
* @return
*/
public Object executeQueryTemplate(String sql,Object[] params, Class clazz,CallBack back){
Connection conn=DBManager.getConnection();
PreparedStatement ps=null;
ResultSet rs=null; try {
ps=conn.prepareStatement(sql);
JDBCUtil.handleParams(ps, params);
rs=ps.executeQuery();
return back.doExecute(conn, ps, rs);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}finally{
DBManager.close(null, ps, conn);
}
} /**
* 执行一条DML语句
* @param sql 要执行的sql语句
* @param params sql语句参数
* @return 影响的记录行数
*/
public int executeDML(String sql, Object[] params) {
Connection conn=DBManager.getConnection();
int count=0; PreparedStatement ps=null; try {
ps=conn.prepareStatement(sql);
JDBCUtil.handleParams(ps, params);
count=ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
DBManager.close(null, ps, conn);
}
return count;
} /**
* 将一个对象储存到数据库中
* @param obj 要储存的对象
*/
public void save(Object obj) {
Class c=obj.getClass();
List<Object> params =new ArrayList<Object>();
TableInfo tableInfo = TableContext.poClassTableMap.get(c);
StringBuilder sql=new StringBuilder("insert into "+tableInfo.getTabName()+" (");
Field[] fs=c.getDeclaredFields();
int fieldNotNullCount=0; for(Field field:fs){
String fieldName=field.getName();
Object fieldValue = ReflectUtil.invokeGet(fieldName, obj); if(fieldValue!=null){
fieldNotNullCount++;
sql.append(fieldName+",");
params.add(fieldValue);
}
}
sql.setCharAt(sql.length()-1, ')');
sql.append(" values (");
for(int i=0;i<fieldNotNullCount;i++){
sql.append("?,");
}
sql.setCharAt(sql.length()-1, ')'); this.executeDML(sql.toString(), params.toArray());
} /**
* 删除数据库中的记录
* @param clazz 对象类型
* @param id 主键id
* @return 影响的记录行数
*/
@SuppressWarnings("rawtypes")
public int delete(Class clazz, Object id) {
// TODO Auto-generated method stub
//通过class找TableInfo
TableInfo tableInfo=TableContext.poClassTableMap.get(clazz);
//主键
ColumnInfo onlyPriKey=tableInfo.getPriKey(); String sql="delete from "+tableInfo.getTabName()+" where "+onlyPriKey.getColName()+"=?"; return executeDML(sql, new Object[]{id}); } /**
* 删除对应数据库中的记录
* @param obj 要删除的对象
* @return 影响的记录行数
*/ public int delete(Object obj) {
// TODO Auto-generated method stub
Class c = obj.getClass();
TableInfo tableInfo = TableContext.poClassTableMap.get(c);
ColumnInfo onlyPrikey = tableInfo.getPriKey(); //反射
Object priKeyValue=ReflectUtil.invokeGet(onlyPrikey.getColName(), obj);
return delete(c, priKeyValue); } /**
* 更新对象对应的记录
* @param obj 对象
* @return 影响的记录行数
*/
public int update(Object obj ,String[] fieldNames) {
// TODO Auto-generated method stub
Class c=obj.getClass();
List<Object> params =new ArrayList<Object>();
TableInfo tableInfo = TableContext.poClassTableMap.get(c);
ColumnInfo priKey = tableInfo.getPriKey();
StringBuilder sql=new StringBuilder("update "+tableInfo.getTabName()+" set "); for(String fieldName: fieldNames){
Object fvalue = ReflectUtil.invokeGet(fieldName, obj);
params.add(fvalue);
sql.append(fieldName+"=?,");
}
params.add(ReflectUtil.invokeGet( priKey.getColName(),obj)); sql.setCharAt(sql.length()-1,' ');
sql.append(" where ");
sql.append(priKey.getColName()+"=? ");
System.out.println(sql.toString());
return this.executeDML(sql.toString(), params.toArray());
} /**
* 查询数据库返回多条记录
* @param sql sql语句
* @param clazz 封装javabean类的Class对象
* @param params sql语句参数
* @return 查询得到的结果集
*/
@SuppressWarnings("rawtypes")
public List queryRows(String sql, final Class clazz, Object[] params) {
// TODO Auto-generated method stub
return (List) executeQueryTemplate(sql, params, clazz, new CallBack() { @Override
public Object doExecute(Connection conn, PreparedStatement ps,
ResultSet rs) {
ResultSetMetaData metaDate;
List list=null;
try {
metaDate = rs.getMetaData();
while(rs.next()){
if(list==null)
list=new ArrayList<>();
Object rowObj=clazz.newInstance();
for(int i=0;i<metaDate.getColumnCount();i++){
String columnName = metaDate.getColumnLabel(i+1);
Object columnValue = rs.getObject(i+1);
//通过反射调用rowObj的set方法
ReflectUtil.invokeSet(rowObj, columnName, columnValue); }
list.add(rowObj);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
}); } /**
* 查询数据库返回一条记录
* @param sql sql语句
* @param clazz 封装javabean类的Class对象
* @param params sql语句参数
* @return 查询得到的结果对象
*/
@SuppressWarnings("rawtypes")
public Object queryUniqueRows(String sql, Class clazz,
Object[] params) {
// TODO Auto-generated method stub
List list=queryRows(sql, clazz, params);
return (list==null||list.size()==0)?null:list.get(0);
} /**
* 查询数据库返回一个值( 一行一列)
* @param sql sql语句
* @param params sql语句参数
* @return 查询得到的结果对象
*/
public Object queryValue(String sql, Object[] params) {
// TODO Auto-generated method stub return executeQueryTemplate(sql, params, null, new CallBack() { @Override
public Object doExecute(Connection conn, PreparedStatement ps,
ResultSet rs) {
Object value = null;
// TODO Auto-generated method stub
try {
while(rs.next()){
value=rs.getObject(1);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return value ;
}
});
} /**
* 查询数据库返回一个数字
* @param sql sql语句
* @param params sql语句参数
* @return 查询得到的结果数字
*/
public Number queryNumber(String sql, Object[] params) {
// TODO Auto-generated method stub
return (Number) queryValue(sql, params);
} /**
* 分页查询
* @param pageNum 当前页
* @param pageSize每页显示的记录条数
* @return
*/
// public abstract Object queryPagenate(int pageNum,int pageSize); @Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
} }
package com.frank.stom.core; /**
* 创建query工厂类
* @author frank
*
*/
public class QueryFactory { private static QueryFactory factory=new QueryFactory();
private static Query prototypeObj;
static{
try {
Class c=Class.forName(DBManager.getConf().getQueryClass());
prototypeObj=(Query) c.newInstance(); } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} }
private QueryFactory(){
} public static QueryFactory getInstance(){
return factory;
} public Query creatyFactory(){
try {
return (Query) prototypeObj.clone();
} catch (CloneNotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} }
}
package com.frank.stom.core; import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map; import com.frank.stom.bean.ColumnInfo;
import com.frank.stom.bean.TableInfo;
import com.frank.stom.core.imp.MysqlTypeConvertor;
import com.frank.stom.util.JavaFileUtil;
import com.frank.stom.util.StringUtil; /**
* 负责获取管理数据库所有表结构和类结构的关系,并可以根据表结构生成类结构。
* @author
*
*/
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 con = DBManager.getConnection();
DatabaseMetaData dbmd = con.getMetaData(); ResultSet tableRet = dbmd.getTables(null, "%","%",new String[]{"TABLE"}); while(tableRet.next()){
String tableName = (String) tableRet.getObject("TABLE_NAME"); TableInfo ti = new TableInfo(tableName,new HashMap<String, ColumnInfo>(), new ArrayList<ColumnInfo>() );
tables.put(tableName, ti); ResultSet set = dbmd.getColumns(null, "%", tableName, "%"); //查询表中的所有字段
while(set.next()){
ColumnInfo ci = new ColumnInfo(set.getString("COLUMN_NAME"),
set.getString("TYPE_NAME"), 0);
ti.getColumns().put(set.getString("COLUMN_NAME"), ci);
} ResultSet set2 = dbmd.getPrimaryKeys(null, "%", tableName); //查询t_user表中的主键
while(set2.next()){
ColumnInfo ci2 = (ColumnInfo) ti.getColumns().get(set2.getObject("COLUMN_NAME"));
ci2.setKeyType(ColumnInfo.PRIMARY_KEY); //设置为主键类型
ti.getPriKeys().add(ci2);
} if(ti.getPriKeys().size()>0){ //取唯一主键。。方便使用。如果是联合主键。则为空!
ti.setPriKey(ti.getPriKeys().get(0));
}
}
} catch (SQLException e) {
e.printStackTrace();
}
//更新类结构
updateJavaPOFile(); //加载po包下的所有的类
loadPOTables(); }
/**
* 根据表结构,更新配置po包下的java类
*/
public static void updateJavaPOFile(){
Map<String,TableInfo> map=tables;
for(TableInfo t:map.values()){
JavaFileUtil.createJavaPOFile(t, new MysqlTypeConvertor());
}
}
/**
* 加载po包下的类
*/
public static void loadPOTables(){
for(TableInfo tableInfo:tables.values()){
try {
Class c = Class.forName(DBManager.getConf().getPoPackage()+
"."+StringUtil.firstChar2UpperCase(tableInfo.getTabName()));
poClassTableMap.put(c, tableInfo);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} } public static void main(String[] args) {
Map<String,TableInfo> tables = TableContext.tables;
for(String v: tables.keySet()) {
System.out.println(v);
}
for(TableInfo f:tables.values()){
System.out.println(f.getPriKey().getColName());
}
System.out.println(tables);
} }
package com.frank.stom.core; /**
* 负责java类型和数据库类型的相互转换
* @author frank
*/ public interface TypeConvertor { /**
* 将数据库类型转换为java类型
* @param columnType 数据库字段类型
* @return java类型
*/
public String databaseType2JavaType(String columnType); /**
* 将java类型转换为数据库类型
* @param javaType java类型
* @return 数据库类型
*/
public String javaType2DatabaseType(String javaType); }
package com.frank.stom.util; import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import com.frank.stom.bean.ColumnInfo;
import com.frank.stom.bean.JavaFieldGetSet;
import com.frank.stom.bean.TableInfo;
import com.frank.stom.core.DBManager;
import com.frank.stom.core.TypeConvertor; /**
* 封装生成java源文件的常用操作
* @author frank
*
*/
public class JavaFileUtil { /**
*根据字段信息生成java属性信息
* @param colum 字段信息
* @param convertor 类型转换器
* @return java属性的set/get方法
*/
public static JavaFieldGetSet createFieldGetSetSRC(ColumnInfo colum,TypeConvertor convertor){
JavaFieldGetSet fieldSet = new JavaFieldGetSet(); String javaFieldType= convertor.databaseType2JavaType(colum.getDataType()); fieldSet.setFieldInfo("\tprivate "+javaFieldType+" "+colum.getColName()+";\n"); StringBuffer getSrc=new StringBuffer();
//public String getUser(){
//生成get方法源码
getSrc.append("\tpublic "+javaFieldType+" get"+StringUtil.firstChar2UpperCase(colum.getColName())+"(){\n" );
getSrc.append("\t\treturn "+colum.getColName()+";\n");
getSrc.append("\t}\n");
fieldSet.setGetInfo(getSrc.toString()); //生成set方法源码
StringBuffer setSrc= new StringBuffer();
setSrc.append("\tpublic void set"+StringUtil.firstChar2UpperCase(colum.getColName())+"(" );
setSrc.append(javaFieldType+" "+colum.getColName()+"){\n");
setSrc.append("\t\tthis."+colum.getColName()+"="+colum.getColName()+";\n");
setSrc.append("\t}\n");
fieldSet.setSetInfo(setSrc.toString());
return fieldSet;
} /**
* 根据表信息生成java类源码
* @param tableInfo 表信息
* @param convertor 数据类型转换器
* @return java类源码
*/
public static String createJavaSrc(TableInfo tableInfo, TypeConvertor convertor){
StringBuffer src= new StringBuffer(); Map<String,ColumnInfo> columns=tableInfo.getColumns();
List<JavaFieldGetSet> javaFields=new ArrayList<JavaFieldGetSet>();
for(ColumnInfo c:columns.values()){
javaFields.add(createFieldGetSetSRC(c,convertor));
}
//生成package语句
src.append("package "+DBManager.getConf().getPoPackage()+";\n\n"); //生成import语句
src.append("import java.sql.*;\n");
src.append("import java.util.*;\n\n");
//生成类声明语句
src.append("public class "+StringUtil.firstChar2UpperCase(tableInfo.getTabName())+" {\n\n");
// System.out.println("public class "+StringUtil.firstChar2UpperCase(tableInfo.getTabName())+" {\n\n"); //生成属性列表
for(JavaFieldGetSet f:javaFields){
src.append(f.getFieldInfo());
}
src.append("\n\n"); //生成get方法列表
for(JavaFieldGetSet f:javaFields){
src.append(f.getGetInfo());
} //生成set方法列表
for(JavaFieldGetSet f:javaFields){
src.append(f.getSetInfo());
} //生成类结束
src.append("}\n");
// System.out.println(src);
return src.toString(); }
/**
*根据表信息生成java文件
* @param table 表信息
* @param convertor 类型转换器
*/
public static void createJavaPOFile(TableInfo table,TypeConvertor convertor){
String src=createJavaSrc(table, convertor); String srcPath=DBManager.getConf().getSrcPath()+"//";
String packagePath=DBManager.getConf().getPoPackage().replaceAll("\\.", "/");
File f=new File(srcPath+packagePath); System.out.println(f.getAbsolutePath()); if(!f.exists()){
f.mkdirs();
} BufferedWriter bw=null;
try {
bw=new BufferedWriter(new FileWriter(f.getAbsoluteFile()+"/"+StringUtil.firstChar2UpperCase(table.getTabName())+".java") );
bw.write(src);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
package com.frank.stom.util; import java.sql.PreparedStatement;
import java.sql.SQLException; /**
* 封装jdbc常用的操作
* @author frank
*
*/
public class JDBCUtil { /**
*给preparedStatement传如参数
* @param ps PreparedStatement
* @param params 参数
*/
public static void handleParams( PreparedStatement ps,Object[] params){ if(params!=null){
for(int i=0;i<params.length;i++){
try {
ps.setObject(i+1,params[i]);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
} }
package com.frank.stom.util; import java.lang.reflect.Method; /**
* 封装反射的常用操作
* @author frank
*
*/
public class ReflectUtil { /**
* 调用obj对象对应属性的get方法
* @param c
* @param fieldName
* @param obj
* @return
*/
public static Object invokeGet(String fieldName, Object obj){
//通过反射机制,调用属性的get方法
try {
Class c=obj.getClass();
Method m=c.getDeclaredMethod("get"+StringUtil.firstChar2UpperCase(fieldName), null);
return m.invoke(obj, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
} /**
* 调用obj对象对应属性的set方法
* @param c
* @param fieldName
* @param obj
*/
public static void invokeSet( Object obj ,String fieldName,Object fieldValue){
//通过反射机制,调用属性的set方法
try {
Class c=obj.getClass();
Method m=c.getDeclaredMethod("set"+StringUtil.firstChar2UpperCase(fieldName), fieldValue.getClass());
m.invoke(obj, fieldValue);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} }
package com.frank.stom.util; /**
* 封装String 类型的常用操作
* @author frank
*
*/
public class StringUtil { /**
* 将目标字符串首字母变为大写
* @param str 目标字符串
* @return 首字母大写的字符串
*/
public static String firstChar2UpperCase(String str){ return str.toUpperCase().substring(0,1)+str.substring(1); } }
package com.frank.stom.test; import java.util.List; import com.frank.po.Student;
import com.frank.stom.core.Query;
import com.frank.stom.core.QueryFactory; public class TestMain { public static void main(String[] args) {
String sql = "SELECT * FROM student WHERE id = ?"; Student stu1 = new Student(); //这一new 产生一个Student对象,一个Class对象
Class clazz = stu1.getClass(); Object[] params = new Object[1];
params[0] = "1"; QueryFactory aueryFactory = QueryFactory.getInstance();
Query query = aueryFactory.creatyFactory();
Object obj = query.queryUniqueRows(sql, clazz, params);
System.out.println(obj); System.out.println(); sql = "SELECT * FROM student";
params = null;
List<Student> list = query.queryRows(sql, clazz, params);
for(Student student : list) {
System.out.println(student);
}
} }
对于数据库表的实体类 po包下面的类 是自动生成的,运行TableContext里面的main()方法,提前生成好实体类,可以根据需要添加实体类的toStirng(),hashCode()等方法。
生成完实体类之后,运行TestMain()进行一些查询,结果为:
转自:https://www.cnblogs.com/frankM/p/4590338.html
手写ORM持久层框架(转)的更多相关文章
- android orm持久层框架
; ; i < 2; i++) { )); ); h1.setWord("这是修改过的数据"); tv.setText(tv.getText() + "\n&quo ...
- Mybatis(一):手写一套持久层框架
作者 : 潘潘 未来半年,有幸与导师们一起学习交流,趁这个机会,把所学所感记录下来. 「封面图」 自毕业以后,自己先创业后上班,浮沉了近8年,内心着实焦躁,虽一直是走科班路线,但在技术道路上却始终没静 ...
- Java精进-手写持久层框架
前言 本文适合有一定java基础的同学,通过自定义持久层框架,可以更加清楚常用的mybatis等开源框架的原理. JDBC操作回顾及问题分析 学习java的同学一定避免不了接触过jdbc,让我们来回顾 ...
- 闭关修炼180天--手写持久层框架(mybatis简易版)
闭关修炼180天--手写持久层框架(mybatis简易版) 抛砖引玉 首先先看一段传统的JDBC编码的代码实现: //传统的JDBC实现 public static void main(String[ ...
- 重学 Java 设计模式:实战中介者模式「按照Mybaits原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...
- 深入理解Mybatis(第一讲)——手写ORM框架(简易版Mybatis)
我们来自定义一个持久层框架,也就是Mybatis的简易版. 使用端的搭建 idea中新建maven工程IPersistence_test: 在resources目录下新建sqlMapConfig.xm ...
- 持久层框架JPA与Mybatis该如何选型
一.现状描述 目前java 持久层ORM框架应用最广泛的就是JPA和Mybatis.JPA只是一个ORM框架的规范, 对该规范的实现比较完整就是Spring Data JPA(底层基于Hibernat ...
- .NET平台下,关于数据持久层框架
在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...
- 菜鸟学习Hibernate——持久层框架
一.Java操作数据库的阶段. Java对数据库进行操作经历了三个阶段. 1.1操作JDBC阶段 这个阶段就是利用JDBC类来操作数据库.这个阶段出现了两个问题: 代码过度重复:在每一次数据库操作的是 ...
随机推荐
- 3.docker镜像管理基础
一.docker镜像相关 1.About Docker Image Docker镜像含有启动容器所需要的文件系统及其内容,因此,其用于创建并启动docker容器. 采用分层构建机制,最底层为bootf ...
- Spring源码--Bean的管理总结(一)
前奏 最近看了一系列解析spring管理Bean的源码的文章,在这里总结下,方便日后复盘.文章地址https://www.cnblogs.com/CodeBear/p/10336704.html sp ...
- 6409. 【NOIP2019模拟11.06】困难的图论(Tarjan求点双)
题目描述 Description 给定由 n 个点 m 条边组成的无向连通图,保证没有重边和自环. 你需要找出所有边,满足这些边恰好存在于一个简单环中.一个环被称为简单环,当且仅当它包含的所有点都只在 ...
- IDEA maven 配置,运行比较慢,加截本地仓库资源数据
在 Runner 配置了参数: -DarchetypeCatalog=internal
- 如何在ASP.NET Core中上传超大文件
HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx. ...
- POJ 1252 Euro Efficiency ( 完全背包变形 && 物品重量为负 )
题意 : 给出 6 枚硬币的面值,然后要求求出对于 1~100 要用所给硬币凑出这 100 个面值且要求所用的硬币数都是最少的,问你最后使用硬币的平均个数以及对于单个面值所用硬币的最大数. 分析 : ...
- [USACO08FEB]连线游戏Game of Lines
题目背景 Farmer John最近发明了一个游戏,来考验自命不凡的贝茜. 题目描述 Farmer John has challenged Bessie to the following game: ...
- 颜色空间模型 与 Opencv中的HSV模型范围
颜色空间总结 RGB.HSV.YUV 什么是颜色 Wiki是这样说的:颜色或色彩是通过眼.脑和我们的生活经验所产生的一种对光的视觉效应.嗯,简单点说,颜色就是人对光的一种感觉,由大脑产生的一种感觉.感 ...
- Qt Creator 启动失败 可能的解决办法
用了一段时间Qt Creator莫名的打开失败 重装一遍,仍然不行: 网上搜到解决办法:删除 ~\AppData\Roaming\QtProject文件夹. linux下:~是/home/Your ...
- RabbitMQ绑定、队列、消息、虚拟主机详解(五)
Binding:绑定,Exchange和Exchange.Queue之间的连接关系 Binding中可以包含RoutingKey或者参数 Queue:消息队列,实际存储消息数据 Durability: ...