狂神说Java:Mybatis

Mybatis

本文为学习《狂神说Java:Mybatis》的学习笔记。文字部分参考狂神说Java Mybatis笔记,代码部分为自测代码。其中根据测试中出现的问题做了解答。


文章目录


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

1 简介

1.1 什么是Mybatis

在这里插入图片描述

  • Mybaties是一款优秀的持久层框架。

1.2 如何获得Mybaties:

  • 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
  • 中文文档:https://mybatis.org/mybatis-3/zh/index.html

1.2 持久化

  • 数据持久化:持久化就是将程序的数据在持久状态和瞬时状态转化的过程
    • 内存:断电即失
    • 数据库(Jdbc),io文件持久化。
  • 为什么要持久化?
    • 有一些对象,不能让他丢掉
    • 内存太贵

1.3 持久层

  • Dao层,用于完成持久化工作的代码块

1.4 为什么需要MyBatis

  • 帮助程序员将数据存入到数据库中

  • 方便。传统的JDBC代码太复杂了,简化,框架,自动化

  • 优点:

    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql
    • 使用的人多(中国用的多,外国用的不多)

2 第一个Mybatis程序

  • 思路:搭建环境 --> 导入MyBatis --> 编写代码 --> 测试

2.1 搭建环境

  1. 建数据库
CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE `mybatis`.`user`( `id` INT(20), `name` VARCHAR(30), `pwd` VARCHAR(30) ); 
INSERT INTO `mybatis`.`user` (`id`, `name`, `pwd`) VALUES ('1', '狂神', '123456'),('2', '张三', '123456'),('3', '李四', '123456');

  1. 新建项目

    1. 创建一个普通的maven项目。注意需要改一下Maven的配置 ,不要放C盘。
      在这里插入图片描述

    2. 删除src目录 (就可以把此工程当做父工程了,然后创建子工程)

    3. 导入maven依赖

    <dependencies>
        <!-- 导入依赖-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

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

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

2.2 创建一个模块

2.2.1 步骤

2.2.1.1 编写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>
    <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?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

</configuration>
2.2.1.2 编写mybatis工具类
package 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;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory = null;
    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.2.1.3 编写实体类

在这里插入图片描述

package pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public User() {
    }

    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;
    }
}

2.2.1.4 编写Dao接口

在这里插入图片描述

package dao;

import pojo.User;

import java.util.List;

public interface UserDao {
    public List<User> getUserList();
}
2.2.1.5 编写实现类(由原来的UserDaoImpl转变为一个Mapper配置文件)

在这里插入图片描述

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="dao.UserDao">
    <!--虽然这个sql的结果是List<User>,但是resultType的值要写泛型里头的类型,比如这里的User,而且要写全名-->
    <select id="getUserList" resultType="pojo.User">
        select * from mybatis.user
  </select>
</mapper>
2.2.1.6 编写测试类

在这里插入图片描述

package dao;

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

import java.util.List;

public class UserDaoTest {
    @Test
    public void test(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            // 方式一:getMapper
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.getUserList();

            //方式二:这种不推荐
            //List<User> userList = sqlSession.selectList("dao.UserDao.getUserList");
            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
}

2.2.2 可能遇到的问题

  • 配置文件没有注册:
    • 错误提示:org.apache.ibatis.binding.BindingException: Type interface dao.UserDao is not known to the MapperRegistry.
    • 修改方案:在核心配置文件里加上相应的映射
      在这里插入图片描述
    <mappers>
        <mapper resource="dao/UserMappr.xml"/>
    </mappers>
  • Maven导出资源问题:
    • 错误提示:java.lang.ExceptionInInitializerError;Caused by: java.io.IOException: Could not find resource dao/UserMappr.xml
    • 解决方法:在父工程和子工程(在子工程加是为哦额防止父工程加的生效,双重保险)的pom里,加上下面代码:
      在这里插入图片描述
      在这里插入图片描述
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
  • 1 字节的 UTF-8 序列的字节 1 无效:
    • 错误提示:java.lang.ExceptionInInitializerError;### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: 1 字节的 UTF-8 序列的字节 1 无效。
    • 原因:是在UserMapper.xml中添加中文注释了。
    • 解决办法也是有两种:
      • 1 直接把中文注释去掉,运行就可以了。
      • 2 不想去掉中文注释的话,把第一行中的encoding="UTF-8"改成encoding=“UTF8”。就是把 - 去了。
  • 忘记在mybatis-config.xml核心配置文件中添加UserMapper.xml映射。
  • resulType后类型不写全,只有在命名别名后才可以不写全。
  • 最好把**Mapper.xml文件放到resource目录下,不然后时候程序会找不到。

3 CRUD

3.1 namespace

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

3.2 select

  • id:对应的namespace中的方法名;
  • resultType : Sql语句执行的返回值;
  • parameterType : 参数类型;
  • UserDao接口:
    public User getUserById(int id);
  • UserMapper.xml:
    <select id="getUserById" resultType="pojo.User">
        select * from user where id = #{id};
    </select>
  • 测试类:
    @Test
    public void getUserByIdTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getUserById(4);
            System.out.println(user);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

3.3 insert

  • UserDao接口:
    public int addUser(User user);
  • UserMapper.xml:
    <insert id="addUser" parameterType="pojo.User">
        insert into user(id,name,pwd) values (#{id},#{name},#{pwd});
    </insert>
  • 测试类:
    @Test
    public void addUserTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            userDao.addUser(new User(4,"toutou","123456"));
            sqlSession.commit();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

3.4 update

  • UserDao接口:
    public int updateUser(User user);
  • UserMapper.xml:
    <update id="updateUser" parameterType="pojo.User">
        update user set name=#{name},pwd=#{pwd} where id=#{id};
    </update>
  • 测试类:
    @Test
    public void updateUserTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            int num = userDao.updateUser(new User(1, "dog", "999999"));
            if(num>0){
                sqlSession.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

3.5 delete

  • UserDao接口:
    public int deleteUser(int id);
  • UserMapper.xml:
    <delete id="deleteUser" >
        delete from user where id=#{id};
    </delete>
  • 测试类:
    @Test
    public void deleteUserTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            int num = userDao.deleteUser(2);
            if(num>0){
                sqlSession.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

3.6 万能Map

  • UserDao接口:
    public int updateUserByMap(Map map);

  • UserMapper.xml:
    <update id="updateUserByMap" parameterType="map">
        update user set name=#{name} where id=#{id};
    </update>
  • 测试类:
    @Test
    public void updateUserMapTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            Map map=  new HashMap<String,Object>();
            map.put("id",1);
            map.put("name","mutou");
            int num = userDao.updateUserByMap(map);
            if(num>0){
                sqlSession.commit();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
  • Map传递参数,直接在sql中取出map里的key即可!
  • 对象传递参数,直接在sql中取出对象的属性即可!
  • 只有一个基本类型参数的情况下,可以直接在sql中取到
  • 多个参数用Map(一个表参数太多,更新时就用到一两个字段,这时候用map比较方便) , 或者注解!

3.7 模糊查询

  • UserDao接口:
    public List<User> selectUserByLike(String value);
  • UserMapper.xml:
    方法一:
    <select id="selectUserByLike" parameterType="String" resultType="pojo.User">
        select * from user where name like #{name};
    </select>

方法二:

    <select id="selectUserByLike" parameterType="String" resultType="pojo.User">
        select * from user where name like "%"#{name}"%";
    </select>
  • 测试类:
    方法一:
    @Test
    public void selectUserByLiketest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            // 方式一:getMapper
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.selectUserByLike("%tou%");
            for (User user : userList) {
                System.out.println(user);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

方法二:

    @Test
    public void selectUserByLiketest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            // 方式一:getMapper
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.selectUserByLike("tou");
            for (User user : userList) {
                System.out.println(user);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

4 配置解析

4.1 核心配置文件

  • mybatis-config.xml(习惯用这个名字,当然也可以不叫这个名字)

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

configuration(配置)
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    	environment(环境变量)
    		transactionManager(事务管理器)
    		dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)

4.2 环境配置 environments

  • MyBatis 可以配置成适应多种环境

  • 不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

  • 学会使用配置多套运行环境!用哪一套环境就把那套设成default。

MyBatis默认的事务管理器就是JDBC ,连接池:POOLED

4.3 属性 properties

  • 我们可以通过properties属性来实现引用配置文件

  • 这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.poperties】

4.3.1 编写一个配置文件:db.properties

在这里插入图片描述

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=root

4.3.2 在核心配置文件中引入

    <properties resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

全部效果如下:

<?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 resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">

                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>

            </dataSource>
        </environment>
    </environments>


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

</configuration>

4.3.3 总结

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

4.4 类型别名 typeAliases

  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置.
  • 意在降低冗余的全限定类名书写。
  • 在核心配置文件添加的代码如下,注意添加的位置:
<typeAliases>
    <typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>

全部效果如下:

<?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 resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

    <typeAliases>
        <typeAlias type="pojo.User" alias="User"/>
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">

                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>

            </dataSource>
        </environment>
    </environments>


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

</configuration>

这时候xml里类名就可以简写了
在这里插入图片描述

  • 也可以指定一个包,每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:
    <typeAliases>
        <package name="pojo"/>
    </typeAliases>
  • 在实体类比较少的时候,使用第一种方式。
  • 如果实体类十分多,建议用第二种扫描包的方式。
  • 第一种可以DIY别名,第二种不行,如果非要改,需要在实体上增加注解。@Alias("author")这种写法实测时报空指针,原因未明。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

4.5 设置 Settings

  • 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
    在这里插入图片描述

4.6 其他配置

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins 插件
    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

4.7 映射器 mappers

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

  • 方式一:【推荐使用】

    <mappers>
        <mapper resource="dao/UserMapper.xml"/>
    </mappers>
  • 方式二:使用class文件绑定注册
    <mappers>
        <!--<mapper resource="dao/UserMapper.xml"/>-->
        <mapper class="dao.UserMapper"/>
    </mappers>
  • 注意点:
    • 接口和他的Mapper配置文件必须同名
    • 接口和他的Mapper配置文件必须在同一个包下
    • 使用class时分割符是“.”,使用resource时分隔符是“/”。如果使用class时分隔符写成了"/"会报空指针异常。
  • 方式三:使用包扫描进行注入
    <mappers>
        <!--<mapper resource="dao/UserMapper.xml"/>-->
        <!--<mapper class="dao.UserMapper"/>-->
        <package name="dao"/>
    </mappers>

4.8 作用域和生命周期

在这里插入图片描述

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

  • SqlSessionFactoryBuilder:

    • 一旦创建了SqlSessionFactory,就不再需要它了
      局部变量
  • SqlSessionFactory:

    • 说白了就可以想象为:数据库连接池
    • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建一个实例。
    • 因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)。
    • 最简单的就是使用单例模式或静态单例模式。
  • SqlSession:

    • 连接到连接池的一个请求
    • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
    • 用完之后需要赶紧关闭,否则资源被占用!
      在这里插入图片描述

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

5.1 问题

  • 当数据库里的列名和实体类的属性不同名时,会出现以下问题:
    在这里插入图片描述

5.2 解决方法

5.2.1 sql起别名

在这里插入图片描述

5.2.2 使用resultMap结果集映射

  • 说明
    • column数据库中的字段,property实体类中的属性
    • type是整体映射而成的类型。
      • 原来select标签里的parameterType=“User”,现在改成了resultMap=“UserMap”。而resultMap=“UserMap” 和 id=“UserMap” type=“User” 合并,相当于中间多了个"UserMap"中转,结果还是"User",所以resultMap的type还是"User"。
    • 映射只需要写需要映射的字段。像表里列名和实体属性名都是id的,就可写可不写。
    <!--
        1.column数据库中的字段,property实体类中的属性
        2.type是整体映射而成的类型。
            原来select标签里的parameterType="User",现在改成了resultMap="UserMap"
            而resultMap="UserMap"<resultMap id="UserMap" type="User"> 合并,相当于中间多了个"UserMap"中转,
            结果还是"User",所以resultMap的type还是"User"3.映射只需要写需要映射的字段。像表里列名和实体属性名都是id的,就可写可不写。
    -->
    <resultMap id="UserMap" type="User">
        <result column="pwd" property="password"></result>
    </resultMap>

    <select id="getUserById" resultMap="UserMap">
        select * from user where id = #{id};
    </select>

6 日志

6.1 日志工厂

  • 如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的助手!

  • 曾经我们使用:sout、debug。现在我们使用:日志工厂
    在这里插入图片描述

  • 日志实现有下列几种,在MyBatis中具体使用哪一个日志实现,在设置中设定即可。mybatis没有默认的日志实现。

    • SLF4J
    • LOG4J 【需要掌握】
    • LOG4J2
    • JDK_LOGGING
    • COMMONS_LOGGING
    • STDOUT_LOGGING 【需要掌握】
    • NO_LOGGING

6.2 STDOUT_LOGGING

  • 使用方法:在mybatis-config.xml里加上下面一段配置即可。注意要加在properties和typeAliases之间。
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

6.3 Log4j

6.3.1 什么是Log4j

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件;

  • 我们也可以控制每一条日志的输出格式;

  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;

  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

6.3.2 怎么使用Log4j

  • 1.先导入log4j的包
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  • 2.编写log4j.properties配置文件
    在这里插入图片描述
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
​
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/mybatistest.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sq1.PreparedStatement=DEBUG

  • 3.配置settings为log4j实现
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
  • 4.测试运行
    在这里插入图片描述

6.3.3 Log4j简单使用

  • 在要使用Log4j的类中,导入包 import org.apache.log4j.Logger;
  • 日志对象,参数为当前类的class对象
  • 日志级别
    • info
    • debug
    • error
package dao;

import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.Test;
import pojo.User;
import utils.MybatisUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserDaoTest {
    static Logger logger = Logger.getLogger(UserDaoTest.class);

    @Test
    public void getUserByIdTest(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();
            //2.执行SQL
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            User user = userDao.getUserById(4);
            System.out.println(user);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
        logger.info("info级别日志");
        logger.debug("debug级别日志");
        logger.error("error级别日志");
    }


}

  • 日志文件如下
    在这里插入图片描述

7 分页

7.1 思考:为什么分页?

  • 减少数据的处理量,或者说在数据量大的时候,分批处理数据。

7.2 使用Limit分页

  • 使用MyBatis实现分页,核心是SQL
  • 1.接口
    public List<User> getUserListByLimit(Map map);

  • 2.Mapper.xml
    <select id="getUserListByLimit" parameterType="map" resultMap="UserMap">
        select * from user limit #{startIndex},#{pageSize}
    </select>

  • 3.测试
    @Test
    public void testLimit(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();

            //2.执行SQL
            // 方式一:getMapper
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            map.put("startIndex",0);
            map.put("pageSize",2);

            List<User> userList = userDao.getUserListByLimit(map);

            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

在这里插入图片描述

7.3 RowBounds分页(不推荐)

  • 核心:不再使用SQL实现分页

  • 1.接口

    public List<User> getUserByRowBounds();
  • 2.mapper.xml
    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from user
    </select>
  • 3.测试
    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //RowBounds实现
        RowBounds rowBounds = new RowBounds(0, 2);
        //通过Java代码层面实现分页
        List<User> userList = sqlSession.selectList("dao.UserMapper.getUserByRowBounds",null,rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.4 分页插件

在这里插入图片描述

8 使用注解开发

8.1 面向接口开发

  • 三个面向区别
    • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性和方法;
    • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现;
    • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构;

8.2 使用注解开发

  • 注解在接口上实现
    @Select("select id,name,pwd as password from user")
    public List<User> getUserList();
  • 需要在核心配置文件中绑定接口
    <mappers>
        <mapper class="dao.UserMapper"/>
    </mappers>
  • 测试
    @Test
    public void test(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();

            //2.执行SQL
            // 方式一:getMapper
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userDao.getUserList();

            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

8.3 本质

  • 本质:反射机制实现
  • 底层:动态代理
    在这里插入图片描述
  • MyBatis详细执行流程
    在这里插入图片描述

8.4 注解CURD

  • 可以设置成自动提交(代码如下),也可以不设置自动提交,手工提交事务。
    在这里插入图片描述
  • 注解在接口上实现
package dao;

import org.apache.ibatis.annotations.*;
import pojo.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    @Select("select id,name,pwd as password from user")
    public List<User> getUserList();

    @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{password})")
    public int addUser(User user);

    @Delete("delete from user where id = #{id}")
    public int deleteUser(@Param("id") int id);

    @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
    public int updateUser(User user);

    @Select("select id,name,pwd as password from user where id = #{id}")
    public User selectUser(@Param("id") int id);

}

  • 需要在核心配置文件中绑定接口
    <mappers>
        <mapper class="dao.UserMapper"/>
    </mappers>
  • 测试
package dao;

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

import java.util.HashMap;
import java.util.List;

public class UserDaoTest {

    @Test
    public void test(){
        SqlSession sqlSession = null;
        try {
            //1.获取SqlSession对象
            sqlSession = MybatisUtils.getSqlSession();

            //2.执行SQL
            // 方式一:getMapper
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userDao.getUserList();

            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

    //insert
    @Test
    public void addUsertest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            userDao.addUser(new User(9,"妞妞","123123"));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

    //delete
    @Test
    public void deleteUsertest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            userDao.deleteUser(6);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

    //update
    @Test
    public void updateUsertest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            userDao.updateUser(new User(3,"huahua","121121"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

    //select
    @Test
    public void selectUsertest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            System.out.println(userDao.selectUser(1));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
}

  1. 关于@Param( )注解
    • 基本类型的参数或者String类型,需要加上
    • 引用类型不需要加
    • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
    • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
  2. #{} 和 ${}
    • #{}可以防止SQL注入
    • ${}不能防止SQL注入

9 Lombok

9.1 说明

  1. Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok- 提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。

9.1 使用步骤:

  1. 在IDEA中安装Lombok插件
  2. 在项目中导入lombok的jar包
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
  • 可用注解
@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
  • 示例
package pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

@Data
@ToString
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

10 多对一处理

10.1 测试环境搭建

  • 导入lombok
  • 新建实体类Teacher,Student
package pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;
}

package dao;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import utils.MybatisUtils;

public class StudentTest {
    @Test
    public void selectStudentTeacherTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            System.out.println(studentMapper.selectStudentTeacher());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
}

  • 建立Mapper接口
package dao;

import pojo.Student;

import java.util.List;

public interface StudentMapper {
}

package dao;

import pojo.Student;
import pojo.Teacher;

import java.util.List;

public interface TeacherMapper {
}

  • 建立Mapper.xml文件
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.StudentMapper">

</mapper>


<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.TeacherMapper">
</mapper>
  • 在核心配置文件中绑定注册我们的Mapper接口或者文件 【方式很多,随心选】
    <mappers>
        <mapper class="dao.StudentMapper"/>
        <mapper class="dao.TeacherMapper"/>
    </mappers>
  • 测试查询是否能够成功

10.2 按照查询嵌套处理

  • 接口
package dao;

import pojo.Student;

import java.util.List;

public interface StudentMapper {
    public List<Student> selectStudentTeacher();
}

package dao;

import pojo.Student;
import pojo.Teacher;

import java.util.List;

public interface TeacherMapper {

    public Teacher selectTeacher(int id);
}

  • Mapper.xml文件
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.StudentMapper">

    <resultMap id="StudentTeacher" type="Student">
        <association property="teacher" javaType="Teacher" column="tid" select="selectTeacher"></association>
    </resultMap>

    <select id="selectStudentTeacher" resultMap="StudentTeacher">
        select * from student;
    </select>

    <select id="selectTeacher" resultType="teacher">
        select * from teacher where id = #{id}
    </select>
</mapper>


<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.TeacherMapper">


</mapper>


  • 测试类
    @Test
    public void selectStudentTeacherTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            System.out.println(studentMapper.selectStudentTeacher());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

10.3 按照结果嵌套处理

  • 接口
    public List<Student> selectStudentTeacher1();
  • Mapper.xml文件
    <select id="selectStudentTeacher1" resultMap="StudentTeacher1">
        select s.id as id,s.name as name ,s.tid as tid,t.name as tname from student s,teacher t where s.tid=t.id
    </select>

    <resultMap id="StudentTeacher1" type="Student">
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
        <association property="teacher" javaType="Teacher">
            <result column="tid" property="id"></result>
            <result column="tname" property="name"></result>
        </association>
    </resultMap>
  • 测试类
    @Test
    public void selectStudentTeacher1Test(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            System.out.println(studentMapper.selectStudentTeacher1());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

11 一对多处理

11.1 测试环境搭建

  • 导入lombok
  • 新建实体类Teacher,Student
package pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
}

package pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;
    private List students;
}

  • 建立Mapper接口
  • 建立Mapper.xml文件
  • 在核心配置文件中绑定注册我们的Mapper接口或者文件 【方式很多,随心选】

11.2 按照查询嵌套处理

  • 接口
    public Teacher selectTeacherStudent(int id);
  • Mapper.xml文件
    <select id="selectTeacherStudent" resultMap="TeacherStudent">
        select * from teacher where id=#{id}
    </select>

    <resultMap id="TeacherStudent" type="teacher">
        <!--这里的colum必须加,不加报空指针错误,其值为下面selectStudent查询的条件-->
        <collection property="students" javaType="List" ofType="Student" column="id" select="selectStudent"></collection>
    </resultMap>

    <select id="selectStudent" resultType="Student">
        select * from student where tid = #{tid}
    </select>
  • 测试类
    @Test
    public void selectTeacherStudentTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
            System.out.println(teacherMapper.selectTeacherStudent(2));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

注意

  • 按照查询嵌套处理时,Mapper.xml文件里用到两个select,一个是测试类里调用的,这个select的必须在接口里定义,否则会报错。另一个为了关联查询而生的select则可以不在接口里定义。
    • 必须定义的select(测试类里用到的select):
      在这里插入图片描述
    • 为关联查询而生的select,无需再接口里定义:
      在这里插入图片描述
  • 按照查询嵌套处理时,resultMap里的<collection property="students" javaType="List" ofType="Student" column="id" select="selectStudent"></collection>
    里必须加column,不加会报错,实测报空指针错,很难排查。这里的colum取值是该表用来做关联查询的字段。

11.3 按照结果嵌套处理

  • 接口
    public Teacher selectTeacherStudent1(int id);
  • Mapper.xml文件
    <select id="selectTeacherStudent1" resultMap="TeacherStudent1">
        select t.id as id,t.name as name,s.id as sid,s.name as sname from teacher t,student s where s.tid=t.id and t.id=#{id}
    </select>

    <resultMap id="TeacherStudent1" type="Teacher">
        <!--这行代码不能少,否则会报错:org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
-->
        <result column="id" property="id"></result>
        <!--这行代码不能少,否则name会为null-->
        <result column="name" property="name"></result>
        <collection property="students" ofType="Student">
            <result property="id" column="sid"></result>
            <result property="name" column="sname"></result>
        </collection>
    </resultMap>
  • 测试类
    @Test
    public void selectTeacherStudent1Test(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
            System.out.println(teacherMapper.selectTeacherStudent1(2));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

注意:

  • 按照结果嵌套处理时,Mapper.xml文件里这两行同名映射不能少。

在这里插入图片描述

  • 如果少了<result column="id" property="id"></result>,会报:org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2错误。
  • 如果少了<result column="name" property="name"></result>,查出来的name为null。

11.4 总结

11.4.1 小结

  • 关联 - association 【对象】
  • 集合 - collection 【集合】
  • javaType & ofType
    • JavaType用来指定实体类中的类型
    • ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

11.4.2 注意点

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

11.4.3 面试高频

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

12 动态SQL

12.1 概念

  • 什么是动态SQL:
    • 动态SQL就是根据不同的条件生成不同的SQL语句
    • 所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
  • 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

12.2 搭建环境

12.2.1 建表

CREATE TABLE `blog`  (
  `id` VARCHAR(10) NOT NULL COMMENT '博客id',
  `title` VARCHAR(30) NOT NULL COMMENT '博客标题',
  `author` VARCHAR(30) NOT NULL COMMENT '博客作者',
  `create_time` DATETIME(0) NOT NULL COMMENT '创建时间',
  `views` INT(30) NOT NULL COMMENT '浏览量',
  PRIMARY KEY (`id`)
)

12.2.2 创建一个基础工程

  • 1.导包
  • 2.编写配置文件
  • 3.编写实体类
package pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;// 属性名和字段名不一致
    private int views;
}

  • 4.编写实体类对应Mapper接口和Mapper.xml文件
package dao;
import pojo.Blog;
import java.util.List;
public interface BlogMapper {
    public List<Blog> selectBlog();
    public int addBlog(Blog bog);
}
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.BlogMapper">
    <select id="selectBlog" resultType="blog">
        select * from blog
    </select>

    <insert id="addBlog" parameterType="blog">
        insert into blog (id,title,author,create_time,views) values (#{id},#{title},#{author},#{createTime},#{views})
    </insert>

</mapper>
  • 5.编写测试类
package dao;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.Blog;
import utils.IDUtils;
import utils.MybatisUtils;

import java.util.Date;

public class BlogTest {
    @Test
    public void selectBlogTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            for (Blog blog : blogMapper.selectBlog()) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

    @Test
    public void addData(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            blogMapper.addBlog(new Blog(IDUtils.getId(),"mysql","cat",new Date(),12));
            blogMapper.addBlog(new Blog(IDUtils.getId(),"mycat","cat",new Date(),12));
            blogMapper.addBlog(new Blog(IDUtils.getId(),"spring","dog",new Date(),13));
            blogMapper.addBlog(new Blog(IDUtils.getId(),"boot","dog",new Date(),15));
            blogMapper.addBlog(new Blog(IDUtils.getId(),"clood","dog",new Date(),16));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }

    }
}

12.3 IF

  • 接口
    public List<Blog> selectBlogIf(Map map);
  • Mapper.xml
    <select id="selectBlogIf" resultType="blog" parameterType="map">
        select * from blog
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>
  • 测试类
    @Test
    public void selectBlogIfTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("author","dog");
            for (Blog blog : blogMapper.selectBlogIf(map)) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

12.4 choose (when, otherwise)

  • 接口
    public List<Blog> selectBlogChoose(Map map);

  • Mapper.xml
    <select id="selectBlogChoose" resultType="blog" parameterType="map">
        select * from blog
        <where>
            <choose>
                <when test="id !=null">
                    and id = #{id}
                </when>
                <when test="author !=null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views > #{views}
                </otherwise>
            </choose>
        </where>
    </select>
  • 测试类
    @Test
    public void selectBlogChooseTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            Map<String, Object> map = new HashMap<String, Object>();
            //map.put("id","092d203247884b71b22f499093f2f85c");
            //map.put("author","dog");
            map.put("views",13);
            for (Blog blog : blogMapper.selectBlogChoose(map)) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

12.5 where、set

  • 接口
    public int updateBlog(Map map);
  • Mapper.xml
    <update id="updateBlog" parameterType="blog">
        update blog
        <set>
            <if test="author != null">
                author = #{author},
            </if>
            <if test="views != null">
                views = #{views},
            </if>
        </set>
        <where>
            id = #{id}
        </where>
    </update>

  • 测试类
    @Test
    public void updateBlogTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("id","092d203247884b71b22f499093f2f85c");
            //map.put("author","star");
            map.put("views",15);
            blogMapper.updateBlog(map);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

12.6 sql片段

  • Mapper.xml
    <update id="updateBlog" parameterType="blog">
        update blog
        <set>
            <include refid="con"></include>
        </set>
        <where>
            id = #{id}
        </where>
    </update>

    <sql id="con">
        <if test="author != null">
            author = #{author},
        </if>
        <if test="views != null">
            views = #{views},
        </if>
    </sql>

12.7 小结

12.7.1 注意事项:

  • 最好基于单标来定义SQL片段
  • 不要存在where标签
  • 动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

12.7.2 建议:

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

13 缓存

13.1 简介

  • 查询 : 连接数据库,耗资源

  • ​ 一次查询的结果,给他暂存一个可以直接取到的地方 --> 内存:缓存

  • 我们再次查询的相同数据的时候,直接走缓存,不走数据库了

  • 什么是缓存[Cache]

    • 存在内存中的临时数据
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题
  • 为什么使用缓存?

    • 减少和数据库的交互次数,减少系统开销,提高系统效率
  • 什么样的数据可以使用缓存?

    • 经常查询并且不经常改变的数据 【可以使用缓存】

13.2 MyBatis缓存

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

13.3 一级缓存

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

13.3.1 测试

  • 开启日志
  • 测试在一个Session中查询两次记录
    @Test
    public void selectTest(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            for (Blog blog : blogMapper.selectBlog()) {
                System.out.println(blog);
            }
            System.out.println("****************************************");
            for (Blog blog : blogMapper.selectBlog()) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }
  • 查看日志输出
    在这里插入图片描述

13.3.2 缓存失效的情况

  • 查询不同的东西
  • 增删改操作,可能会改变原来的数据,所以必定会刷新缓存
  • 查询不同的Mapper.xml
  • 手动清理缓存
在这里插入代码片

13.4 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取内容
    • 不同的mapper查询出的数据会放在自己对应的缓存(map)中
  • 一级缓存开启(SqlSession级别的缓存,也称为本地缓存)

  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。

  • 为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。

13.4.1 测试

  • 开启全局缓存:mybatis-config.xml文件
        <setting name="cacheEnabled" value="true"/>
  • 在Mapper.xml中使用缓存
    <cache
            eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
  • 测试
    @Test
    public void select2Test(){
        SqlSession sqlSession = null;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            for (Blog blog : blogMapper.selectBlog()) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
        System.out.println("***************************");
        try {
            sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
            for (Blog blog : blogMapper.selectBlog()) {
                System.out.println(blog);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭sqlSession
            sqlSession.close();
        }
    }

在这里插入图片描述

13.4.2 小结:

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

13.5 缓存原理

在这里插入图片描述

  • 注意:
    • 只有查询才有缓存,根据数据是否需要缓存(修改是否频繁选择是否开启)useCache=“true”。只能关闭二级缓存,不能关闭一级缓存。
      在这里插入图片描述

13.6 自定义缓存-ehcache

  • Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存
  • 1.导包
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
  • 2.在mapper.xml文件中指定使用我们的ehcache缓存实现
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值