- 自定义持久层框架
- 前言
- 一、JDBC问题分析
- 二、解决策略分析
- 二、框架设计
- 1.使用端
- 2. 框架端
- 三、实现
- 1.使用端
- 2.框架端
- 总结
前言 例如:为什么连接数据库不再使用JDBC,而改用诸如Mybatis的持久层框架,此篇通过自定义持久层框架分析对比了二者的区别,及持久层的实现原理
提示:以下是本篇文章正文内容,下面案例可供参考
一、JDBC问题分析- 数据库连接创建、释放频繁,造成系统资源浪费,从而影响系统性能;
- sql语句存在硬编码,不易扩展和维护;
- 查询结果集的封装存在硬编码,sql变化会导致解析变化,不易维护;
- 连接频繁---->使用连接池
- sql语句硬编码----->使用配置文件
- 封装结果集硬编码 ------>使用反射、内省封装pojo对象
提供核心配置文件
sqlMapConfig.xml 提供数据库配置信息,引入mapper.xml
mapper.xml 提供sql语句配置信息
-
加载配置文件,以字节流读取到内存中
创建Resources类,getResourceAsStaream方法,返回InputStream -
创建Bean对象,存放解析出来的内容
Configuration:核心配置类,存放sqlMapConfig.xml 解析出来的内容;
MappedStatement:映射配置类,存放mapper.xml解析春来的内容;
Configuration 中引入MappedStatement,便于传递执行。 -
解析配置文件
创建类SqlSessionFactoryBuilder
创建方法build
该方法做了两件事:
第一,dom4j解析字节输入流,封装成Configuration对象中;
第二,创建工厂类SqlSessionFactory对象。 -
创建SQLSessionFactory接口及实现类DefaultSqlSessionFactory
方法openSession,该方法获取SqlSession接口的实例类对象 -
创建SqlSession接口及实现类DefaultSession
创建CRUD方法:selectList()、selectOne()、insert()、update()、delete()等,方法中调用Executor接口的实力类对象的方法
优化:在SqlSession中添加getMapper方法,通过代理实现(代理对象在调用任何方法,都会执行getMapper中的invoke方法) -
创建Executor接口及实现类SimpleExecutor
该类的crud方法中执行的就是jdbc的代码:注册驱动获连接、获取sql、获取预处理对象、设置参数、执行sql、封装结果集
sqlMapConfig.xml 代码如下:
sqlMapConfig.xml 代码如下:
2.框架端
Resources.java代码如下:
public static InputStream getResourceAsStaream(String path){
InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);
return resourceAsStream;
SqlSessionFactoryBuilder.java代码如下:
public SqlSessionFactory build(InputStream in) throws PropertyVetoException, documentException {
//第一:使用dom4j解析配合文件,将解析出来的配置文件封装到Configuration中
XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
Configuration configuration = xmlConfigBuilder.parseConfig(in);
//第二:创建SqlsessionFactory对象:工厂类:生产sqlSession:会话对象
DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
return defaultSqlSessionFactory;
}
XMLConfigBuilder.java代码如下:
public Configuration parseConfig(InputStream in) throws documentException, PropertyVetoException {
document document = new SAXReader().read(in);
//根标签
Element rootElement = document.getRootElement();
List list = rootElement.selectNodes("//property");
Properties properties = new Properties();
for (Element element : list) {
String name = element.attributevalue("name");
String value = element.attributevalue("value");
properties.setProperty(name,value);
}
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
comboPooledDataSource.setUser(properties.getProperty("username"));
comboPooledDataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(comboPooledDataSource);
//mapper.xml解析:拿到路径--字节输入流---解析
List mapperList = rootElement.selectNodes("//mapper");
for (Element element : mapperList) {
String mapperPath = element.attributevalue("resource");
InputStream resourceAsStaream = Resources.getResourceAsStaream(mapperPath);
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
xmlMapperBuilder.parse(resourceAsStaream);
}
return configuration;
}
xmlMapperBuilder.java代码如下:
public void parse(InputStream inputStream) throws documentException {
document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
String namesapce = rootElement.attributevalue("namespace");
List selectlist = rootElement.selectNodes("//select");
List insertlist = rootElement.selectNodes("//insert");
List updatelist = rootElement.selectNodes("//update");
List deletelist = rootElement.selectNodes("//delete");
//组装方法类型与标签集合的对应关系
Map map = new HashMap();
map.put("select",selectlist);
map.put("insert",insertlist);
map.put("update",updatelist);
map.put("delete",deletelist);
Iterator> it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry entry = it.next();
dealConfiguration(configuration,(List)entry.getValue(),(String)entry.getKey(),namesapce);
}
}
private void dealConfiguration(Configuration configuration,List list,String methodType,String namesapce){
for (Element element : list) {
String id = element.attributevalue("id");
String resultType = element.attributevalue("resultType");
String paramterType = element.attributevalue("paramterType");
String sqlText = element.getTextTrim();
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setResultType(resultType);
mappedStatement.setParamterType(paramterType);
mappedStatement.setSql(sqlText);
mappedStatement.setMethodType(methodType);
String key = namesapce + "." + id;
configuration.getMappedStatementMap().put(key,mappedStatement);
}
}
DefaultSqlSession.java代码如下:
@Override
public List selectList(String statementid, Object... params) throws Exception{
//完成对SimpleExecutor里query方法的调用
SimpleExecutor simpleExecutor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
List
DefaultSqlSession.java代码如下:
@Override
public List query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
//1.注册驱动获取连接
Connection connection = configuration.getDataSource().getConnection();
//2.获取SQL语句: select * from user where id=#{id} and username=#{username}
String sql = mappedStatement.getSql();
//解析sql语句: select * from user where id=? and username=? 转换过程中,对#{}里面的值进行存储
BoundSql boundSql = getBoundSql(sql);
//3. 获取预处理对象:paramterStatement
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//4. 设置参数
//获取参数全路径
String paramterType = mappedStatement.getParamterType();
Class> paramterClass = getClassType(paramterType);
List parameterMappings = boundSql.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
String content = parameterMapping.getContent();
//反射
Field declaredField = paramterClass.getDeclaredField(content);
//暴力访问
declaredField.setAccessible(true);
Object o = declaredField.get(params[0]);
preparedStatement.setObject(i+1,o);
}
//5. 执行sql
ResultSet resultSet = preparedStatement.executeQuery();
String resultType = mappedStatement.getResultType();
Class> resultTypeClass = getClassType(resultType);
ArrayList
总结 以上就是自定义持久层框架的思路及内容,其中对sql语句解析的类时mybatis中自带的类。



