天哪!手动编写mybatis雏形竟然这么简单 (5)

解析
1、创建一个ParameterMappingTokenHandler 处理器
2、创建一个GenericTokenParser 类,并初始化开始标记,结束标记,处理器
3、执行genericTokenParser.parse(sql);获取解析后的sql‘’,以及在parameterMappingTokenHandler 中存放了参数名称的集合。
4、将解析后的sql 和参数封装到BoundSql 实体类中。

/** * 解析自定义占位符 * @param sql * @return */ private BoundSql getBoundSql(String sql){ ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler(); GenericTokenParser genericTokenParser = new GenericTokenParser("#{","}",parameterMappingTokenHandler); String parse = genericTokenParser.parse(sql); return new BoundSql(parse,parameterMappingTokenHandler.getParameterMappings()); } 将参数注入到preparedStatement 中

上面的就完成了sql,的解析,但是我们知道上面得到的sql 还是包含 JDBC的 占位符,所以我们需要将参数注入到preparedStatement 中。
1、通过boundSql.getSqlText()获取带有占位符的sql.
2、接收参数名称集合 parameterMappingList
3、通过mapper.getParmType() 获取到参数的类。
4、通过getDeclaredField(content)方法获取到参数类的Field。
5、通过Field.get() 从参数类中获取对应的值
6、注入到preparedStatement 中

BoundSql boundSql=getBoundSql(mapper.getSql()); String sql=boundSql.getSqlText(); List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList(); //获取preparedStatement,并传递参数值 PreparedStatement preparedStatement=connection.prepareStatement(sql); Class<?> parmType = mapper.getParmType(); for (int i = 0; i < parameterMappingList.size(); i++) { ParameterMapping parameterMapping = parameterMappingList.get(i); String content = parameterMapping.getContent(); Field declaredField = parmType.getDeclaredField(content); declaredField.setAccessible(true); Object o = declaredField.get(parm[0]); preparedStatement.setObject(i+1,o); } System.out.println(sql); return preparedStatement; 执行sql

其实还是调用JDBC 的executeQuery()方法或者execute()方法

//执行sql ResultSet resultSet = preparedStatement.executeQuery(); 通过反射将结果集封装成对象

在获取到resultSet 后,我们进行封装处理,和参数处理是类似的。
1、创建一个ArrayList
2、获取返回类型的类
3、循环从resultSet中取数据
4、获取属性名和属性值
5、创建属性生成器
6、为属性生成写方法,并将属性值写入到属性中
7、将这条记录添加到list 中
8、返回list

/** * 封装结果集 * @param mapper * @param resultSet * @param <E> * @return * @throws Exception */ private <E> List<E> resultHandle(Mapper mapper,ResultSet resultSet) throws Exception{ ArrayList<E> list=new ArrayList<>(); //封装结果集 Class<?> resultType = mapper.getResultType(); while (resultSet.next()) { ResultSetMetaData metaData = resultSet.getMetaData(); Object o = resultType.newInstance(); int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { //属性名 String columnName = metaData.getColumnName(i); //属性值 Object value = resultSet.getObject(columnName); //创建属性描述器,为属性生成读写方法 PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultType); Method writeMethod = propertyDescriptor.getWriteMethod(); writeMethod.invoke(o,value); } list.add((E) o); } return list; } 创建SqlSessionFactoryBuilder

我们现在来创建一个SqlSessionFactoryBuilder 类,来为使用端提供一个人口。

public class SqlSessionFactoryBuilder { private Configuration configuration; public SqlSessionFactoryBuilder(){ configuration=new Configuration(); } public SqlSessionFactory build(InputStream in) throws DocumentException, PropertyVetoException, ClassNotFoundException { XmlConfigBuilder xmlConfigBuilder = new XmlConfigBuilder(configuration); configuration=xmlConfigBuilder.loadXmlConfig(in); SqlSessionFactory sqlSessionFactory = new DefaultSqlSessionFactory(configuration); return sqlSessionFactory; } }

可以看到就一个build 方法,通过SqlMapConfig的文件流将信息解析到configuration,创建并返回一个sqlSessionFactory 。

到此,整个框架端已经搭建完成了,但是我们可以看到,只实现了select 的操作,update、inster、delete 的操作我们在我后面提供的源码中会有实现,这里只是将整体的设计思路和流程。

在这里插入图片描述

测试

终于到了测试的环节啦。我们前面写了自定义的持久层,我们现在来测试一下能不能正常的使用吧。
见证奇迹的时刻到啦

在这里插入图片描述

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxyxx.html