Mybatis学习—如何对JDBC进行封装

Mybatis学习—如何对JDBC进行封装

    • 追踪过程
    • 整体框架执行流程
    • 图示如下

上文简单学习了Mybatis怎么使用,现在看看Mybatis怎么对JDBC进行封装实现数据持久化的。

追踪过程

还是上一篇的测试类,debug模式进行探究Mybatis如何封装JDBC。

 InputStream inputStream = Resources.getResourceAsStream("mybatisConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();
        StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        studentMapper.insertStudent(student);
        session.commit();
        session.close();

在InputStream inputStream = Resources.getResourceAsStream(“mybatisConfig.xml”);该行打上断点。
进入其中,发现:
Mybatis学习—如何对JDBC进行封装_第1张图片
SqlSessionFactoryBuilder该类是返回一个Sqlsession类实例,着重看build方法,发现其又调用了一个重载build方法,并把读取流当做参数传入
在这里插入图片描述现在再看这个重载build函数

 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

XMLConfigBuilder构造方法是干什么的呢?点进去看看
Mybatis学习—如何对JDBC进行封装_第2张图片有个XPath解析器,看来是读取解析xml文件的。
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);这行代码就是读取当前Mybatis的配置文件。
然后又把parser传参去build方法,再继续下一步

 public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

parseConfiguration(parser.evalNode("/configuration"));
return configuration;
这两句先是解析核心配置文件,然后作为configuration返回
看一下configuration是什么样的:
Mybatis学习—如何对JDBC进行封装_第3张图片那么这个配置文件configuration返回给谁了?
Mybatis学习—如何对JDBC进行封装_第4张图片可见还得进入这又一个build方法中

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

发现一个默认的SqlSessionFactory工厂,点进去看看
在这里插入图片描述可见这个默认的SqlSessionFactory就是SqlSessionFactory的一个实现,里面就有Configuration属性。

跟进openSession方法

@Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }

可以看到configuration.getDefaultExecutorType(),点进去看到
Mybatis学习—如何对JDBC进行封装_第5张图片返回的是一个默认的执行器类型对象,将其作为参数传入了openSessionFromDataSource方法中,进入

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

一部分一部分分析

final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

这两句是读取配置文件的开发环境,即下图
Mybatis学习—如何对JDBC进行封装_第6张图片
接着读

 final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);

这里首句是创建一个执行器,然后将配置文件,执行器,自动提交方式作为参数,返回一个DefaultSqlSession。
现在来看看session是什么
Mybatis学习—如何对JDBC进行封装_第7张图片
到这里,可以看出build方法就是读取配置文件,把配置文件信息在内存中以一个对象形式存在,这个对象就是congfiguration,加快读取配置文件速度。
综上:Mybatis框架执行流程

  1. 将框架中配置文件保存到configuration对象
  2. 将Configuration作为属性交给DefaultSqlSessionFactory类实例对象
  3. 由SqlSessionFactory工厂创建一个SqlSession对象
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        studentMapper.insertStudent(student);

mybatis是如何定位sql语句的?
mybatis是如何输送数据到sql语句中?
mybatis是如何输入sql语句到数据库中
SqlSession中dirty属性的作用?

带着疑问 我们继续跟进:
跟进getMapper方法之中
在这里插入图片描述看看后面的标注,在具体看看这个configuration:
Mybatis学习—如何对JDBC进行封装_第8张图片
加载资源已经找到了对应的XML文件,继续跟进,进入getmapper中
在这里插入图片描述查看这个mapperRegistry
Mybatis学习—如何对JDBC进行封装_第9张图片继续跟进

 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

可以说是很深层的getMapper方法了,进入newInstance中
在这里插入图片描述继续return,
在这里插入图片描述进入MapperProxy构造方法中,从构造方法中出来在进入newInstace中
在这里插入图片描述一直走下去,走到一个invoke方法中

 @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

其中method参数将sql语句带入进来
Mybatis学习—如何对JDBC进行封装_第10张图片就这么一直走下去直到

 private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
        Class<?> declaringClass, Configuration configuration) {
      String statementId = mapperInterface.getName() + "." + methodName;
      if (configuration.hasStatement(statementId)) {
        return configuration.getMappedStatement(statementId);
      } else if (mapperInterface.equals(declaringClass)) {
        return null;
      }
      for (Class<?> superInterface : mapperInterface.getInterfaces()) {
        if (declaringClass.isAssignableFrom(superInterface)) {
          MappedStatement ms = resolveMappedStatement(superInterface, methodName,
              declaringClass, configuration);
          if (ms != null) {
            return ms;
          }
        }
      }
      return null;
    }
  }
这个configuration参数

fuck!跑晕了 什么时候把sql语句传进来了?
跑着跑着,突然看到了一个函数
在这里插入图片描述精神一振,
Mybatis学习—如何对JDBC进行封装_第11张图片
返回一个value 不知干嘛的,又进了一个函数,出现了一个ms变量
Mybatis学习—如何对JDBC进行封装_第12张图片
走着走着 突然进了update方法
Mybatis学习—如何对JDBC进行封装_第13张图片惊奇又困惑的发现参数parameter传进来了
Mybatis学习—如何对JDBC进行封装_第14张图片
同时还将dirty从false变成true
走啊走,走啊走

@Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

终于走到了JDBC里面熟悉的东西Statement,将sql语句,配置对象,简单执行器都传入

StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);

走下去直到
在这里插入图片描述这里讲sql语句和后面的参数绑定起来,然后一路读取得到我的数据库的账户密码
在这里插入图片描述连接数据库
Mybatis学习—如何对JDBC进行封装_第15张图片在这里插入图片描述最后看这个stmt
在这里插入图片描述
Mybatis学习—如何对JDBC进行封装_第16张图片大体的封装就是这样了,头都晕了!

整体框架执行流程

综上:MyBatis框架执行流程

  1. 将sql语句和数据库配置信息保存在配置文件
  2. 在MyBatis运行时,将配置信息存储Configuration对象
  3. 在创建SqlSession对象提供属性
    1) Configuration对象
    2) dirty:true sql语句执行完毕后 可以事务提交
    false sql语句执行发送错误 事务进行回滚
    3) Executor执行器对象:
    创建Statement对象,在创建过程中
    依靠MapperStatement对象将赋值内容与sql占位符
    进行绑定
  4. SqlSession.commit(): 根据此时dirty属性决定提交和回滚
  5. SqlSession.close();把connection放回数据库连接池中

图示如下

Mybatis学习—如何对JDBC进行封装_第17张图片

你可能感兴趣的:(Mybatis)