MyBatis学习笔记

基于教程or博客:

【尚硅谷】SSM框架教程

MyBatis学习笔记----Matty‘s Blog

本机环境:

  • IDEA 2021.2.3
  • JDK 15
  • Maven 3.6.0
  • MySQL8
  • MyBatis 3.5.7

1.简介介绍

在官方中文站上面是这么写的

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

所谓持久层,简单言之就是将数据固定保存的一大坨代码。在电脑上有两个数据存储的地方,RAM(内存)和ROM(硬盘)。RAM中的数据是短暂的,当你关闭电脑之后这里面的数据就会消失。有时候我们想将数据在RAM中保存下来,就需要持久层发挥作用,将内容保存到ROM中,这样我们才可以长期获得相同的数据。

后面的,其实就是大概说明MyBatis是如何方便我们写SQL,操作数据库。

1.1历史

MyBatis起源于Apache的一个开源项目ibatis。所以有的时候在导入包的时候,会发现包名是ibatis。

1.2特点

  • 自定义SQL:就是可以按照自己的需求手写SQL语句。
  • 支持存储过程
  • 支持高级映射:可以自定义POJO和数据库字段之间的映射。

1.3对比其他持久层框架

  • JDBC:缺点是SQL是夹杂在JAVA文件中的,耦合度高,导致硬编码内伤。此外,对后期的维护不易,因为实际的开发需求中SQL发生变化,经常修改的情况非常多。最后是代码非常多,开发效率低下。
  • Hibernate和JPA:这两种虽然开发效率高,操作简便,但是由于是内部生成SQL语句,所以不容易对项目做出特殊的优化。另外由于反射操作过多,导致性能下降。而且两者都是基于全映射的全自动框架,大量字段的POJO进行部分映射的时候会比较困难。

不过,Hibernate和JPA在后续的发展过程中,据说在性能和操作方面已经是大幅度超过MyBatis了。在国外发起的开发框架投票中,JPA的使用者占到了一半以上,相比之下MyBatis只有百分之二十。不过在我学习的现在,国内主流框架还是MyBatis+一堆插件(比如MyBatis-plus)

2.快速开始-第一个MyBatis程序

2.0 设计表以及添加数据

因为设计表仅仅为了学习Mybatis,所以不需要太复杂,简单设计几个字段即可。

CREATE TABLE `t_user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(20) DEFAULT NULL,
  `age` int DEFAULT NULL,
  `gender` char(1) DEFAULT NULL,
  `email` char(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3;

2.1 创建Maven项目以及导入相关依赖

这里如果没学过Maven的话,墙裂建议先去了解学习一下,非常非常好用。操作也十分简单,基本上两个小时就可以了解大概。之后就是在实际应用中不断使用加强记忆了。

这里导入的依赖主要有四个,第一个是mybaits核心依赖,第二个是Junit测试依赖,第三个是MySQL依赖,第四个log4j日志依赖

<dependencies>
    <!-- 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.12</version>
        <scope>test</scope>
    </dependency>

    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>
    
    <!-- log4j -->
	<dependency>
    	<groupId>log4j</groupId>
    	<artifactId>log4j</artifactId>
    	<version>1.2.17</version>
	</dependency>
</dependencies>

CV完之后,更新一下POM,稍等片刻,你就会发现学习MyBatis所需要的所有依赖都已自动下载好了!!(这么激动的原因是,以前都是手动导包。你大概也经历过,去网上搜索,下载的时候大概率还要忍受某度网盘的速度,而且更加绝望的是,你有可能最后发现你下载半天的jar包还和你的版本不匹配。)

导入之后先别急着进行下一步。这里先把主项目目录下的src文件删除。然后再新建一个Maven模块。这样,子pom会自动继承父pom的依赖,免去我们每次新建项目都要重新导入依赖的麻烦,此外还可以帮助我们更好的管理和编写代码。

2.2 配置MyBatis核心文件

配置文件都写在XML文件中,这里面包含了MyBatis系统的核心设置。比如获取数据库连接实例的数据源,决定事务作用域和控制方式的事务管理。

创建完项目之后,需要在src/main/resources目录下面新建mybatis-config.xml文件。然后补充下面的内容。

在这里,我们习惯上命名为:mybatis-config.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 : 选择那个环境有效
     -->
    <environments default="development">
        <environment id="development">

            <!-- 事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>

            <!-- 数据源 即连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://这里是本机数据库地址?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=utf-8amp;autoReconnect=true"/>
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 引入 MyBatis 的映射文件 : 存放SQL语句 和 POJO的映射方式
 		这个文件是后面再写的,这里可以先空着-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml"></mapper>
    </mappers>
</configuration>

2.3 UserMapper接口

类似于DAO,不过不需要创建一个实现类。而是通过Mybatis来创建代理实现类,并执行映射文件中编写的SQL语句

习惯上的起名是 POJO+Mapper

package com.atguigu.mybatis.mapper;

public interface UserMapper {
    int insertUser();
}

2.4 UserMapper映射文件

接下来在resources文件下新建一个UserMapper.xml文件。在这个文件中,Mapper文件中的一个抽象方法,一一对应映射文件中的一条SQL语句。

<?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接口 -->
<mapper namespace="com.atguigu.mybatis.mapper.UserMapper">
    <!--
        id : 对应接口的方法名称。一定要确保id和抽象方法一致,否则会报错
    -->
    <select id="insertUser">
        INSERT INTO t_user VALUES (NULL, 'admin', '123456', 23, '男', '12345@qq.com');
    </select>
</mapper>

2.5 log4j配置文件

这里的log4j配置文件,并非是MyBatis运行的必要条件。这里添加的原因是可以方便定位报错位置。

在log4j中有不同的日志级别:FATAL(致命) > ERROR(错误) > WARN(警告)> INFO(信息) > DEBUG(调试)

从左到右打印的内容会越来越详细

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5d %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n"/>
        </layout>
    </appender>

    <logger name="java.sql">
        <level value="debug"/>
    </logger>
    <logger name="org.apache.ibatis" >
        <level value="info"/>
    </logger>

    <!-- 默认配置,级别为debug 且根据name为log.console和 log.file两个appender输出-->
    <root>
        <level value="debug"/>
        <appender-ref ref="STDOUT"/>
    </root>
</log4j:configuration>

2.6 测试功能

最后,在test/java中编写测试类。

package com.atguigu.mybatis;

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 org.junit.Test;
import com.atguigu.mybatis.mapper.UserMapper;

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

public class MyBatisTest {
    @Test
    public void testInsert() throws IOException {
        // 获取核心配置文件的输入流
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");

        // 获取SqlSessionFactoryBuilder 对象 -> 工厂构建器
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 创建 SqlSession 工厂 -> 创建会话
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resourceAsStream);

        // 获取 会话 对象 -> MyBatis 提供的操作数据库的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 获得Mapper接口的代理类 -> 操纵Mapper类执行数据库操作
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        // 执行SQL操作
        Integer rows = userMapper.insertUser();
        System.out.println("rows = " + rows);

        // 提交事务 -> 事务是默认开启的
        sqlSession.commit();

        // 关闭资源
        sqlSession.close();
    }
}

最后,刷新一下数据库,就可以在数据库中看到插入的数据了。

3. 初步了解核心配置文件

3.1 environments

顾名思义,就医配置MyBatis当前工作数据库环境的的地方。需要注意这里的标签是复数的,也就是可以配置多个环境(environment),此时使用唯一的ID属性来区分不同的环境。

以我们上面配置的文件为例,复数标签中的default属性表示默认hi使用的环境ID。

    <environments default="development">
        <environment id="development">

            <!-- 事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>

            <!-- 数据源 即连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://这里是本机数据库地址?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=utf-8amp;autoReconnect=true"/>
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>

3.1.1 transactionManager

            <!-- 事务管理器 -->
            <transactionManager type="JDBC"></transactionManager>

这里使用type属性来设置事务管理器的类型。

JDBC表示使用JDBC原生事务管理方式,可以手动的开启关闭事务,手动提交回滚事务。

MANAGED:被管理的,也就是其他的事务管理方式。例如可以使用Spring来管理事务。

3.1.2 DataSource

            <!-- 数据源 即连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://这里是本机数据库地址?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;characterEncoding=utf-8amp;autoReconnect=true"/>
                <property name="username" value="用户名"/>
                <property name="password" value="密码"/>
            </dataSource>

主要作用是设置数据源,属性type就是数据源的类型,比如POOLED就是使用数据库连接池,还可以设置UNPOOLED(不使用数据库连接池,每个链接直接重新创建)和JNDI(使用上下文中的数据源)

其中的子标签都是配置标签,是用来配置连接数据库的相关信息。

3.2 引入jdbc.properties

本质上就是将datasource中的配置信息提取,放在jdbc.properties文件中,如果需要使用,就直接在核心配置文件中引入即可直接使用。

提取配置信息,在resources目录下新建文件jdbd.properties

jdbc.url=jdbc:mysql://192.168.23.128:3306/ssm?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&autoReconnect=true
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=123456

引入文件,直接使用

<?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>
    <!-- 引入 properties 文件 -->
    <properties resource="jdbc.properties"></properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/UserMapper.xml"></mapper>
    </mappers>
</configuration>

3.3 typeAliases

类型别名,设置之后就可以在Mapper中的resultType属性中使用简单类型别名。

3.4 settings

是核心全局设置,常用的有下划线转驼峰,延迟加载等。其他的一些设置都可以在官方文档中找到。

3.4.1 下划线转驼峰

<settings>
    <!-- 下划线 自动映射 驼峰 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

3.4.2 延迟加载

<settings>
    <!-- 延迟加载
        LazyLoadingEnabled: true,开启延迟加载
        aggressiveLazyLoading: false, 开启按需加载
    -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

3.5 Mappers

引入Mapper映射文件主要有两种方式,单个文件引入和包引入。

<mappers>
    <mapper resource="mappers/UserMapper.xml"></mapper>

    <!--
        包扫描方式, 两个条件
        1. Mapper 接口和 Mapper.xml 必须在一个包下
        2. Mapper 接口必须和 Mapper.xml 名字一致
     -->
    <package name="com.atguigu.mybatis.mapper"/>
</mappers>

4. 不同类型参数的获取

在MyBatis中,获取输入参数的方式有两种,分别是 #()$() 。两者的大致功能都类似,只不过在处理特殊场景时使用不同的方式会比较便捷。在实际使用中,最常使用的是#{}

总的来说,获取参数的情况可以分为:获取单个字面量参数,获取多个字面量参数,获取单个POJO,以及Map等集合。

4.1 获取单个字面量参数

在MyBatis中获取单个参数的方法十分简单,只需要在sql语句中使用#{}和${}来表示参数即可。需要注意的是,前者使用的方式是占位符方式,后者使用的是字符串拼接的方式。

public User getUserByUsername(String username);
//这里是mapper接口中的方法。
<!-- 占位符方式 -->
<select id="getUserByUsername" resultType="user">
    SELECT * FROM t_user WHERE username = #{username};
</select>

<!-- 字符串拼接方式 -->
<select id="getUserByUsername" resultType="user">
    SELECT * FROM t_user WHERE username = '${username}';
</select>

4.2 获取多个字面量参数

当Mapper接口中的方法有多个参数的时候,MyBatis会创建Map,使用paramX或者argX为键,参数为值,在使用的时候就需要按照输出的参数顺序,获取需要的不同的参数。

User checkLogin(String username, String password);
<select id="checkLogin" resultType="user">
    SELECT * FROM t_user WHERE username = #{param1} and password = #{param2};
</select>

<select id="checkLogin" resultType="user">
    SELECT * FROM t_user WHERE username = #{arg0} and password = #{arg1};
</select>

因为使用paramX或argX需要记忆参数的位置,在实际开发中较为不便。因而现在常用的是在Mapper接口的方法参数前添加@Param()注解,在注解中设置参数的别名(一般也就是参数名),这样就可以在XML文件直接使用参数名获取需要的参数了。

User checkLogin(@Param("username") String username, @Param("password") String password);
<select id="checkLogin" resultType="user">
    SELECT * FROM t_user WHERE username = #{username} and password = #{password};
</select>

4.3 获取单个POJO

需要注意的是,POJO中必须有getter和setter方法,因为属性只跟getter/setter有关系;单个POJO会形成一个Map,属性名作为键,getter后面的值作为值。

void insertUser(User user);
<select id="insertUser">
	insert into t_user values (null, #{username}, #{password}, #{age}, #{gender}, #{email})
</select>

4.4 在Map中获取

/**
 * {username: "xxxx"}
 * {password: "xxxx"}
 * @param map
 * @return
 */
User checkLoginByMap(Map<String, Object> map);
<!-- User checkLoginByMap(Map<String, Object> map); -->
<select id="checkLoginByMap" resultType="user">
    SELECT * FROM t_user WHERE username = #{username} and password = #{password};
</select>

MyBatis的缓存

1.一级缓存

一级缓存是sqlSession级别的缓存。默认是自动开启的。从一个sqlSession中查询出来的数据会被缓存,当再一次在同一sqlSession中查询同一条记录时会直接从缓存中获取。

在以下情况中,一级缓存会失效:

  1. 不同的sqlSession对应不同的一级缓存
  2. 同一个sqlSession但是查询条件不同
  3. 同一个sqlSession两次查询期间执行了任一增删改操作
  4. 同一个sqlSession两次查询期间手动清空了缓存

2.二级缓存

二级缓存是sqlSessionFactory级别的缓存,需要手动开启。通过同一个sqlSessionFactory创建的sqlSession查询的结果会被缓存,之后如果再次执行同样的操作,会直接从缓存中获取数据。

二级缓存开启的条件:

  1. 在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置。
  2. 在映射文件中设置标签cache
  3. 二级缓存必须在sqlSession关闭或者提交之后有效
  4. 查询的数据所转换的实体类型必须实现序列化接口

二级缓存失效的条件:在两次查询之间执行了任一增删改操作。

二级缓存的相关配置

了解即可,暂时使用默认设置。

  • eviction属性:缓存回收策略,默认是LRU

  • flushInterval属性:刷新间隔,默认不设置。

  • size属性:缓存最多可以存储多少个对象,过大会导致内存溢出。

  • readOnly属性:只读属性,有true和false两个值。

    true表示只读缓存,会给所有调用者返回缓存对象的相同实例,因此这些对象不能修改,这提供了很重要的性能优势。

    false表示读写缓存,会通过序列化返回缓存对象的拷贝,这样一来速度会慢一些,但是安全,因此是默认设置。

缓存查询顺序

先查询二级缓存(前提是二级缓存已开启),因为二级缓存中可能有其他程序已经查询得到的数据,可以拿来直接使用。如果二级缓存中没有,再查询一级缓存,如果一级缓存中也没有命中,则会直接查询数据库。sqlSession关闭之后,一级缓存中的数据会写入二级缓存。

整合第三方缓存EHCache

第三方缓存主要是针对二级缓存。了解即可,无需专门记忆。

逆向工程

正向工程:先创建Java实体类,由框架负责实体类生成数据表。Hibernate是支持正向工程的。

逆向工程:先创建数据库表,由框架负责根据数据库表反向生成以下资源:

  1. Java实体类
  2. Mapper接口
  3. Mapper映射文件

逆向工程在工作中使用很少,这里只是粗略看过了视频了解,也没有深入学习。以后工作了遇到了再来学习吧。

分页插件

posted @ 2023-02-01 19:39  Thales_ZeeWay  阅读(24)  评论(0)    收藏  举报