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】
原文地址:https://www.cnblogs.com/codeToSuccess/p/13906211.html