Mybatis源码分析

MyBatis 简介:

MyBatis(Java写的)的持久化解决方案将用户从原始的JDBC访问中解放出来,用户只需要定义需要操作的SQL语句,无须关注底层的JDBC操作,就可以以面向对象的方式进行持久化操作。底层数据库连接的获取、数据访问的实现、事物控制和数据库连接的关闭等都无须用户关系,从而将应用层从底层的JDBC中抽取出来,通过配置文件管理JDBC连接,让MyBatis完成持久化访问的实现。个人总结一下;就是用传统的JDBC操作比较麻烦,而用了MyBatis框架以后,就可以让用户只关注sql语句,不关注底层JDBC操作;

传统JDBC技术

Connection
PreparedStatement
ResultSet
这些不是框架 ,JDBC是规范
如果用JDBC来解决问题:可以解决问题:
在这里插入图片描述
代码如下:

package imooccache;

import imooccache.computable.ExpensiveFunction;

import java.sql.*;

public class test {
    public static void main(String[] args) {
        try {
            // 1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            // 2.获取数据库连接
            Connection conn = DriverManager.getConnection(
                    "jdbc:mysql://47.99.175.156:3306/guns?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT",
                    "root", "****");

            // 3.使用Connection来创建一个Statement对象
            Statement stmt = conn.createStatement();

            // 4.执行sql语句
            ResultSet rs = stmt.executeQuery("select * from sys_dict");

            while (rs.next()){
                System.out.println(rs.getInt(1) + "\t" + rs.getInt(2) + "\t"
                                        + rs.getInt(3));
            }

            // 释放资源
            if (rs != null){
                rs.close();
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}

使用了MyBatis框架以后,就不需要处理加载驱动,创建连接,创建statement这些过程;
当然,MyBatis也是有这些过程的。它使用了ORM思想实现了结果集的封装。
ORM: Object Relational Mappging 对象关系映射
简单的说:就是把数据库表和实体类及实体类的属性对应起来
让我们可以操作实体类就实现操作数据库。

MyBatis的入门

MyBatis的环境搭建:
第一步:创建maven工程并导入坐标
第二步:创建实体类和dao的接口
第三步:创建Mybatis的主配置文件 SqlMapConfig.xml
第四步:创建映射配置文件 ITestDao.xml

第一步:
在这里插入图片描述
第二步:
在这里插入图片描述
在这里插入图片描述
第三步:

<?xml version ="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!--environments中default 和 environment中的id应该一致-->
        <environment id="mysql">
            <!--配置事物的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源-->
            <dataSource type="POOLED">
                <!--配置数据库的4个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>

                <property name="url" value="jdbc:mysql://47.99.175.156:3306/guns?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=false&amp;serverTimezone=CTT"/>
                <property name="username" value="root"/>
                <property name="password" value="******"/>
            </dataSource>
        </environment>
    </environments>

    <!--指定映射配置文件的位置-->

    <mappers>
        <mapper resource="dao/ITestDao.xml"></mapper>
    </mappers>
</configuration>

第四步:
在这里插入图片描述
环境搭建的注意事项:
第一个:创建ITestDao.xml和ITestDao.java时名称,也可以使用ITestMapper
在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper
第二个: mybatis的映射配置文件位置必须和dao接口的包结构相同;(就是在mysql主配置文件中,写mapper时,需要要和dao接口的包结构相同)
在这里插入图片描述

第三个:映射配置文件的mapper标签的namespace属性的取值必须是dao接口的全限定类名
第四个:映射配置文件的操作配置 ,其id属性的取值必须是dao接口的方法名;

在这里插入图片描述
现在是进行测试:

package com.sainan;

import dao.ITestDao;
import domain.Test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class test {

    public static void main(String[] args) throws IOException {
        // 1. 读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        // 3. 使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        // 4. 使用SqlSession创建Dao接口的代理对象
        ITestDao mapper = session.getMapper(ITestDao.class);
        // 5. 使用代理对象执行方法
        List<Test> all = mapper.findAll();
        for(Test test : all){
            System.out.println(test);
        }
        // 6. 释放资源
        session.close();
        in.close();
    }
}

结果也是成功的:
在这里插入图片描述
其步骤为:
第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口中的代理对象
第五步:执行dao中的方法
第六步:释放资源
感觉这样是挺麻烦的,其实这是MyBatis单独的使用,如果和其他框架进行结合的话,会简单很多;
当然,也可以使用注解简单一些;
第一:这样就不需要配置ITestDao.xml了
第二: 在接口上写下:
在这里插入图片描述
第三:在主配置文件下,写下:
在这里插入图片描述
也是可以达到目标;
下面对mybatis使用情况进行分析:
在这里插入图片描述
读配置文件:如果用决定路径的话,那么肯定不行;部署的时候,你也需要这个路径;不合适
读相对路径的话;比如说src/java/main/xxx.xml这时候如果部署到tomcat上时,就没有src这个目录了。
为此:读路径基本上就是两种:
第一个:使用类加载器。它只能读取类路径的配置文件
第二个:使用ServletContext 对象的getRealPath()
2.创建工厂mybatis使用了构建者模式:把这个工厂交给包工队,只需要告诉他需求就好了,这个builder就是包工队(构建者),in就是需求;
优势:把对象的创建细节隐藏,使使用者直接调用方法即可拿到对象。
3.SqlSession是使用工厂模式得到的,好处,降低类之间的依赖关系,解耦
4.创建Dao接口实现类使用了代理模式 优势:不修改源码的基础上对已有方法的增强;
为什么它要做的这么麻烦?
为了灵活:每多了一个类,就可以有多种选择;
建造者模式
那么为什么需要用建造者模式呢?一般来说,如果一个对象的构建比较复杂,就可以使用工厂模式和构建者模式,相对于工厂模式会产出一个完整的产品,构建者模式应用于更加复杂的对象的构建,甚至只会构建产品的一个部分;
下面对其进行分析:
在这里插入图片描述
在进行进入:
在这里插入图片描述
发现他会读取配置文件,然后通过配置文件执行下面这个bulid(Configuration config)生成一个默认的SqlSessionFactory;由此可见,当把InputStream进行输入的时候,要先进行解析生成Configuration,解析完以后,在根据内容来创建SqlSessionFactory对象。所以,如果直接构建的话,太麻烦了;
所以使用了构建者模式:当然,构建者模式,还可以解决一个产品多个方法执行不同时,产生不同的类的问题:细节 实现可以参考我的另一个文章构建者模式

工厂模式
由于之前返回的是:
在这里插入图片描述
接收的SqlSessionFactory是一个接口;当我们点进去的时候
在这里插入图片描述
发现是这个:
在这里插入图片描述
我们点击一下这个小绿标:进入第一个:
在这里插入图片描述
在这里就发现了工厂模式了:
在这里插入图片描述
代理模式
代理模式还是Mybatis的核心使用的模式,由于这个模式,我们只需要编写接口,而不需要实现。
当我们执行下面这行语句的时候,
在这里插入图片描述
点击进入getMapper 你会看到一个接口,这时候点击ctrl + alt + b 就会看到他的实现类
在这里插入图片描述
这个时候,就可以看到configuration.getMapper了。
在这里插入图片描述
在进入就会看到mapperRegistry.getMapper方法
在这里插入图片描述

在往下,该方法又会调用mapperProxyFactory.newInstance(sqlSession)来生成一个具体的代理;
在这里插入图片描述
在点进去看:
在这里插入图片描述
发现先会执行下面的这个newInstance 然后在执行上面这个newInstance(),这里就生成了动态代理对象,传入的是,mapperInterface.getClassLoader(), new Class[] mapperInterface 和mapperProxy(InvocationHandler实现类对象),这时候,执行代理对象的每个方法都会变成执行mapperProxy的invoke()方法;
而查看MapperProxy的代码,可以看到如下内容:
在这里插入图片描述
非常典型的,该MapperProxy类实现了InvocationHandler接口,并且实现了该接口的invoke方法。
通过这种方式,我们只需要编写Mapper.java接口类,当真正执行一个Mapper接口时,就会转发给MapperProxy.invoke方法;

Proxy.newProxyInstance(与被代理类或接口的类加载器,被代理对象要实现相同的接口,如何代理);
如何代理: 就是InvocationHandler实现类,里面会有写invoke方法。
下面进行分析invoke() 方法。
在这里插入图片描述
查看invoke方法 如果是Object类的方法,则直接执行
在这里插入图片描述
如果不是,从缓存中获取MapperMethod,如果为空,则创建并加入缓存
在这里插入图片描述
MapperMethod 根据mapperInterface.getName() + “.” + method.getName()从Configuration对象里找到对应的MappedStatement,从而知道要执行SQL操作类型,然后调用传入的sqlSession实例上的响应的方法。
所以,cachedMapperMethod 会返回一个mapperMethod,然后再执行以下的语句;
在这里插入图片描述
在这里插入图片描述
调用传入的sqlSession实例上的相应方法;
这里sqlSession是一个DefaultSqlSession对象,所以,执行的是DefaultSqlSession对象,然后在执行它的方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值