可怕!你没看错,这次确实是纯手工实现一个MyBatis框架

目录

  • 前言

  • JDBC

  • MyBatis

  • 源码分析

  • 前置知识

  • 原理分析

  • 自己实现一个 MyBatis 框架

# 前言

MyBatis 是一个非常优秀的持久层应用框架,目前几乎已经一统天下。既然是持久层框架,那么一定是对于数据库的操作,Java 中谈到数据库操作,一定少不了 JDBC。那么 ,MyBatis 比传统的 JDBC 好在哪那?MyBatis 又在哪方面做了优化呢?

# JDBC

如果我们需要查询所有用户,传统的 JDBC 会这样写。

 

public static void main(String[] args) {
    //声明Connection对象
    Connection con = null;
    try {
        //加载驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //创建 connection 对象
        con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db","username","password");

        //使用 connection 对象创建statement 或者 PreparedStatement 类对象,用来执行SQL语句
        Statement statement = con.createStatement();
        //要执行的SQL语句
        String sql = "select * from user";
        //3.ResultSet类,用来存放获取的结果集!!
        ResultSet rs = statement.executeQuery(sql);

        String job = "";
        String id = "";
        while(rs.next()){
            //获取job这列数据
            job = rs.getString("job");
            //获取userId这列数据
            id = rs.getString("userId");

            //输出结果
            System.out.println(id + "\t" + job);
        }
    } catch(ClassNotFoundException e) {
        e.printStackTrace();
    } catch(SQLException e) {
        //数据库连接失败异常处理
        e.printStackTrace();
    }catch (Exception e) {
        e.printStackTrace();
    }finally{
        rs.close();
        con.close();
    }
}

通过上面的代码,我们可以将 JDBC 对于数据库的操作总结为以下几个步骤:

  1. 加载驱动
  2. 创建连接,Connection 对象
  3. 根据 Connection 创建 Statement 或者 PreparedStatement 来执行 SQL 语句
  4. 返回结果集到 ResultSet 中
  5. 手动将 ResultSet 映射到 JavaBean 中

传统的 JDBC 操作的问题也一目了然,整体非常繁琐,也不够灵活,执行一个 SQL 查询就要写一堆代码。

# MyBatis

来看看 MyBatis 代码如何查询数据库。几行代码就完成了数据库查询操作,并且将数据库查询出来的结果映射到了 JavaBean 中了。我们的代码没有加入 Spring Mybatis,加入 Spring 后整体流程会复杂很多,不方便我们理解。

 

//获取 sqlSession,sqlSession 相当于传统 JDBC 的 Conection
public static SqlSession getSqlSession(){
  InputStream configFile = new FileInputStream(filePath);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder.build(configFile);
    return sqlSessionFactory.openSession();
}

//使用 sqlSession 获得对应的 mapper,mapper 用来执行 sql 语句。
public static User get(SqlSession sqlSession, int id){
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    return userMapper.selectByPrimaryKey(id);
}

我们来对 MyBatis 操作数据库做一个总结:

  1. 使用配置文件构建 SqlSessionFactory
  2. 使用 SqlSessionFactory 获得 SqlSession,SqlSession 相当于传统 JDBC 的 Conection
  3. 使用 SqlSession 得到 Mapper
  4. 用 Mapper 来执行 SQL 语句,并返回结果直接封装到 JavaBean 中

# 源码分析

大家平时应该经常使用 MyBatis 框架,对于 SqlSessionFactory、SqlSession、Mapper 等也有一些概念。下面我们从源码来分析怎么实现这些概念。

前置知识

先给出一个大部分框架的代码流程,方便大家理解框架。下面的图片就说明了接口、抽象类和实现类的关系,我们自己写代码时也要多学习这种思想。

可怕!你没看错,这次确实是纯手工实现一个MyBatis框架

带着结果看过程

看源码对于很多人来说都是一个比较枯燥和乏味的过程,如果不做抽象和总结,会觉得非常乱。另外,看源码不要去抠某个细节,尽量从宏观上理解它。这样带着结果看过程你就会知道设计者为什么这么做。

先给出整个 MyBatis 框架的架构图,大家先有一个印象:

可怕!你没看错,这次确实是纯手工实现一个MyBatis框架

原理分析

说明,我们讲解的是原生的 MyBatis 框架,并不是与 Spring 结合的 MyBatis 框架。

还是把上面 MyBatis 操作数据库的代码拿过来,方便我们与源码对照。

 

 //获取 sqlSession,sqlSession 相当于传统 JDBC 的 Conection
  public static SqlSession getSqlSession(){
     //步骤一
    InputStream configFile = new FileInputStream(filePath);
    //步骤二
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder.build(configFile);
      return sqlSessionFactory.openSession();
  }
  
  //使用 sqlSession 获得对应的 mapper,mapper 用来执行 sql 语句。
  public static User get(SqlSession sqlSession, int id){
     //步骤三
      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      return userMapper.selectByPrimaryKey(id);
  }

MyBatis 框架的第一步就是加载我们数据库的相关信息,比如用户名、密码等。以及我们在 XML 文件中写的 SQL 语句。

 

//配置文件中指定了数据库相关的信息和写 sql 语句的 mapper 相关信息,稍后我们需要读取并加载到我们的配置类中。
  <configuration>
    <environments default="development">
      <environment id="development">
        <transactionManager type="JDBC">
          <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/db"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
          </dataSource>
        </transactionManager>
      </environment>
    </environments>
  </configuration>
  <mappers>
    <mapper resource="xml/UserMapper.xml"/>
  </mappers>

第二步就是通过读取到的配置文件信息,构建一个 SqlSessionFactory。

通过 openSession 方法返回了一个 sqlSession,我们来看看 openSession 方法做了什么。

 

 //我们来重点看看 openSession 做了什么操作, DefaultSqlSessionFactory.java
  @Override
  public SqlSession openSession() {
    return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
  }
  
  public Configuration getConfiguration() {
    return this.configuration;
  }
  //这个函数里面有着事务控制相关的代码。
  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
  
    DefaultSqlSession var8;
    try {
      Environment environment = this.configuration.getEnvironment();
      TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
      //根据上面的参数得到 TransactionFactory,通过 TransactionFactory 生成一个 Transaction,可以理解为这个 SqlSession 的事务控制器
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      // 将这个事务控制器封装在 Executor 里
      Executor executor = this.configuration.newExecutor(tx, execType);
      // 使用 configuration 配置类,Executor,和 configuration(是否自动提交) 来构建一个 DefaultSqlSession。
      var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
    } catch (Exception var12) {
      this.closeTransaction(tx);
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
    } finally {
      ErrorContext.instance().reset();
    }
  
    return var8;
  }

看了上面的一大段代码你可能会觉得蒙,没关系,我们来划重点,最终结果返回了一个 DefaultSqlsession。

 

 // 使用 configuration 配置类(我们上面读取的配置文件就需要加载到这个类中),Executor(包含了数据事务控制相关信息),和 autoCommit(是否自动提交) 来构建一个 DefaultSqlSession。
  var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);

有了这个 sqlSession 之后,我们就可以实现所有对数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值