MyBatis原理总结(手写实现类)

Posted toov5

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis原理总结(手写实现类)相关的知识,希望对你有一定的参考价值。

我们在实际开发中,越简单越好,所以都是采用不写Dao实现类的方式。不管是使用xml还是直接配置。

但是MyBatis是支持写Dao实现类的

 注意sqlSession是这里面的一个灵魂,有很多执行api

技术图片

 

目录结构:

技术图片

 

 方法:

/**
 * 用户的持久层接口
 */
public interface IUserDao 
    List<User> findAll();

实现类:

public class UserDaoImpl implements IUserDao 

    private SqlSessionFactory factory;
    //覆盖掉默认构造函数,这样就有了工厂,可以进一步创建对象
    public UserDaoImpl(SqlSessionFactory factory)
        this.factory = factory;
    
    @Override
    public List<User> findAll() 
        //1.使用工厂创建SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //2.使用sqlSession执行查询所有方法(此处需要的参数:(String statement)从配置文件中获取) namespace + id
        List<User> userList = sqlSession.selectList("com.toov5.dao.IUserDao.findAll");
        //使用完后关闭掉
        sqlSession.close();
        return userList;
    

实体类:

public class User implements Serializable 
  private Integer id;
  private String username;
  private Date birthday;
  private String sex;
  private String address;

    public Integer getId() 
        return id;
    

    public void setId(Integer id) 
        this.id = id;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    

    public Date getBirthday() 
        return birthday;
    

    public void setBirthday(Date birthday) 
        this.birthday = birthday;
    

    public String getSex() 
        return sex;
    

    public void setSex(String sex) 
        this.sex = sex;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    @Override
    public String toString() 
        return "User" +
                "id=" + id +
                ", username=‘" + username + ‘\\‘‘ +
                ", birthday=" + birthday +
                ", sex=‘" + sex + ‘\\‘‘ +
                ", address=‘" + address + ‘\\‘‘ +
                ‘‘;
    

 

全局配置文件:

<?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">
        <!-- 配置mysql的环境-->
        <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://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <!--resource目录下 对应要创建相应的包 -->
        <mapper resource="com/toov5/dao/IUserDao.xml"/>
    </mappers>
</configuration>

 

映射文件:

 

<?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE mapper
                PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.toov5.dao.IUserDao">
<!--查询所有-->
<select id="findAll" resultType="com.toov5.entity.User">
        select * from  user;
    </select>
</mapper>

 

测试类:

/**
 * MyBatis测试类
 */
public class MyBatisTest 
    public static void main(String[] args) throws IOException 
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2. 创建SqlSessonFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //如何解析,如何封装已经底层帮助实现了。细节封装了。
        SqlSessionFactory factory = builder.build(in);
       // SqlSessionFactory 是个接口,需要找实现。这个工厂是用来创建对象的,创建过程省略了
        //3. 使用工厂生产SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //不需要代理类了,SqlSession 是有查询方法的.使用工厂创建Dao对象,传入工厂
        IUserDao userDao = new UserDaoImpl(factory);
        //5.使用代理对象执行方法
        List<User> userList = userDao.findAll();
        userList.stream().forEach(
                user ->
                    System.out.println(user);
                
        );
        //6.释放资源
        in.close();
    

 

Mybatis在用动态代理dao方式时候,也是找到对应的sql语句的。

执行结果,一模一样。

技术图片

 

 

引申


 

 补充,对于绝对路径和相对路径,绝对路径不准确,采用相对路径。  

  相对路径有两种方案可以获得。 1. 类加载器,只能读取类路径的配置文件     2. 使用ServletContext对象的getRealPath()

 

创建工厂,采用了构建这模式。隐藏了创建细节。使用户直接调用方法就可以拿到对象了

技术图片

使用工厂模式生产SqlSession。降低类间的依赖,解耦合。

创建dao接口实现类使用了代理模式。不修改源码基础上对已有的方法增强。

 

MyBatis原理分析:

MyBatis在使用代理Dao的方式实现增删改查时候,做的什么事呢?

 两件事: 

   一: 创建对象

   二: 在代理对象中调用selectList

 

从一开始就需要解析配置文件,

技术图片

进而做如下操作:

 1. 根据配置文件的信息创建Connection对象,注册驱动,获取连接

 2. 获取愈合粗粒对象PreparedStatement,此时需要SQL语句。 com.prepareStatement(sql)

 3. 执行查询 ResultSet resultSet = preparedStatement.executeQuery();

 4.遍历结果用于封装

   List<E> list = new ArrayList();

  while(resultSet.next())

     E element = xxx;   // 可以通过反射后去 class.forName("配置的全限定类名").newInstance();   使用反射封装

 //  进行封装。把每个rs的内容都添加到element中,把element加入到list中

   list.add(element);

 

于是我们就可以把表的列名看成是实体类的属性名称,就可以使用反射的方式来根据名称获取每个属性。

5.返回结果

 

综上所述: 需要提供方法两个信息

1. 连接信息

2. 映射信息,包含两部分:  执行的sql语句; 封装结果的实体类全限定类名。这两个信息作为属性定义对象。

     String  key  : nameSpace+id

     Mapper value :  String的sql语句    方法的全类名

技术图片

通过方法:

 session.getMapper(IUserDao.class) 实现了代理对象的创建

 根据dao接口的字节码创建到的代理对象

public <T> getMapper(Class<T> daoInterfaceClass)

使用的的参数是 : 类加载器(与被代理对象使用相同的类加载器), Class数组:代理对象要实现接口的字节码数组, 如何代理(Handler)

Proxy.newProxyInstance()

此方法的封装:

 s1.类加载器: 它使用的和被代理对象是相同的类加载器

 s2.代理对象要实现的接口: 和被代理对象实现相同的接口

 s3.如何代理: 它就是增强的方法,我们需要自己来提供

       此处是一个InvocationHandler的接口,我们需要写一个该接口的实现类

       调用该类的selectList方法

 

 自定义MyBatis能通过入门案例看到的类:

  class Resources

  class SqlSessionFactoryBuilder

  interface SqlSessionFactory

 

 此时的pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--<dependency>-->
            <!--<groupId>org.mybatis</groupId>-->
            <!--<artifactId>mybatis</artifactId>-->
            <!--<version>3.4.5</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

 构建者构建工厂,工厂生产SqlSession。SqlSession可以做的事情很多。

 总结:读取配置文件io流,解析出我们要的信息,交给构建者,构建者使用工具类,构建了工厂对象,工厂的openSession方法提供了sqlSession对象,sqlSession去干活。

 

以上是关于MyBatis原理总结(手写实现类)的主要内容,如果未能解决你的问题,请参考以下文章

《Java手写系列》-手写MyBatis框架

手写Mybatis,彻底搞懂框架原理

《Java手写系列》-手写MyBatis框架

《Java手写系列》-手写MyBatis框架

《Java手写系列》-手写MyBatis框架

从零开始手写 mybatis- mybatis 事务管理机制详解