mybatis源码解析及分页的具体实现及mybatis分页的功能实现

mybatis源码解析Mapper动态代理的实现

 

mybatis是通过XML配置的方来定制化 SQL、存储过程以及高级映射等。

用mybatis框架的执行步骤:

主要的代码

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlsessionfactor = new SqlSessionFactoryBuilder().build(is);
		SqlSession session = sqlsessionfactor.openSession();
		UserMapper mapper = session.getMapper(UserMapper.class);

 1.Resources

InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

第一步的是进行io操作,对xml的操作一个io操作。

这行代码的主要的作用就是将路径下的资源读取到流中

Mybatis的一个查询数据库数据的代码,通过mapper找到配置文件的sql语句,执行sql语句获取数据。

通过getResourceAsStream 读取资源文件 ,在读取的过程中调用classLoaderWrapper中的方法,然后通过对

classLoader[]数组的遍历 ,然后进行判断类加载器中所读的流是否为null,如果不为null则返回InputStream对象

 

第一:

Resources 资源工具类

主要作用: 把路径下的资源文件读取到流中

通过getResourceAsStream 读取资源文件

在读取的过程中 调用 classLoaderWrapper中的方法

然后通过对classLoader[]数组的遍历 然后进行判断 类加载器中所读的流是否为null

如果不为null 则返回InputStream对象

2. SqlSessionFactory 与 SqlSession

        SqlSessionFactory sqlsessionfactor = new SqlSessionFactoryBuilder().build(is);

		SqlSession session = sqlsessionfactor.openSession();

这边是以 SqlSessionFactoryBuilder 去创建 SqlSessionFactory,从表面上来看,咱们都是通过SqlSession去执行sql语句

那么如何怎么获取SqlSession呢?

 

(1)我们就先从SqlSessionFactoryBuilder入手, 咱们先看看源码是怎么实现的:

public class SqlSessionFactoryBuilder {

  //Reader读取mybatis配置文件,传入构造方法
  //除了Reader外,其实还有对应的inputStream作为参数的构造方法,
  //这也体现了mybatis配置的灵活性
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }

  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }

  //mybatis配置文件 + properties, 此时mybatis配置文件中可以不配置properties,也能使用${}形式
  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }

  //通过XMLConfigBuilder解析mybatis配置,然后创建SqlSessionFactory对象
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      //下面看看这个方法的源码
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

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

}

这边是以SqlSessionFactoryBuilder 通过XMLConfigBuilder 去解析我们传入的mybatis的配置文件。

(2)当我们获取到SqlSessionFactory之后,就可以通过SqlSessionFactory去获取SqlSession对象。源码如下:

/**
   * 通常一系列openSession方法最终都会调用本方法
   * @param execType 
   * @param level
   * @param autoCommit
   * @return
   */
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //之前说了,从表面上来看,咱们是用sqlSession在执行sql语句, 实际呢,其实是通过excutor执行, excutor是对于Statement的封装
      final Executor executor = configuration.newExecutor(tx, execType);
      //关键看这儿,创建了一个DefaultSqlSession对象
      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();
    }
  }

通过以上步骤,咱们已经得到SqlSession对象了。接下来就是是执行sql语句了。

SqlSession拿到了,就可以调用SqlSession中一系列的select...,  insert..., update..., delete...方法进行CRUD操作了。

二、

SqlsessionFactory是mybatis的 核心对象,获取核心对象的方式

SqlsessionFactoryBuilder构建  SqlsessionFactory 实例

通过Xpath解析的方式去解析mybatis-config.xml 文件 解析的文件内容套接到configuration中 而这个configuration 相

当于 mybatis-config.xml 中的配置文件所对应的类。返回DefaultSqlSessionFactory对象。

3.openSession

openSession的最终调用在org.apache.ibatis.session.defaults包下的DefaultSqlsessionFactory中。

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

 该方法下有三个参数 第一个执行器的类型  第二个 事务的隔离级别 第三个 是否自动提交

  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();
    }
  }

 

三、

获取SQLsession对象 通过DefaultSqlSessionFactory对象调用它里面opensession方法返回DefaultSQLSession对象

调用的是DefaultSqlSessionFactory类中opensessionFromDataSource

该方法下有三个参数 第一个执行器的类型  第二个 事务的隔离级别 第三个 是否自动提交

 

声明一个事务的对象,通过配置文件去读取环境标签的信息,然后通过环境去获取事务工厂对象,通过dataSource的配置获取事务的对象,再根据事务执行器的类型 去创建事务执行器 Executor(相当于Statement)通过执行器 事务自动提交以及配置文件对象 返回 DefaultSqlSession对象。

 4.MapperProxy

 在mybatis中,通过MapperProxy动态代理我们的dao,

当执行自己写的dao里面的方法的时候,其实是对应的mapperProxy在代理。那么,咱们就看看怎么获取MapperProxy对象吧:

(1)通过SqlSession从Configuration中获取。源码如下

/**
   * 什么都不做,直接去configuration中找, 哥就是这么任性
   */
  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

(2)SqlSession把包袱甩给了Configuration, 接下来就看看Configuration。源码如下

/**
   * 烫手的山芋,俺不要,你找mapperRegistry去要
   * @param type
   * @param sqlSession
   * @return
   */
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

(3)Configuration不要这烫手的山芋,接着甩给了MapperRegistry, 那咱看看MapperRegistry。 源码如下:

/**
   * 烂活净让我来做了,没法了,下面没人了,我不做谁来做
   * @param type
   * @param sqlSession
   * @return
   */
  @SuppressWarnings("unchecked")
  public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //能偷懒的就偷懒,俺把粗活交给MapperProxyFactory去做
    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);
    }
  }

(4)MapperProxyFactory,最终交给它去做了。咱们看看源码:

/**
   * 别人虐我千百遍,我待别人如初恋
   * @param mapperProxy
   * @return
   */
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    //动态代理我们写的dao接口
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  
  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

四、通过sqlsession获取相应Mapper

   第一层通过调用sqlsession中getMapper方法

   第二层通过调用配置中的getMapper方法

   第三层通过映射的注册器中的getMapper方法来进行获取相应的Mapper对象

其中使用了MapperProxyFactory 工厂对象来获取 MapperProxy 在里面使用反射和动态代理的方式来获取最终的mapper对象。

通过以上的动态代理,咱们就可以方便地使用dao接口啦:

UserMapper mapper = session.getMapper(UserMapper.class);
User insertUser = new User();

总结:

  • 首先会读取mybatis-config.xml配置文件及Mapper.xml映射文件。
  • 从以上配置文件中解析各个标签中的信息,并将信息注册到Configuration实例中,同时还会初始化默认的参数。
  • 通过DefaultSqlSessionFactoryBuilder#build(Configuration config)实例化DefaultSqlSessionFactory,并将Configuration传递给它。并通过Configuration中的连接池、事务隔离级别,以及executor和autoCommit等参数实例化SqlSession接口的实现类DefaultSqlSession。
  • DefaultSqlSession具体实现了SqlSession中定义的接口。并通过自己持有的Executor接口,委托具体的Executor去执行sql语句完成具体的CRUD操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值