Mybatis归纳

1. 简介

1.1 什么是Mybatis

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CIIKgeid-1648975231457)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220331141433028.png)]

如何获得Mybatis?

  • maven仓库

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    
  • GitHub

    https://github.com/mybatis/mybatis-3/releases

  • 中文文档

    https://mybatis.org/mybatis-3/zh/index.html

1.2 持久化

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SY7deRDw-1648975231457)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220331170004515.png)]

1.3 持久层

Dao层, Service层, Controller层…

  • 完成持久化工作的代码块
  • 层界限十分明显

1.4 为什么需要Mybatis?

  • 帮助程序猿将数据存入到数据库中。
  • 方便
  • 传统的JDBC代码太复杂了。简化。框架。自动化。
  • 不用Mybatis也可以。 更容易上手。 技术没有高低之分
  • 优点:
    • 简单易学
    • 灵活
    • sq|和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。

2. 第一个Mybatis程序

顺序: 搭建环境 --> 导入Mybatis --> 编写代码 --> 测试!

2.1 搭建环境

  • 搭建数据库
CREATE DATABASE `mybatis`;

USE `mybatis`;

CREATE TABLE `user`(
		`id` INT(20) NOT NULL PRIMARY KEY,
		`name` VARCHAR(30) DEFAULT NULL,
		`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
		(1,'tom','123456'),
		(2,'jack','123456'),
		(3,'jason','654321')
  • 新建项目

    1. 新建一个普通的maven项目

    2. 删除src目录

    3. 导入maven依赖

      <!--导入依赖-->
      <dependencies>
          <!--mysql驱动-->
          <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>8.0.21</version>
          </dependency>
          <!--mybatis-->
          <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
          <dependency>
              <groupId>org.mybatis</groupId>
              <artifactId>mybatis</artifactId>
              <version>3.5.6</version>
          </dependency>
          <!--junit-->
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.11</version>
              <scope>test</scope>
          </dependency>
      </dependencies>
      

2.2 创建一个模块

  • 编写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核心配置文件-->
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
    
    </configuration>
    
  • 编写Mybatis工具类

    package com.xz.utils;
    
    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;
    
    /**
     * @author 许正
     * @version 1.0
     */
    //sqlSessionFactory --> sqlSession
    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            //使用Mybatis第一步: 获取sqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            try {
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        // 既然有了SqlSessionFactory,顾名思义,我们就可以从中获得 SqlSession 的实例了。
        // SqlSession 完全包含了面向数据库执行SQL命令所需的所有方法。
        public static SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
        }
    }
    

2.3 编写代码

  • 实体类

    package com.xz.pojo;
    
    /**
     * @author 许正
     * @version 1.0
     */
    //实体类
    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        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 String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    }
    
  • Dao接口

    package com.xz.dao;
    
    import com.xz.pojo.User;
    
    import java.util.List;
    
    /**
     * @author 许正
     * @version 1.0
     */
    public interface UserDao {
        List<User> getUserList();
    }
    
  • 接口实现类由原来的UserDaoImpl转变为一个 Mapper配置文件.

    <?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 = 绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.xz.dao.UserDao">
        <!--select查询语句-->
        <select id="getUserList" resultType="com.xz.pojo.User">
            select * from mybatis.user
        </select>
    </mapper>
    

2.4 测试

注意:

org.apache.ibatis.binding.BindingException: Type interface com.xz.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么?

核心配置文件中注册mappers

  • junit测试
package com.xz.dao;

import com.xz.pojo.User;
import com.xz.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

/**
 * @author 许正
 * @version 1.0
 */
public class UserDaoTest {

    @Test
    public void test(){

        //第一步: 获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一: getMapper
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();

        for (User user : userList) {
            System.out.println(user);
        }

        //关闭SqlSession
        sqlSession.close();
    }
}

可能会遇到的问题:

  1. 配置文件没有注册
  2. 绑定接口错误。
  3. 方法名不对
  4. 返回类型不对
  5. Maven导出资源问题

3. CRUD

3.1 namespace

namespace中的包名要和 Dao/Mapper 接口的包名一致!

3.2 select

选择,查询语句:

  • id: 就是对应的namespace中的方法名
  • resultType: Sql语句执行的返回值!
  • parameterType: 参数类型
  1. 编写接口

    //查询全部用户
    List<User> getUserList();
    
  2. 编写对应的mapper中的sql语句

    <select id="getUserById" parameterType="int" resultType="com.xz.pojo.User">
        select *
        from mybatis.user
        where id = #{id};
    </select>
    
  3. 测试

    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        User user = mapper.getUserById(1);
        System.out.println(user);
    
        sqlSession.close();
    }
    

3.3 insert

sql语句

<insert id="addUser" parameterType="com.xz.pojo.User">
    insert into mybatis.user(id, name, pwd)
    values (#{id}, #{name}, #{pwd})
</insert>

3.4 updete

<update id="updateUser" parameterType="com.xz.pojo.User">
    update mybatis.user
    set name = #{name},
        pwd  = #{pwd}
    where id = #{id};
</update>

3.5 delete

<delete id="deleteUser" parameterType="int">
    delete
    from mybatis.user
    where id = #{id};
</delete>

注意!!!

  • 增删改需要提交事务

3.6 可能出现的错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GIgxxPGs-1648975231458)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401173958501.png)]

3.7 万能Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!

  1. 编写接口

    //万能的Map
    int addUser2(Map<String, Object> map);
    
  2. 编写对应的mapper中的sql语句

    <insert id="addUser2" parameterType="map">
        insert into mybatis.user(id, name)
        values (#{userId}, #{userName});
    </insert>
    
  3. 测试

    @Test
    public void addUser2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        Map<String, Object> map = new HashMap<>();
        map.put("userId", 5);
        map.put("userName", "zeaper");
    
        mapper.addUser2(map);
    
        sqlSession.commit();
        sqlSession.close();
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FKaQKRHs-1648975231458)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401175922292.png)]

3.8 模糊查询

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K65cKP6k-1648975231459)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401180657440.png)]

建议使用第一种方式,可以防止Sql注入!

4. 配置解析

4.1 核心配置文件

  • mybatis-config.xml

  • Mybatis 的配置文件包含了会深深影响 Mybatis 行为的设置和属性信息.

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LFX7OkVs-1648975231459)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401181133004.png)]

4.2 环境变量 (environments)

MyBatis可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境。
学会使用配置多套运行环境!
Mybatis默认的事务管理器就是JDBC,连接池: POOLED

4.3 属性 (properties)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENnSn25Z-1648975231461)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401210936184.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kZfQZaDg-1648975231462)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401211055991.png)]

编写一个配置文件

driver=com.mysql.jdbc.Driver
url=jdbc:jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8
username=root
password=root

在核心配置文件中引入

<!--引入外部配置文件-->
<properties resource="db.properties"/>

db.properties 文件如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrV3DvnI-1648975231462)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401212357081.png)]

  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的!

4.4 typeAliases (类型别名)

  • 类型别名是为Java类型设置一个短的名字。

  • 存在的意义仅在于用来减少类完全限定名的冗余。

  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的Java Bean,比如:

    扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!

    <!--可以给实体类起别名-->
    <typeAliases>
        <!--<typeAlias type="com.xz.pojo.User" alias="User"/>-->
        <package name="com.xz.pojo"/>
    </typeAliases>
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4yTxFTeG-1648975231462)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220401213645489.png)]

4.5 设置

这是MyBatis中极为重要的调整设置,它们会改变MyBatis的运行时行为。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AcgZfqQi-1648975231463)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402091718837.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PBzTdZyC-1648975231464)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402091733576.png)]

4.6 其他配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OjSBbZQ9-1648975231465)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403092401409.png)]

  • 全局缓存

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XgxBSFIk-1648975231465)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403150523236.png)]

4.7 映射器 (mappers)

MapperRegistry: 注册绑定我们的Mapper文件;

方式一:

<mappers>
    <mapper resource="com/xz/dao/UserMapper.xml"/>
</mappers>

方式二: 使用class文件绑定注册

<mappers>
    <mapper class="com.xz.dao.UserMapper"/>
</mappers>

方式三: 使用扫描包进行注入绑定

<mappers>
    <package name="com.xz.dao"/>
</mappers>

方式二和方式三需注意:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xDfRjfBP-1648975231466)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402093157460.png)]

4.8 作用域(Scope)和生命周期

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yqaQ4tKn-1648975231466)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402093552679.png)]

生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0HkQFRVw-1648975231467)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402093746655.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m4wCticU-1648975231468)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402093937292.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bSyAMxyO-1648975231468)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402093947215.png)]

5. 解决属性名和字段名不一致的问题

5.1 问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdn9dnuB-1648975231469)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402094632138.png)]

测试会出现问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FW2ohnkt-1648975231469)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402095456522.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a6F16iuU-1648975231470)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402095542671.png)]

5.2 解决方案

  • 起别名

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDHankoh-1648975231471)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402100517471.png)]

  • resultMap

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHitUsQ7-1648975231471)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402101724852.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eblb25jZ-1648975231472)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402102238962.png)]

6. 日志

6.1 日志工厂

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wTW7HwB1-1648975231472)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402102709996.png)]

  • SLF4J
  • LOG4J(deprecated since 3.5.9) [掌握]
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING [掌握]
  • NO_LOGGING

在Mybatis中具体使用哪个日志实现, 在设置中设定!

6.2 STDOUT_LOGGING

STDOUT_LOGGING : 标准日志输出

在mybatis核心配置文件中,配置我们的日志!

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1xdxeWHQ-1648975231473)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402103714339.png)]

6.3 LOG4J

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cbiTy1fq-1648975231473)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402104237439.png)]

  1. 先导入log4j的包

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
    
  2. log4j.properties

    log4j.rootLogger=debug, stdout, R
    
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    
    # Pattern to output the caller's file name and line number.
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
    
    log4j.appender.R=org.apache.log4j.RollingFileAppender
    log4j.appender.R.File=example.log
    
    log4j.appender.R.MaxFileSize=100KB
    # Keep one backup file
    log4j.appender.R.MaxBackupIndex=5
    
    log4j.appender.R.layout=org.apache.log4j.PatternLayout
    log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
    
  3. 配置log4j为日志的实现

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
  4. Log4j的使用! 直接测试运行刚才的查询

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tropuogW-1648975231473)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402111137485.png)]

简单使用

  1. 在要使用Log4j的类中,导入包

    import org.apache.log4j.Logger;

  2. 日志对象, 参数为当前类的class

    static Logger logger = Logger.getLogger(UserDaoTest.class);
    
  3. 日志级别

    logger.info("info: 进入了testLog4j");
    logger.debug("debug: 进入了testLog4j");
    logger.error("error: 进入了testLog4j");
    

7. 分页

为什么要分页?

  • 减少数据的处理量

7.1 使用limit分页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y2oOo23T-1648975231473)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402113145941.png)]

使用Mybatis实现分页, 核心Sql:

  1. 接口

    //分页
    List<User> getUserByLimit(Map<String, Integer> map);
    
  2. Mapper.xml

    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select *
        from mybatis.user
        limit #{startIndex}, #{pageSize}
    </select>
    
  3. 测试

    @Test
    public void getUserByLimit() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        Map<String, Integer> map = new HashMap<>();
        map.put("startIndex", 1);
        map.put("pageSize", 2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    

7.2 RowBounds分页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-flkni6Go-1648975231474)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402153726412.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hUpNZy9m-1648975231474)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402153739441.png)]

7.3 分页插件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXhj8HFu-1648975231474)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402153845035.png)]

了解即可,万一以后公司的架构师,说要使用,你需要知道它是什么东西!

8. 使用注解开发

8.1 面向接口编程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCjMpJ0X-1648975231475)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402154326150.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MpGQeGh7-1648975231475)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402154338292.png)]

8.2 使用注解开发

  1. 注解在接口上实现

    public interface UserMapper {
        @Select("select * from mybatis.user")
        List<User> getUsers();
    }
    
  2. 需要在核心配置文件中绑定接口!

    <!--绑定接口-->
    <mappers>
        <mapper class="com.xz.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void getUserList() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        //本质: 反射机制实现
        //底层: 动态代理!
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        for (User user : mapper.getUsers()) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    

8.3 CRUD

  1. 我们可以在工具类创建的时候实现自动提交事务!

    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }
    
  2. 编写接口,增加注解

    public interface UserMapper {
        @Select("select * from mybatis.user")
        List<User> getUsers();
    
        //方法存在多个参数, 在所有的参数前面必须加上 @Param 注解
        @Select("select * from user where id = #{id}")
        User getUserById(@Param("id") int id);
    
        @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
        int addUser(User user);
    
        @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
        int updateUser(User user);
    
        @Delete("delete from user where id=#{id}")
        int deleteUser(int id);
    }
    
    
  3. 测试类

    public class UserMapperTest {
    
        @Test
        public void getUserList() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
    //        int user = mapper.addUser(new User(2, "飞飞公主", "555666"));
    //        int user = mapper.updateUser(new User(3, "秋山帅豪", "789456"));
            int user = mapper.deleteUser(5);
            System.out.println(user);
    
            sqlSession.close();
        }
    
    
    }
    

注意:我们必须要将接口注册绑定到我们的核心配置文件中!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V20KdlCR-1648975231477)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402171921228.png)]

${} 和 #{} 区别: 使用#{}可以有效的防止sql注入,提高系统的安全性

详细区别:https://blog.csdn.net/weixin_41231928/article/details/105120292

9. Lombok

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wlXmJCm6-1648975231477)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402172332013.png)]

9.1 使用步骤

  1. 在IDEA中安装Lomcok插件!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xh8g0n0W-1648975231477)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402174110256.png)]

  2. 在项目中导入Lombok的jar包

    <dependencies><dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency></dependencies>
    
  3. 在实体类上加注解即可!

    package com.xz.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author 许正
     * @version 1.0
     */
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String password;
    
    
    }
    

效果图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AgMUwJJh-1648975231478)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402174217190.png)]

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var

说明:

@Data : 无参构造,get、 set、tostring、hashcode,equals
@Getter and @Setter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor

Lombok既有有点又有缺点, 简化了我们的代码, 但降低了可读性, 尽量自己写比较好.

10. 多对一处理

多对一:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMv8WbG4-1648975231478)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402174743419.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5bV8CIbD-1648975231478)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402175101774.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6gYuwow-1648975231478)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402175230433.png)]

10.1 测试环境搭建

  1. 导入lombok (也可自己写)
  2. 新建实体类Teacher, Student
  3. 建立Mapper接口
  4. 建立Mapper.xml文件
  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件! [方式很多, 随心选]
  6. 测试查询是否能够成功!

10.2 按照查询嵌套处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aGbsx3eJ-1648975231478)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402212536640.png)]

10.3 按照结果嵌套处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mN9zS2Dt-1648975231479)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402213001273.png)]

回顾Mysql 多对一查询方式:

  • 子查询
  • 联表查询

11. 一对多处理

比如: 一个老师拥有多个学生!
对于老师而言,就是一对多的关系!

11.1 环境搭建

  • 和刚才一样

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bOhFDYB7-1648975231479)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220402213701727.png)]

11.2 按照结果嵌套处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZmQXy7uP-1648975231479)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403081647253.png)]

11.3 按照查询嵌套处理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s0Pz504n-1648975231480)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403082321374.png)]

小结

  1. 关联 - association [多对一 ]
  2. 集合 - collection [一对多]
  3. javaType & ofType
    1. JavaType用来指定实体类中属性的类型
    2. ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!

注意点

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题!
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j

面试高频

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLRSgQjD-1648975231480)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403083451156.png)]

12. 动态SQL

什么是动态SQL : 动态SQL就是指根据不同的条件生成不同的SQL语句

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面, 去执行一些逻辑代码

利用动态SQL这一特性可以彻底摆脱这种痛苦。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWqkqvXB-1648975231481)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403084309357.png)]

12.1 搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

创建一个基础工程:

  1. 导包

  2. 编写配置文件

  3. 添加工具类

  4. 编写实体类

    package com.xz.pojo;
    import lombok.Data;
    import java.util.Date;
    /**
     * @author 许正
     * @version 1.0
     */
    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    
  5. 编写实体类对应的 Mapper接口 和 Mapper.xml

    package com.xz.dao;
    
    import com.xz.pojo.Blog;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author 许正
     * @version 1.0
     */
    public interface BlogMapper {
    
        //添加数据
        int addBlog(Blog blog);
    
        //查询博客
        List<Blog> queryBlogIf(Map map);
    }
    
    <?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.xz.dao.BlogMapper">
    
        <insert id="addBlog" parameterType="blog">
            insert into mybatis.blog (id, title, author, create_time, views)
            values (#{id}, #{title}, #{author}, #{createTime}, #{views});
        </insert>
    
        <select id="queryBlogIf" parameterType="map" resultType="blog">
            select * from mybatis.blog where 1=1
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </select>
    </mapper>
    

12.2 if

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog where 1=1
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</select>

12.3 choose(when, otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>

            <otherwise>
                and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

12.4 trim(where, set)

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from mybatis.blog
    <where>
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>
<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </set>
    where id = #{id};
</update>

12.5 SQL片段

有的时候,我们可能会将一些公共的部分抽取出来,方便复用!

  1. 使用SQL标签抽取公共的部分

    <sql id="if-title-author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </sql>
    
  2. 在需要使用的地方使用Include标签引用即可

    <select id="queryBlogIf" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <include refid="if-title-author"></include>
        </where>
    </select>
    

注意事项:

  • 最好基于单表来定义SQL片段
  • SQL片段不要存在where标签

12.6 foreach

select * from `user` where 1=1 and 
    <foreach item='id' collection="ids"
             open="()" separator="or" close=")">
        #{id}
    </foreach>
(id=1 or id=2 or id=3)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPI6jkyL-1648975231481)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403111312969.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PsALsF7t-1648975231482)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403113547055.png)]

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 先在Mysq|中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可!

13. 缓存 (了解)

13.1 简介

查询: 连接数据库,耗资源!
一次查询的结果,给他暂存在一个可以直接取到的地方! -->内存:缓存
我们再次查询相同数据的时候,直接走缓存,就不用走数据库了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NZyKcgXo-1648975231483)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403143829069.png)]

13.2 Mybatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存: -级缓存和级缓存
    • 默认情况下,只有一 -级缓存开启。 (SqlSession级别的缓存, 也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性, MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

13.3 一级缓存

  • 一级缓存也叫本地缓存:
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

测试步骤:

  1. 开启日志!

  2. 测试在一个Session中查询两次相同记录

  3. 查看日志输出

在这里插入图片描述

缓存失效的情况:

  1. 查询不同的东西

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0VoJEy6-1648975231484)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403145857672.png)]

  1. 查询不同的Mapper.xml

  2. 手动清理缓存!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y5Ye5nU8-1648975231484)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220403150003745.png)]

小结: 一级缓存默认是开启的,只在一次SqISession中有效, 也就是拿到连接到关闭连接这个区间段!
一级缓存就是一 个Map。

13.4 二级缓存

  • 二级缓存也叫全局缓存,一 -级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map) 中;

步骤:

  1. 开启全局缓存

    <!--显示的开启全局缓存-->
    <setting name="cacheEnabled" va1ue="true"/>
    
  2. 在要使用二级缓存的Mapper中开启

    <!--在当前Mapper.xml中使用二级缓存--> 
    <cache/>
    

    也可以自定义参数

    <!--在当前Mapper.xml中使用二级缓存-->
    <cache evi ction="FIFO"
        flush Interva1="60000"
        size="512"
        readonly="true"/>
    
  3. 测试

    1. 出现的问题:我们需要将实体类序列化! 否则就会报错!

      Caused by: java.io.NotSerializableException: com.xz.pojo.User
      

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中;
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓冲中!

13.5 缓存原理图

在这里插入图片描述

缓存顺序

  1. 先看二级缓存中有没有
  2. 再看一级缓存中有没有
  3. 查询数据库

13.6 自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存.

要在程序中使用, 需要先导包!

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

在Mapper.xml中指定我们的ehcache缓存实现

<!--在当前Mapper.xml中使用二级缓存-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统宕机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->

</ehcache>

目前我们大多使用Redis数据库来做缓存! K - V

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员正正

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值