Java进阶笔记(一):自定义持久层框架
一、相关概念
什么是持久层:
可以长时间保存数据的设备,如硬盘等。
什么是持久层框架:
可以操作持久层数据的一套可复用的相互协作的类(代码)。
JDBC:
Java数据库连接(Java Database Connectivity,简称JDBC),是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。
对象/关系数据库映射(ORM):
ORM全称Object Relation Mapping(对象-关系映射),一种程序设计技术,通过在对象与关系型数据库之间建立映射,达到操作对象来操作数据库的效果。
Mybatis:
基于ORM的半自动轻量级持久层框架,可以定制化SQL,因此是半自动,不过可以进行SQL优化获得性能提升。
Hibernate:
全自动化的ORM框架,无需编写SQL语句,只需要设计好对象之间的关系,配置好xml文件;数据库,表,表之间的关系,都是自动生成。
二、概要
学到了如何自己写一个持久层框架,核心是对JDBC的封装,简要步骤如下:
在resources文件夹下新建xml,将jdbc信息、sql语句写入,在程序中使用dom4j读取;
使用工厂模式,编写SQLSessionFactory类,获取SqlSession对象;
使用动态代理和反射,获取Mapper对象的代理,通过代理对象执行sql。
三、遇到的知识点
1.new PropertyDescriptor()的用法:
下方代码是自定义持久层部分代码,当执行select语句后返回resultSet时。
//这个mappedStatement是自定义的一个类,从xml中用dom4j获取了resultType的值填入了这个类的变量中,然后这里用get方法得到resultType。
String resultType = mappedStatement.getResultType();
//应该先判空,这里省略了。
Class<?> resultTypeClass = Class.forName(resultType);
//返回用的list
ArrayList<Object> al = new ArrayList<>();
//执行sql后返回的结果集有下一个时
while(resultSet.next()){
//实现resultType用的一个对象
Object o = resultTypeClass.newInstance();
//元数据
ResultSetMetaData metaData = resultSet.getMetaData();
//遍历列
for(int i = 1; i <= metaData.getColumnCount(); i++){
//字段名(数据库的列名,从1开始)
String columnName = metaData.getColumnName(i);
//字段的值(数据库中对应列的值)
Object value = resultSet.getObject(columnName);
//使用内省,传入参数名与对象名,获得相关方法
PropertyDescriptor pd = new PropertyDescriptor(columnName, resultTypeClass);
//获取写方法
Method writeMethod = pd.getWriteMethod();
//将值写入对象o
writeMethod.invoke(o,value);
}
//将一个结果对象放入结果list中
al.add(o);
}
//返回select结果
return (List<E>)al;
2.getDeclaredField()方法的用法:
下方代码是自定义持久层部分代码,当执行sql语句前、处理ParameterType与#{}参数时。
//从自定义对象中获取ParamterType的值(从xml中用dom4j解析出来、存入自定义对象中的)
String paramterType = mappedStatement.getParamterType();
//获取类对象,同上,这个方法中处理了一下null
Class<?> paramtertypeClass = getClassType(paramterType);
//使用boundSql获取parameterMappingList,这是mybatis中处理#{}参数的类
//一个装有sql语句中的参数的list,例如#{id}中的id。
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
for (int i=0; i<parameterMappingList.size(); i++){
ParameterMapping parameterMapping = parameterMappingList.get(i);
//这个content指的是变量名,例如#{id}中的"id"这个字符串
String content = parameterMapping.getContent();
//然后获得这个类中字符串为content的变量对象
Field declaredField = paramtertypeClass.getDeclaredField(content);
//设置为允许访问私有成员模式
declaredField.setAccessible(true);
//这个params[i]是由Object ... 的形式传入的,取得第i个对象,例如User对象
//然后从User对象中获取到变量为"id"的值(与content对应)(传入的params[0]表示User对象)
Object o = declaredField.get(params[0]);
//这里是jdbc替换sql中的"?"参数的方法,将第i+1个"?"替换为对应的值
//从1开始,所以为i+1
//顺序按照parameterMappingList的顺序排好了,不会乱
preparedStatement.setObject(i+1,o);
}
//从mybatis中拿了4个文件,放到了utils目录下,分别是:【GenericTokenParser】、【ParameterMapping】、【ParameterMappingTokenHandler】、【TokenHandler】