当前位置: 首页 > news >正文

MyBatis的简介和核心的组件(映射器、执行器、SqlSession及其工厂)

Java知识点总结:想看的可以从这里进入

目录

    • 1、简介
      • 1.1、原始JDBC
      • 1.2、MyBatis
    • 2、核心组件
      • 2.1、组件介绍
      • 2.2、SqlSessionFactory
      • 2.3、SqlSession
      • 2.4、映射器
        • 2.4.1 接口和XML映射
        • 2.4.2 发送SQL
        • 2.4.3、注解的形式
      • 2.5、执行器
      • 2.6、mybatis流程

1、简介


1.1、原始JDBC

在以前我们都是使用原始的JDBC,但是这种连接会造成创建、释放频繁造成系统资源的浪费从而影响性能,当sql变化时需要去改变Java代码,不符合开闭的原则,在查询时要手动将结果集封装到实体,插入时手动的提取实体到占位符,增加了代码量。

//原始的JDBC手动创建连接
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
    Class.forName("com.mysql.cj.jdbc.Driver");
    String url = "jdbc:mysql://localhost:3306/库名?useUnicode=true&amp&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
    String root = "root";
    String password = "密码";
    conn = DriverManager.getConnection(url,root,password);
    ps = conn.prepareStatement("sql语句");
    rs = ps.executeQuery();
    while (rs.next()){
        //获取数据
    }
} catch (Exception e) {
    e.printStackTrace();
}finally {
    try {
        conn.close();
        ps.close();
        rs.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

1.2、MyBatis

正是由于原始的JDBC各种问题所以才出现了一些框架出现,比如MyBatis。官网

MyBatis 是apache的一个开源项目,是一种半自动的对象关系映射(ORM)框架,它在Java对象和数据库的表之间建立映射关系(类对应表,属性对应字段),内部封装了JDBC相关操作,所以不用再去关注注册驱动、获取连接、执行 SQL、释放资源等操作,极大简化了持久层开发工作。其中SQL语句需要我们自己编写,虽然相对于自动的映射框架来说,增加了不少代码量,但是它有较高的灵活性,可以根据需要,自由地对SQL进行定制。

MyBatis 通过 XML 或注解配置Statement,并通过Java对象和Statement中的SQL进行映射生成最终执行的SQL语句,最后由MyBatis框架执行SQL并将结果映射成Java对象并返回。

MyBatis 有三个基本要素:

  • 核心组件(核心的类和接口)
  • MyBatis核心配置文件(mybatis-config.xml)
  • SQL映射器(mapper.xml)

MyBatis还有一种增强的工具版本 Mybatis-Plus,它是在Mybatis的基础上做了一些增强,在不改变MyBatis的基础上,简化了开发。

Mybatis的使用过程:

  • 添加mybatis的依赖

    <!--mysql8依赖-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    <!--mybatis依赖 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    <!-- junit的依赖,测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <!-- log4j 日志-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  • MyBatis 默认使用 log4j 输出日志信息,所以可以配置日志文件 log4j.properties

    ### 设置日志级别和输出位置 ###
    log4j.rootLogger=DEBUG,console,logFile
    log4j.additivity.org.apache=true
    
    # 输出到控制台(console)
    log4j.appender.console=org.apache.log4j.ConsoleAppender
    # 输出级别最低为DEBUG
    log4j.appender.console.Threshold=DEBUG		
    # 表示所有消息都会被立即输出
    log4j.appender.console.ImmediateFlush=true
    #输出日志到控制台的方式
    log4j.appender.console.Target= System.out
    # 灵活布局输出日志
    log4j.appender.console.layout=org.apache.log4j.PatternLayout
    #设定以怎样的格式显示消息。
    log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] [%c] [%p] -%m%n
    
  • 创建mybatis-config.xml配置文件

  • 编写,加载映射文件mapper.xml

  • 加载配置文件,创建SqlSessionFactory工厂,获取SqlSession

  • 调用mapper映射文件中的SQL语句来执行CRUD操作

  • 返回结果集的映射

2、核心组件


2.1、组件介绍

mybatis的核心组件主要有4部分

  • SqlSessionFactoryBuilder(构造器):它的作用仅仅用来生成 SqlSessionFactory,创建成功后就失去作用,所以用在生成 SqlSessionFactory 的方法中作为局部变量使用,用完即可回收。

    它通过内部的build(InputStream inputStream, String environment, Properties properties) 创建SqlSessionFactory,使用流读取配置文件。

  • SqlSessionFactory:相当于数据库的连接池,主要是用 openSession() 创建SqlSession接口,所以需要存在MyBatis的整个应用中。一般是创建一个单例模式,生命周期等同MyBatis的生命周期

  • SqlSession:相当于Connection对象,用于业务请求,用完关闭。存在于一次业务请求中,处理完请求后使用close方法关闭。

  • SQL Mapper(映射器):Mapper是通过SqlSession获取的,所以Mapper的生命周期小于SqlSession,它相当于一个请求中的业务处理。

2.2、SqlSessionFactory

SqlSessionFactory是 Mybatis的核心组件,每个MyBatis都是以一个SqlSessionFactory实例为中心,而它的作用就是生产SqlSession。

使用MyBatis需要配置 SqlSessionFactory 对象,通常使用 SqlSessionFactoryBuilder 的 build() 方法,SqlSessionFactory作为一个工厂接口,唯一的作用就是用来创建SqlSession的,所以我们一般会用单例模式来处理它。而一般选用通过XML配置的方式来生成 SqlSessionFactory。

  • XML配置SqlSessionFactory

    <?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>
        <!--setting设置-->
        <settings>
            <!--日志STDOUT_LOGGING和LOG4J-->
            <setting name="logImpl" value="LOG4J"/>
        </settings>
    
        <!--设置别名,对应的实体 -->
        <typeAliases>
            <typeAlias alias="名字" type="实体类路径"/>
        </typeAliases>
    
        <!-- 配置mybatis运行环境 -->
        <environments default="development">
            <environment id="development">
                <!-- 使用JDBC的事务管理 -->
                <transactionManager type="JDBC"/>
                <!--连接数据库-->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/数据库"/>
                    <property name="username" value="root"/>
                    <property name="password" value=""/>
                </dataSource>
            </environment>
        </environments>
    
        <!-- 加载将mapper文件 -->
        <mappers>
            <mapper resource="mapper文件路径"/>
        </mappers>
    </configuration>
    
  • 创建一个帮助类,读取xml文件,生成SqlSessionFactory

    public class SqlSessionUtil {
        private static SqlSessionFactory factory = null;
        static {
            try {
                InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
                factory = new SqlSessionFactoryBuilder().build(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        public static SqlSessionFactory getFactory(){
            return factory;
        }
    }
    

2.3、SqlSession

SqlSession是MyBatis的核心接口,其有两个实现类:其中DefaultSqlSession是单线程,SqlSessionManager是多线程。

它就相当于Connection对象,代表一个连接数据库的资源,每次需要获取和关闭。它提供了面向数据库执行 SQL 命令所需的所有方法,可以通过 SqlSession 实例直接运行已映射的 SQL 语句。

//SqlSession的获取,
SqlSession sqlSession = SqlSessionUtil.getFactory().openSession();

SqlSession具体的作用有3种:

  • 获取Mapper接口

    sqlSession.getMapper(***Mapper.class);	//创建的Mapper接口
    
  • 发送SQL给数据库

    String statement=“Mapper接口的全限定名+XML映射文件方法的id名(方法名)”
    Object parameter:插入所需的参数,通常是对象或者Map
    RowBounds rowBounds:用于分页,它的两个属性: offset指查询的当前页数; limit指当前页显示多少条数据。
    String mapKey:执查询结果会被封装成一个Map集合返回,key就是参数mapKey传入的列名,value 是封装的对象。
    ResultHandler handler:ResultHandler对象用来处理查询返回的复杂结果集,通常用于多表查询。

    public interface SqlSession extends Closeable {
    
      /**查询方法,查询结果只有一条数据时才使用。*/
      <T> T selectOne(String statement);
      <T> T selectOne(String statement, Object parameter);
    
      /**查询方法,返回执行SQL话句查询结果的泛型对象的集合。。*/
      <E> List<E> selectList(String statement);
      <E> List<E> selectList(String statement, Object parameter);
      <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
    
      /**查询方法,根据结果对象中的一个属性将结果列表转换为 Map */
      <K, V> Map<K, V> selectMap(String statement, String mapKey);
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
      <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
    
      /**Cursor 提供与 List 相同的结果,只是它使用 Iterator 懒惰地获取数据。*/
      <T> Cursor<T> selectCursor(String statement);
      <T> Cursor<T> selectCursor(String statement, Object parameter);
      <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
    
      /**使用ResultHandler检索从语句键和参数映射的单行。 */
      void select(String statement, Object parameter, ResultHandler handler);
      void select(String statement, ResultHandler handler);
      void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
    
      /**插入方法,返回执行SQL语句所影响的行数。。*/
      int insert(String statement);
      int insert(String statement, Object parameter);
    
      /**执行更新语句。将返回受影响的行数 */
      int update(String statement);
      int update(String statement, Object parameter);
    
      /**执行删除语句。将返回受影响的行数。*/
      int delete(String statement);
      int delete(String statement, Object parameter);
    
      /**提交事务。 */
      void commit();
      void commit(boolean force);
    
      /**回滚事务 */
      void rollback();
      void rollback(boolean force);
    
      /**刷新批处理语句*/
      List<BatchResult> flushStatements();
    
      /**关闭会话 */
      @Override
      void close();
    
      /**清除本地会话缓存。*/
      void clearCache();
    
      /**检索当前配置。 */
      Configuration getConfiguration();
    
      /**检索映射器*/
      <T> T getMapper(Class<T> type);
    
      /**检索内部数据库连接 */
      Connection getConnection();
    }
    
    
  • 控制数据库事务

    /**提交事务。 */
    void commit();
    void commit(boolean force);
    
    /**回滚事务 */
    void rollback();
    void rollback(boolean force);
    

2.4、映射器

MyBatis中最重要也是最复杂的组件,MyBatis是由一个Mapper接口,和一个XML映射文件(注解),对应以前的dao接口和一个dao实现类,它主要的作用是:

  • 描述映射规则
  • 提供SQL语句
  • 配置缓存
  • 提供动态SQL

2.4.1 接口和XML映射

在MyBatis中数据的一张表,分别对应一个实体类,Mapper接口、和一个XML的映射文件。

在IDEA中可以引入插件MyBatisCodeHelperPro,使用插件辅助创建所需的类。

在这里插入图片描述

在这里插入图片描述

  • 实体类:和数据表对应的实体类会自动创建好,并生成get和det方法。

    在这里插入图片描述

  • mapper:接口,编写查询所有的方法,如果映射的路径正确,点击创建,会自动在xml文件中创建好

    在这里插入图片描述

  • mapping:mapper的实现类,xml形式配置。

    它的映射规则是:

    先通过 mapper namespace=“com.yu.mapper.UserMapper” 映射到对应的接口

    然后通过select、update、delete、inser这些标签的 id 属性值映射得到接口对应的方法上

    再通过 resultMap、parameterType这两个属性可以将获得的结果集,映射到对应的实体类上进行自动装配。

    <?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是相应的Mapper接口的全限定名-->
    <mapper namespace="com.yu.mapper.UserMapper">
    
        <!--数据库的表和是实体类的映射关系,可以自己配置属性是另外一个实体的情况 -->
        <resultMap id="BaseResultMap" type="com.yu.pojo.User">
            <id column="user_id" jdbcType="INTEGER" property="userId" />
            <result column="username" jdbcType="VARCHAR" property="username" />
            <result column="password" jdbcType="VARCHAR" property="password" />
            <result column="deleted" jdbcType="BIT" property="deleted" />
        </resultMap>
    
        <!--数据表的字段,在本XML中可直接引用-->
        <sql id="Base_Column_List">
            user_id, username, `password`, deleted
        </sql>
    
        <!--和Mapper接口中的方法对应,select为查询属性, id为方法名, resultType为返回值-->
        <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
            <!--@mbg.generated-->
            select 
            <include refid="Base_Column_List" />
            from `user`
            where user_id = #{userId,jdbcType=INTEGER}
        </select>
    
        <!--    插入-->
        <insert id="insert" keyColumn="user_id" keyProperty="userId" parameterType="com.yu.pojo.User" useGeneratedKeys="true">
            <!--@mbg.generated-->
            insert into `user` (username, `password`, deleted)
            values (#{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{deleted,jdbcType=BIT})
        </insert>
    
        <!--删除-->
        <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
            <!--@mbg.generated-->
            delete from `user`
            where user_id = #{userId,jdbcType=INTEGER}
        </delete>
    
        <!--修改-->
        <update id="updateByPrimaryKeySelective" parameterType="com.yu.pojo.User">
            <!--@mbg.generated-->
            update `user`
            <set>
                <if test="username != null">
                    username = #{username,jdbcType=VARCHAR},
                </if>
                <if test="password != null">
                    `password` = #{password,jdbcType=VARCHAR},
                </if>
                <if test="deleted != null">
                    deleted = #{deleted,jdbcType=BIT},
                </if>
            </set>
            where user_id = #{userId,jdbcType=INTEGER}
        </update>
    </mapper>
    

2.4.2 发送SQL

通过SqlSession可以获取Mapper接口,它对比SqlSession发送的SQL语句,有很高的可读性,因为SqlSession需要使用自己的方法通过SQL的id属性去匹配相应的SQL,而Mapper则是直接使用自己定义的方法。

public class SqlSessionTest {
    @Test
    public void test(){
        SqlSession sqlSession = SqlSessionUtil.getFactoryBean().openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.selectByPrimaryKey(1);
        sqlSession.commit();
        System.out.println(user.getUsername());

    }
}

配置的日志打印的信息:

在这里插入图片描述

查到了数据

在这里插入图片描述

2.4.3、注解的形式

映射器中也有相应的注解来代替XML映射文件,来实现SQL语句,如果和XML同时定义,XML会覆盖掉注解.

public interface UserMapper {

    @Select("select user_id, username, `password`, deleted from `user` where user_id =#{userId}")
    User selectByPrimaryKey(Integer userId);

}

上面的这条注解语句可以代替下面这个:

<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    <!--@mbg.generated-->
    select 
    <include refid="Base_Column_List" />
    from `user`
    where user_id = #{userId,jdbcType=INTEGER}
</select>

虽然注解的形式要简单很多,但是很多的 sql语句的复杂性是很高的,这种复杂的sql语句放在XML文件中更适合,而且他还可能牵扯到一些动态 SQL等问题,所以还是推荐使用XML的方式。

2.5、执行器

MyBatis整体操作无非就是:连接数据库、编译生成SQL语句、执行SQL、获取数据进行封装等几个步骤,其中执行器就是用来执行SQL语句的,存在于SqlSession中。

在这里插入图片描述

MyBatis有三种基本的执行器:

  1. 简单执行器SimpleExecutor:每次执行update或select都会开启一个statement对象,用完立刻关闭statement对象
  2. 可重用执行器ReuseExecutor:执行update或select前,以sql作为key查找Statement对象,存在就使用不存在就创建,用完后不关闭,放置在Map中供下一次使用。(重复使用)
  3. 批量执行器BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
        executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
        executor = new ReuseExecutor(this, transaction);
    } else {
        executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
        executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

2.6、mybatis流程

在这里插入图片描述

  1. 读取MyBatis的核心配置文件:读取配置数据库的连接、属性、类别名、映射器等信息。
  2. 加载映射文件:Mapping.xml映射文件,用来配置操作数据库的SQL语句,可以通过xml和注解获取
  3. 构造会话工厂获取SqlSessionFactory:通过SqlSessionFactoryBuilder对象构建
  4. 创建会话对象SqlSession:包含了执行SQL的一些方法
  5. Executor执行器:mybatis的核心,用来SQL语句的生成和查询缓存的维护
  6. Statement对象:对SQL语句的封装,一个对象对应XML文件中的一个sql语句标签。
  7. 输入参数映射:传递参数,进行预编译处理
  8. 封装结果集:将SQL语句产生的数据进行封装

相关文章:

  • 《计算几何》学习笔记
  • 干货分享:Docker 容器应用示例
  • 闭包的定义,原理,应用场景,优点,缺点
  • js控制台输出佛祖保佑图形图案/彩色图形图案实例代码
  • 黑客进行攻击中最重要的环节“信息收集”
  • Vue(6)
  • JSON 数据类型转换工具
  • CSP-J 2019 入门级 第一轮 第17题
  • 小程序map组件一——使用腾讯地图个性化地图组件、腾讯云可视化大屏展示
  • 【项目实战】高并发内存池
  • go语言|数据结构:二叉树可视化(svg树形图改进版)
  • JVM - 垃圾回收方式性能研究
  • flink笔记2(Flink 快速上手)
  • k8s部署服务+日志收集+监控系统+CICD自动化
  • Docker Compose
  • [iOS]Core Data浅析一 -- 启用Core Data
  • [数据结构]链表的实现在PHP中
  • echarts的各种常用效果展示
  • extjs4学习之配置
  • git 常用命令
  • Golang-长连接-状态推送
  • javascript从右向左截取指定位数字符的3种方法
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • python学习笔记 - ThreadLocal
  • SpiderData 2019年2月16日 DApp数据排行榜
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 搭建gitbook 和 访问权限认证
  • 代理模式
  • 等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规
  • 回顾 Swift 多平台移植进度 #2
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $NOIp2018$劝退记
  • (5)STL算法之复制
  • (vue)页面文件上传获取:action地址
  • (附源码)springboot 基于HTML5的个人网页的网站设计与实现 毕业设计 031623
  • (九十四)函数和二维数组
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)四层和七层负载均衡的区别
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .NET Core WebAPI中封装Swagger配置
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • .NET 使用 XPath 来读写 XML 文件
  • .net 托管代码与非托管代码
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET程序员迈向卓越的必由之路
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • .Net转前端开发-启航篇,如何定制博客园主题