美文网首页
深入理解MyBatis(一)--MyBatis的基本组成

深入理解MyBatis(一)--MyBatis的基本组成

作者: 彳亍口巴 | 来源:发表于2020-04-09 10:21 被阅读0次

一、MyBatis的整体架构

MyBatis 的整体架构分为三层 , 分别是基础支持层 、 核心处理层和接口层


MyBatis的整体架构

二、基础

1、MyBatis的核心组件
  • SqlSessionFactoryBuilder (构造器):它会根据配置信息或者代码来生成 SqlSessionFactory (工厂接口)
  • SqlSessionFactory:依靠工厂来生成 SqlSession (会话)
  • SqlSession:是一个既可以发送 SQL 去执行并返回接口,也可以获取 Mapper 的接口。
  • SQL Mapper:它是 MyBatis 新设计的组件,它是有一个 Java 接口和 XML 文件(或注解)构成的,需要给出对应的 SQL 和映射规则。它负责发送 SQL 去执行,并返回结果。

2、Configuration

这里我们的 Configuration 的类全限定名为 org.apache.ibatis.session.Configuration,它在 MyBatis 中将以一个 Configuration 类对象的形式存在,而这个对象将存在于整个 MyBatis 应用的生命周期中,以便重复读取和运用。在内存中的数据是计算机系统中读取速度最快的,我们可以解析一次配置的 XML 文件保存到 Configuration 对象中,方便我们从这个对象中读取配置信息,性能高。单例占用空间小,基本不占用存储空间,而且可以反复使用。Configuration 类对象保存着我们配置在 MyBatis 的信息。在 MyBatis 中提供了两个 SqlSessionFactory 的实现类, DefualtSqlSessionFactory 和 SqlSessionManager。不过 SqlSessionManager 目前还没有使用,MyBatis 中目前使用的是 DefualtSqlSessionFactory。


3、映射器

映射器是由 Java 接口和 XML 文件(或注解)共同组成的,它的作用如下:定义参数类型、描述缓存、描述 SQL 语句、定义查询结果和 POJO 的映射关系。

一个映射器的实现方式有两种:一种是通过 XML 的方式实现,一种是通过代码+注解实现。第二种方式实现复杂、代码可读性差等,所以建议使用第一种方式。第一种方式其实就是由一个 Java 接口和一个 XML 文件构成(即 MyBatis 代码生成器生成的一样)。


4、映射器,一个没有实现类的接口怎么能运行呢?

这里需要用到 Java 的动态代理:我们会在 MyBatis 上下文中描述这个接口,而 MyBatis 会为这个接口生成代理类对象,代理对象会根据“接口全路径+方法名”去匹配,找到对应的 XML 文件(或注解)去完成它所需要的任务,返回我们需要的结果。


5、生命周期

想要保证多线程中 MyBatis 的正确性、高性能、没有并发问题,就必须掌握 MyBatis 中 SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper 的生命周期。

SqlSessionFactoryBuilder:利用 XML 或者 Java 编码获得资源来构建 SqlSessionFactory 的,通过它可以构建多个 SessionFactory。它的作用就是一个构建起,一旦我们构建了 SqlSessionFactory,它的作用就已经完结了,失去了存在的意义,这是我们就应该毫不犹豫的废弃它,将它回收。所以它的生命周期只存在于方法的局部,它的作用就是生成 SqlSessionFactory 对象。

SqlSessionFactory:作用是创建 SqlSession,而 SqlSession 就是一个会话,相当于 JDBC 中的 Connection 对象。每次应用程序需要访问数据库,我们就要通过 SqlSessionFactory 创建 SqlSession,所以** SqlSessionFactory 应该在 MyBatis 应用的整个生命周期中。而如果我们多次创建同一个数据库的 SqlSessionFactory,则每次创建 SqlSessionFactory 会打开更多的数据库连接(Connection)资源,那么连接资源就很快会被耗尽。因此 SqlSessionFactory 的责任是唯一的,它的责任就是创建 SqlSession,所以我们果断采用单例模式**。如果我们采用多例,那么它对数据库连接的消耗是很大的,不利于我们统一的管理,这样便嗅到了代码的坏味道。

SqlSession:是一个会话,相当于 JDBC 的一个 Connection 对象,它的生命周期应该是在请求数据处理事务的过程中。它是一个线程不安全的对象,在涉及多线程的时候,我们需要特别的当心,操作数据库需要注意其隔离级别,数据库锁等高级特性。此外,每次创建的 SqlSession 都必须及时关闭它,它长期存在就会使数据库连接池的活动资源减少,对系统性能的影响很大。

Mapper:是一个接口,而没有任何实现类,它的作用是发送 SQL,然后返回我们需要的结果,或者执行 SQL 从而修改数据库的数据,因此它应该在一个 SqlSession 事务方法之内,是一个方法级别的东西。它就如果 JDBC 中的一个 SQL 语句的执行,它最大的范围和 SqlSession 是相同的

image

三、配置

1、全部 MyBatis 的配置元素

MyBatis 配置 XML 文件的层次结构。这些层次是不能够颠倒顺序的,如果颠倒顺序,MyBatis 在解析 XML 文件的时候就会出现异常了。

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--配置-->
    <properties/><!--属性-->
    <settions/><!--设置-->
    <typeAliases/><!--类型命名,不区分大小写-->
    <typeHandlers/><!--类型处理器-->
    <objectFactory/><!--对象工厂-->
    <plugins/><!--插件-->
    <environments><!--配置环境-->
        <environment>
            <transactionManager/><!--事务管理器-->
            <dataSource/><!--数据源-->
        </environment>
    </environments>
    <databaseIdProvider/><!--数据库厂商标识-->
    <mappers/><!--映射器-->
</configuration>

四、映射器

MyBatis 是针对映射器构造的 SQL 构建的轻量级框架。

1、select 元素

有3中传递多个参数的方式:map;@Param;实体。

这三种方式对比:

  • 使用 Map 传递参数。因为 Map 导致代码的可读性下降,会导致后面的扩展和维护比较困难,所以建议少使用这种方式。
  • 使用 @Param 注解方式。这种方式可读性高,但是当参数个数很多的时候,同样会导致可读性和维护性下降,所以,当参数个数小于等于 5 时,建议采取这种方式。
  • 使用实体 JavaBean 的方式。当参数个数大于 5 时,建议采取这种方式。
2、insert 元素(写demo)

实现主键回填,即执行完新增后返回主键 id。

3、级联(写demo)

级联的延迟加载实现原理是通过动态代理来实现的。有一个动态代理对象,里面保存着相关的 SQL 和参数,一旦我们使用这个代理对象的方法,它会进入到动态代理对象的代理方法里,方法里面会通过发送 SQL 和参数,就可以把对应的结果从数据库里查回来,这便是其实现原理。

4、缓存(写demo)

目前流行的缓存服务器有 MongoDB、Redis、Ehcache 等。无需从磁盘上读入,具有快速读取和使用的特点。如果缓存的命中率高,那么可以极大的提高系统的性能,所以使用缓存的关键在于存储内容访问的命中率。


五、实际操作代码展示

1、利用注解的方式操作数据库

分为4个部分,配置文件、接口(里面带上注解)、实体类、测试类
配置文件

<?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>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
    <package name="com.bjsxt.pojo"/>
</typeAliases>
<!-- default引用environment的id,当前所使用的环境 -->
    <environments default="default">
    <!-- 声明可以使用的环境 -->
    <environment id="default">
    <!-- 使用原生JDBC事务 -->
    <transactionManager type="JDBC"></transactionManager>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:7625/ssm"/>
    <property name="username" value="root"/>
    <property name="password" value="762513499"/>
    </dataSource>
    </environment>
    </environments>
    <mappers>
    <package name="com.bjsxt.mapper"/>
    </mappers>

</configuration>

接口+注解

package com.bjsxt.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.bjsxt.pojo.Teacher;

public interface TeacherMapper {

    @Select("select * from teacher")
    List<Teacher> selAll();

    @Insert("insert into teacher values(default,#{name})")
    int insOne(Teacher teacher);

    @Update("update teacher set name=#{name} where id=#{id}")
    int updOne(Teacher teacher);

    @Delete("delete from teacher where id=#{0}")
    int delById(int id);
}

实体类

package com.bjsxt.pojo;

public class Teacher {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Teacher() {
        super();
    }

    @Override
    public String toString() {
        return "Teacher [id=" + id + ", name=" + name + "]";
    }

}

测试类

package com.bjsxt.test;

import java.io.IOException;
import java.io.InputStream;

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 com.bjsxt.mapper.TeacherMapper;
import com.bjsxt.pojo.Teacher;

public class test01 {
    public static void main(String[] args) throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession session = factory.openSession();

        TeacherMapper t = session.getMapper(TeacherMapper.class);
//      List<Teacher> list = t.selAll();
        // System.out.println(list);

        Teacher teacher = new Teacher();
        teacher.setName("haha");
        teacher.setId(1);
//      int updOne = t.updOne(teacher);
//      System.out.println(updOne);
        System.out.println(t.selAll());
        t.insOne(teacher);

//          int delById = t.delById(2);

//      System.out.println(delById);

        session.commit();
        session.close();

    }
}


2、通过xml的方式操作数据库

MyBatis配置文件

<?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>
<!-- default引用environment的id,当前所使用的环境 -->
    <environments default="default">
    <!-- 声明可以使用的环境 -->
    <environment id="default">
    <!-- 使用原生JDBC事务 -->
    <transactionManager type="JDBC"></transactionManager>
    <dataSource type="POOLED">
    <property name="driver" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:7625/ssm"/>
    <property name="username" value="root"/>
    <property name="password" value="762513499"/>
    </dataSource>
    </environment>
    </environments>
    <mappers>
    <mapper resource="com/bjsxt/mapper/FlowerMapper.xml"/>
    
    </mappers>

</configuration>

xml配置文件,里面的namespace可以任意配置

<?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">
  <!-- namespace:理解成实现类的全路径(包名+类名) -->
<mapper namespace="a.b">
    <!-- id:方法名
        parameterType:定义参数类型
        resultType:返回值类型
        
        如果方法返回值是list,在resultType中写List的泛型,因为
        mybatis对jdbc进行封装,一行一行的读取数据
     -->
<select id="selectAll" resultType="com.bjsxt.pojo.Flower">
    select * from flower
</select>

<select id="selectById" resultType="int">
    select count(*) from flower
</select>

<select id="c" resultType="com.bjsxt.pojo.Flower">
    select id,name,price,production from flower
</select>
</mapper>

实体类

package com.bjsxt.pojo;

public class Flower {
    private int id;
    private String name;
    private double price;
    private String production;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public String getProduction() {
        return production;
    }
    public void setProduction(String production) {
        this.production = production;
    }
    public Flower() {
        super();
    }
    
    public Flower(int id, String name, double price, String production) {
        super();
        this.id = id;
        this.name = name;
        this.price = price;
        this.production = production;
    }
    @Override
    public String toString() {
        return "Flower [id=" + id + ", name=" + name + ", price=" + price + ", production=" + production + "]";
    }
    
}

测试类

package com.bjsxt.test01;

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

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test01 {
    public static void main(String[] args) throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.xml");
        //使用设计工厂模式
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //生产SqlSession
        SqlSession session=factory.openSession();
        /*List<Flower> list=session.selectList("a.b.selectAll");
        for(Flower flower:list) {
            System.out.println(flower.toString());
        }*/
        
        /*int  n = session.selectOne("a.b.selectById");
        System.out.println(n);*/
        //Map<Object, Object> map = session.selectMap("a.b.c", "name");先显示名字,再显示全部,适合根据名字快速查询
        Map<Object, Object> map = session.selectMap("a.b.c", "price");//先显示价格,再显示全部
        System.out.println(map);
        
        session.close();
    }
}


引用(本文章只供本人学习以及学习的记录,如有侵权,请联系我删除)

深入理解MyBatis的原理:整个体系

相关文章

网友评论

      本文标题:深入理解MyBatis(一)--MyBatis的基本组成

      本文链接:https://www.haomeiwen.com/subject/pfuqmhtx.html