• Java之MyBatis


    Java之MyBatis

    ORM介绍

    在这里插入图片描述

    • 对象:Java实体对象
    • 关系:关系型数据库
    • 映射:二者之间的对应关系
    Java概念数据库概念
    属性字段
    对象记录/行

    背景

    原始JDBC操作问题分析

    1、频繁创建和销毁数据库的连接会造成系统的资源浪费从而影响系统性能;

    2、sql硬编码,如需修改,则需改动java代码,不易维护;

    3、查询操作,结果集与实体需要手动映射,较为繁琐;

    4、增删改操作涉及到的参数需要,手动设置并处理占位符问题。

    原始JDBC问题解决方案

    1、使用数据库连接池初始化连接资源;

    2、SQL语句抽取到配置文件中;

    3、通过反射、内省等底层技术,将实体与字段自动映射。

    MyBatis框架

    介绍

    • MyBatis是一个优秀的基于Java的持久层框架,它内部封装了JDBC,使开发者只需要关注SQL语句本身,而不需要花费精力去处理加载驱动、创建连接、创建执行者对象等复杂繁琐的操作;
    • MyBatis通过xml或注解的方式将要执行的的各种Statement配置起来,通过Java对象和Statement中的SQL动态参数进行映射生成最终要执行的SQL语句;
    • 最后MyBatis框架执行完SQL并将结果映射为Java对象并进行返回,通过ORM思想解决实体与数据库字段映射问题,对JDBC封装,屏蔽了JDBC原生的API底层访问细节,避免直接和底层的JDBC API打交道;

    快速入门

    项目结构

    在这里插入图片描述

    pom.xml
    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
    
        <groupId>com.testgroupId>
        <artifactId>MyBatisDemoartifactId>
        <version>1.0-SNAPSHOTversion>
    
        <dependencies>
            
            <dependency>
                <groupId>org.mybatisgroupId>
                <artifactId>mybatisartifactId>
                <version>3.5.7version>
            dependency>
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>5.1.47version>
            dependency>
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>1.18.22version>
            dependency>
            
            <dependency>
                <groupId>log4jgroupId>
                <artifactId>log4jartifactId>
                <version>1.2.17version>
            dependency>
        dependencies>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    mybatis-config.xml(核心配置文件)
    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
        <properties resource="jdbc.properties"/>
        
        <environments default="development">
            
            <environment id="development">
                
                <transactionManager type="JDBC"/>
                
                <dataSource type="POOLED">
                    
                    <property name="driver" value="${jdbc.driverClass}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                dataSource>
            environment>
        environments>
        
        <mappers>
            
            
            
            <mapper resource="mappers/UserMapper.xml"/>
        mappers>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    jdbc.properties(数据库连接配置)
    jdbc.driverClass=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=root
    
    • 1
    • 2
    • 3
    • 4
    实体类
    package com.test.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import java.io.Serializable;
    
    /**
     * 映射数据库中的t_user表
     *
     * @author zhangzengxiu
     * @date 2022/9/3
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class User implements Serializable {
        private static final long serialVersionUID = -2427372682522927866L;
    
        /**
         * 主键id
         */
        private Integer id;
    
        /**
         * 用户名
         */
        private String usetname;
    
        /**
         * 密码
         */
        private String password;
    
        /**
         * 年龄
         */
        private Integer age;
    
        /**
         * 性别
         */
        private String sex;
    
        /**
         * 邮箱
         */
        private String email;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    数据库表
    CREATE TABLE `t_user` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `username` varchar(20) DEFAULT NULL COMMENT '用户名',
      `password` varchar(30) DEFAULT NULL COMMENT '密码',
      `age` int(11) DEFAULT NULL COMMENT '年龄',
      `sex` varchar(2) DEFAULT NULL COMMENT '性别',
      `email` varchar(30) DEFAULT NULL COMMENT '邮箱',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    mapper接口
    package com.test.mapper;
    
    import com.test.pojo.User;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    /**
     * @author zhangzengxiu
     * @date 2022/9/3
     */
    public interface UserMapper {
    
        /**
         * 新增user
         *
         * @param user
         * @return
         */
        int insertUser(User user);
    
        /**
         * 根据id删除user
         *
         * @param id
         * @return
         */
        int delUserById(@Param("id") Integer id);
    
        /**
         * 更新user
         *
         * @param user
         * @return
         */
        int updateUser(User user);
    
        /**
         * 查询user
         *
         * @param id
         * @return
         */
        User queryUser(@Param("id") Integer id);
    
        /**
         * 查询user列表
         *
         * @return
         */
        List<User> queryUserList();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    mapper.xml(映射配置文件)
    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.test.mapper.UserMapper">
    
        
        <insert id="insertUser" parameterType="com.test.pojo.User">
          INSERT INTO t_user
             (
             `username`,
             password,
             age,
             sex,
             email
            )
          VALUES
            (
            #{username},
            #{password},
            #{age},
            #{sex},
            #{email}
            )
        insert>
    
        
        <delete id="delUserById">
          DELETE FROM t_user
          WHERE id=#{id}
        delete>
    
        
        <update id="updateUser">
          UPDATE t_user
          SET username=#{username},
          password=#{password},
          age= #{age},
          sex=#{sex},
          email=#{email}
          WHERE id=#{id}
        update>
    
        
        <select id="queryUser" resultType="com.test.pojo.User">
          SELECT
            id,
            username,
            password,
            age,
            sex,
            email
          FROM
            t_user
          WHERE
            id=#{id}
        select>
    
        
        <select id="queryUserList" resultType="com.test.pojo.User">
        SELECT
            id,
            username,
            password,
            age,
            sex,
            email
        FROM t_user
      select>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    mapper接口全类名—>mapper映射配置文件.xml—>SQL语句—>ORM映射

    1、映射文件的namespace与mapper接口全类名保持一致

    2、映射文件中的SQL语句的id与mapper接口方法名保持一致

    3、查询功能标签必须设置resultType或resultMap

    3.1resultType:设置默认的映射关系,java属性值与数据库字段列名完全匹配

    3.2resultMap:设置自定义的映射关系,java属性与数据库字段列名不匹配情况或联合查询

    单测
    工具类
    package com.test.util;
    
    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.InputStream;
    
    /**
     * Sqlsession工具类
     *
     * @author zhangzengxiu
     * @date 2022/9/3
     */
    public class SqlSessionUtil {
    
        /**
         * 获取Sqlsession
         *
         * @return
         */
        public static SqlSession getSqlSession() throws Exception {
            //加载核心配置文件
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //获取SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            //获取SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            //获取SqlSession 设置为自动提交
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            return sqlSession;
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    测试代码
    package com.test.mapper;
    
    import com.test.pojo.User;
    import com.test.util.SqlSessionUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Assert;
    import org.junit.Test;
    
    import java.util.List;
    
    /**
     * @author zhangzengxiu
     * @date 2022/9/3
     */
    public class UserMapperTest {
    
        /**
         * 测试添加user方法
         *
         * @throws Exception
         */
        @Test
        public void testInsertUser() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            /*
                SqlSession底层通过代理模式
                为mapper接口创建mapper接口的实现类对象并返回
             */
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = new User(null, "zhanghsan", "123454", 23, "男", "1234@qq.com");
            int res = userMapper.insertUser(user);
            Assert.assertEquals(1, res);
        }
    
        /**
         * 测试删除user方法
         *
         * @throws Exception
         */
        @Test
        public void testDelUser() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            int res = userMapper.delUserById(20);
            Assert.assertEquals(1, res);
        }
    
        /**
         * 测试更新user方法
         *
         * @throws Exception
         */
        @Test
        public void testUpdateUser() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = new User();
            user.setId(22);
            user.setUsername("yyccf");
            user.setPassword("222");
            user.setAge(30);
            user.setSex("男");
            user.setEmail("1222@123.com");
            int res = userMapper.updateUser(user);
            Assert.assertEquals(1, res);
        }
    
        /**
         * 测试查询user方法
         *
         * @throws Exception
         */
        @Test
        public void testQueryUser() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = userMapper.queryUser(23);
            System.out.println("user = " + user);
        }
    
        /**
         * 测试查询user列表方法
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserList() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            List<User> users = userMapper.queryUserList();
            for (User user : users) {
                System.out.println(user);
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    注意:

    踩坑:

    由于我们核心配置文件中配置的事务管理是JDBC,

    则我们的事务都需要手动去处理,需要手动提交事务才会生效

    sqlSession.commit();

    或者创建sqlSession对象时,设置为自动提交,即可不用手动提交

    //获取SqlSession 设置为true自动提交
    SqlSession sqlSession = sqlSessionFactory.openSession(true);

    小技巧:

    想查看实际执行的SQL语句:

    通过debug打断点到org.apache.ibatis.executor.SimpleExecutor类

    • 增删改类方法:debug断点到doUpdate()
    • 查询方法:debug断点doQuery

    补充:

    SqlSession:Java程序与数据库之间的会话;由MyBatis为我们提供的操作数据库的会话对象

    SqlSessionFactory:生产sqlSession工厂;

    优化
    事务管理

    设置事务为自动提交,不手动控制事务

    JDBC事务默认自动提交,可以通过手动事务管理
    connection.setAutoCommit(false);
    MyBatis采用JDBC事务管理器,默认所有事物的提交或回滚都需要手动处理

    JDBC事务默认自动提交:

    在这里插入图片描述

    MyBatis采用JDBC事务管理器,sqlSession默认不自动提交:
    在这里插入图片描述

    核心代码
    //事务管理
    //获取SqlSession 默认为false,需要手动控制事务,提交事务等
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //手动提交事务
    sqlSession.commit();
    
    //获取SqlSession 设置为自动提交
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    //提交事务(不需要了)
    //sqlSession.commit();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    MyBatis日志记录
    核心操作

    pom依赖

    
    <dependency>
       	<groupId>log4jgroupId>
    	<artifactId>log4jartifactId>
    	<version>1.2.17version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    日志文件 log4j.xml

    
    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="%-5p %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>
        <root>
            <level value="debug"/>
            <appender-ref ref="STDOUT"/>
        root>
    log4j:configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    控制台打印信息
    在这里插入图片描述

    日志级别

    FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

    从左到右内容越详细

    核心配置文件

    SSM(Spring+SpringMVC+MyBatis)框架该配置文件可以省略

    mybatis-confuig.xml
    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
        
        <properties resource="jdbc.properties"/>
    
        
        <typeAliases>
            
            
            
            
            
            <package name="com.test.pojo"/>
        typeAliases>
    
        
        <environments default="development">
            
            <environment id="development">
                
                <transactionManager type="JDBC"/>
                
                
                <dataSource type="POOLED">
                    
                    <property name="driver" value="${jdbc.driverClass}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                dataSource>
            environment>
        environments>
        
        <mappers>
            
            
            
            <package name="com.test.mapper"/>
            
            
        mappers>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    typeAliases类型别名

    查询返回的实体resultType是全限定类名,较为繁琐,可通过起别名的方式进行优化

    设置别名前:

    
        <select id="queryUser" resultType="com.test.pojo.User">
          SELECT
            id,
            username,
            password,
            age,
            sex,
            email
          FROM
            t_user
          WHERE
            id=#{id}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    设置类名别名:

    注意配置顺序!!!

    
        <typeAliases>
            
            
            
            
            
            <package name="com.test.pojo"/>
        typeAliases>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    设置类型别名后:

    
        <select id="queryUser" resultType="user">
          SELECT
            id,
            username,
            password,
            age,
            sex,
            email
          FROM
            t_user
          WHERE
            id=#{id}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    mappers引入映射文件

    与接口对应的映射配置文件必须引入到核心配置文件中

      
        <mappers>
            
            
            
            <package name="com.test.mapper"/>
            
            
        mappers>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    MyBatis获取参数值

    mapper接口中参数的值在mapper.xml映射配置文件中如何获取

    ${} 与#{}

    ${}本质就是字符串拼接,可能会造成SQL注入,单引号需要手动处理

    #{}本质就是占位符赋值

    MyBatis获取参数值的不同情况:
    情况一:

    Mapper接口方法的参数为单个的字面量类型

    Mapper接口

    	/**
         * 根据username查询User
         *
         * @param username
         * @return
         */
        User getUserByUsername(String username);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    	
        <select id="getUserByUsername" resultType="user">
            
            
            
            
            
            
            
            SELECT * FROM t_user WHERE username = '${aaa}'
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    #{}:#{username}与 #{aaa}均可查询

    占位符赋值与值没关系,只与位置有关

    #{}获取,可以以任意名称来获取。本质就是占位符
    在这里插入图片描述

    : {}: {username}与 ${aaa}均可查询。本质就是字符串拼接

    ${}获取,可以以任意名称来获取,但是如果是字符串类型,需要手动拼接单引号否则报错
    在这里插入图片描述

    报错信息:
    在这里插入图片描述

    总结:

    ${} 与#{}以任意名称的字符串来获取参数值,建议使用参数名,见名知意。但是需要注意 ${} 单引号问题。

    占位符赋值与值没关系,只与位置有关;

    #{}来获取,可以以任意名称来获取;

    ${}来获取,可以以任意名称来获取,但是如果是字符串类型,需要手动拼接单引号否则报错!!!

    情况二:

    Mapper接口方法的参数为多个时

    Mapper接口

    	/**
         * 根据用户名密码查询user
         *
         * @param username
         * @param pssword
         * @return
         */
        User login(String username, String pssword);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    映射配置文件

     
        <select id="login" resultType="user">
            
            
            SELECT * FROM t_user WHERE username='${param1}' AND password ='${param2}'
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
     -- 无法根据参数名获取到值
     SELECT * FROM t_user WHERE username=#{username} AND password =#{password}
    
    • 1
    • 2

    报错信息:
    在这里插入图片描述

    -- 可根据报错提示的默认名称获取到值
     SELECT * FROM t_user WHERE username=#{arg0} AND password =#{arg1}
     SELECT * FROM t_user WHERE username=#{param1} AND password =#{param2}
     -- 组合亦可
     SELECT * FROM t_user WHERE username=#{param1} AND password =#{arg1}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    -- 可根据${} 获取到值,需要注意单引号问题
     SELECT * FROM t_user WHERE username='${param1}' AND password ='${param2}'
    
    • 1
    • 2

    在这里插入图片描述

    总结:

    MyBatis会将这些参数放在一个map集合中,以两种方式进行存储

    1、以arg0、arg1…为键,参数为值;

    2、以param1、param2…为键,参数为值;

    因此只需要通过#{}和${}以键的形式来访问值即可,同样需要 ${}注意单引号问题

    情况三:

    Mapper接口方法的参数为有多个,手动将参数封装为map

    情况二中,是由MyBatis将参数自动封装为Map,我们可自己封装一个map,将map进行传递

    接口

    	 /**
         * 根据用户名密码查询user
         *
         * @param map 参数封装为map
         * @return
         */
        User loginByMap(Map<String, Object> map);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    	
        <select id="loginByMap" resultType="user">
            SELECT * FROM t_user WHERE username=#{username} AND password = #{password}
            
        
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试代码

    	/**
         * 侧说loginByMap方法
         * 手动将参数封装为map
         *
         * @throws Exception
         */
        @Test
        public void testLoginByMap() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            Map<String, Object> map = new HashMap();
            map.put("username", "admin");
            map.put("password", "123456");
            User user = userMapper.loginByMap(map);
            System.out.println(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    只需要通过#{}和 以我们自己设计的键的形式来访问值即可,同样需要 {}以我们自己设计的键的形式来访问值即可,同样需要 以我们自己设计的键的形式来访问值即可,同样需要{}注意单引号问题

    情况四:(常用)

    Mapper接口方法的参数为实体类

    接口访问

    	 /**
         * 新增user
         *
         * @param user
         * @return
         */
        int insertUser(User user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    	
        <insert id="insertUser" parameterType="com.test.pojo.User">
          INSERT INTO t_user
             (
             `username`,
             password,
             age,
             sex,
             email
            )
          VALUES
            (
            #{username},
            #{password},
            #{age},
            #{sex},
            #{email}
            )
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    总结:

    map以键来访问,实体以属性名进行访问

    属性严格意义上来讲是从setter方法上,去掉set之后,将首字母小写后获取到的

    #{}以属性的方式进行访问, ${}需要注意单引号问题

    情况五:(常用)

    @Param命名参数形式

    情况二时,我们使用MyBatis提供的默认的参数进行访问,不灵活

    情况三时,我们可通过自己封装map的形式来,通过键的形式来访问,较为繁琐

    接口

     /**
       * 根据用户名密码查询user
       *
       * @param username
       * @param pssword
       * @return
       */
     User login(@Param("username") String username,@Param(value="pssword") String pssword);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    映射配置文件

    	
        <select id="login" resultType="user">
          SELECT * FROM t_user WHERE username=#{username} AND password =#{password}
        select>
    
    • 1
    • 2
    • 3
    • 4

    总结:

    @Param(“xxx”)是MyBatis以@Param的值为键,以参数为值,将其放到Map中,相当于情况二三的结合,还可以自己灵活的设置键

    MyBatis存储map的时候,有两种方式:

    1、以@Param的值为键,以参数为值

    2、以param1、param2…为键,以参数为值

    情况一:单个字面量的值,也通过@Param来解决

    情况二:多参数,也可通过@Param来解决

    整合下来,总归两种:1、实体类对象;2、@Param

    MyBatis各种查询功能

    查询一个实体对象

    接口

    	/**
         * 根据id查询user
         *
         * @param id
         * @return
         */
        User queryUserById(@Param("id") Integer id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

      
        <select id="queryUserById" resultType="com.test.pojo.User">
            SELECT * FROM t_user WHERE id =#{id}
        select>
    
    • 1
    • 2
    • 3
    • 4

    测试代码

    	/**
         * 测试根据id查询user实体
         * 1、若查询的结果只有一条,可以通过实体类对象或集合接收;
         * 2、若查询的数据有多条,可以通过集合接收。一定不能通过实体类对象接收,此时会报错:TooManyResultsException
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserById() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            Integer id = 22;
            User user = selectMapper.queryUserById(id);
            Assert.assertEquals(user.getId(), id);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    总结:

    1、查询结果只有1条时:

    1.1、可通过实体类对象接收

    1.2、可通过list集合接收

    1.3、也可通过map接收

    ​ {password=123456, sex=男, id=22, age=30, email=1222@ 123.com, username=admin}

    查询一个List集合

    接口

    	/**
         * 查询User列表
         *
         * @return
         */
        List<User> queryUserList();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    映射配置文件

     
        <select id="queryUserList" resultType="com.test.pojo.User">
        SELECT * FROM t_user
        select>
    
    • 1
    • 2
    • 3
    • 4

    测试代码

    	/**
         * 测试查询user列表
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserList() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            List<User> userList = selectMapper.queryUserList();
            for (User user : userList) {
                System.out.println(user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    总结:

    2、查询出的数据有多条:

    2.1、可以通过list集合接收

    2.2、也可通过map接收

    ​ [{password=123456, sex=男, id=22, age=30, email=1222@ 123.com, username=admin}, {password=123454, sex=男, id=23, age=23, email=1234@ qq.com, username=zhanghsan}, {password=123454, sex=男, id=24, age=23, email=1234@ qq.com, username=zhanghsan}]

    2.3在Mapper接口方法上添加@MapKey注解,此时可将每条数据转换为的map集合作为key,以某个字段的值作为键,放在同一个map集合中

    ​ {22={password=123456, sex=男, id=22, age=30, email=1222@ 123.com, username=admin}, 23={password=123454, sex=男, id=23, age=23, email=1234@ qq.com, username=zhanghsan}, 24={password=123454, sex=男, id=24, age=23, email=1234@ qq.com, username=zhanghsan}}

    注意:一定不能通过实体对象接收,会报错:TooManyResultsException

    查询单行单列

    接口

     	/**
         * 查询user的count数
         *
         * @return
         */
        int queryUserCount();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <select id="queryUserCount" resultType="java.lang.Integer">
          SELECT COUNT(*) FROM t_user
        select>
    
    • 1
    • 2
    • 3
    • 4

    测试代码

    	 /**
         * 测试查询user的count数
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserCount() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            int count = selectMapper.queryUserCount();
            System.out.println(cout);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    MyBatis中设置了默认的类型别名:

    举个例子:

    java.lang.Integer-----> Integer , int

    int------> _int , _integer

    Map-----> map

    String-----> string

    查询一个Map集合

    接口

    	/**
         * 根据id查询User为map
         *
         * @param id
         * @return
         */
        Map<String, Object> queryUserByIdToMap(@Param("id") Integer id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <select id="queryUserByIdToMap" resultType="java.util.Map">
           SELECT * FROM t_user WHERE id =#{id}
        select>
    
    • 1
    • 2
    • 3
    • 4

    测试代码

    	/**
         * 测试根据id查询User为Map
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserByIdToMap() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            Integer id = 22;
            Map<String, Object> map = selectMapper.queryUserByIdToMap(id);
            System.out.println(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    返回结果

    {password=123456, sex=, id=22, age=30, email=1222@123.com, username=admin}
    
    • 1

    查询出来的map集合:

    以字段为键,以值为值

    Map响应到浏览器就是一个json

    查询列表为Map

    若获取的数据没有实体类预支对应,可获取为map

    接口

    	/**
         * 查询多个user转为一个Map
         *
         * @return
         */
        List<Map<String, Object>> queryUserListToMap();
    
    	/**
         * 以id作为建,每个map作为值
         *
         * @return
         */
        @MapKey("id")
        Map<String, Object> queryUserListToMap2();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    映射配置文件

     	
        <select id="queryUserListToMap" resultType="java.util.Map">
             SELECT * FROM t_user
        select>
    
    	
        <select id="queryUserListToMap2" resultType="java.util.Map">
           SELECT * FROM t_user
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试代码

    	/**
         * 测试查询多个user转为一个Map
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserListToMap() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            List<Map<String, Object>> maps = selectMapper.queryUserListToMap();
            System.out.println(maps);
        }
    
    	/**
         * 测试查询多个user转为一个Map
         * id为键,字段为值
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserListToMap2() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SelectMapper selectMapper = sqlSession.getMapper(SelectMapper.class);
            Map<String, Object> map = selectMapper.queryUserListToMap2();
            System.out.println(map);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    结果

    List的Map

    [{password=123456, sex=, id=22, age=30, email=1222@123.com, username=admin}, {password=123454, sex=, id=23, age=23, email=1234@qq.com, username=zhanghsan}, {password=123454, sex=, id=24, age=23, email=1234@qq.com, username=zhanghsan}]
    
    • 1

    id为键,map为值

    {22={password=123456, sex=, id=22, age=30, email=1222@123.com, username=admin}, 23={password=123454, sex=, id=23, age=23, email=1234@qq.com, username=zhanghsan}, 24={password=123454, sex=, id=24, age=23, email=1234@qq.com, username=zhanghsan}}
    
    • 1

    特殊SQL执行

    以下几种情况,用#{} 可能会出现一些问题。

    处理模糊查询

    接口:

     	/**
         * 根据username模糊匹配user
         *
         * @param username
         * @return
         */
        List<User> queryUserLikeUsername(@Param("username") String username);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

        /**
         * 测试根据username模糊匹配user
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserLikeUsername() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
            List<User> userList = mapper.queryUserLikeUsername("z");
            for (User user : userList) {
                System.out.println(user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    映射配置文件:

    
        <select id="queryUserLikeUsername" resultType="com.test.pojo.User">
            
            SELECT * FROM t_user WHERE  username LIKE '%#{username}%'
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    报错截图:
    在这里插入图片描述

    注意:

    模糊查询:#{} 需要写在一对单引号中,单引号在SQL语句中,表示一个字符串,

    '%?%'会被解析为字符串的一部分,而不是一个占位符。

    所以当我们给占位符进行赋值的时候,没有占位符就会报错。

    解决方案一:使用${} 而不是#{}

    映射配置文件:

    
        <select id="queryUserLikeUsername" resultType="com.test.pojo.User">
            SELECT * FROM t_user WHERE username LIKE '%${username}%'
        select>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    解决方案二:使用concat函数进行字符串拼接

    映射配置文件:

    
        <select id="queryUserLikeUsername" resultType="com.test.pojo.User">
            SELECT * FROM t_user WHERE username LIKE concat('%',#{username},'%')
        select>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    解决方案三:拼接字符串

    映射配置文件:

    
        <select id="queryUserLikeUsername" resultType="com.test.pojo.User">
           SELECT * FROM t_user WHERE username LIKE "%"#{username}"%"
       select>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    处理批量删除

    接口:

    	/**
         * 根据id批量删除
         *
         * @param ids
         * @return
         */
        int delUsersByIds(@Param("ids") String ids);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

    	/**
         * 测试根据id批量删除
         *
         * @throws Exception
         */
        @Test
        public void testDelUsersByIds() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
            int res = mapper.delUsersByIds("21,22,30");
            System.out.println(res);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    映射配置文件:

    	
        <delete id="delUsersByIds">
            DELETE FROM t_user  WHERE id IN (#{ids})
        delete>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    #{} 会自动加单引号,这样的SQL在执行过程中是不正确的,所以并不会有数据被删除,因为SDL不能被正确执行

    解决方案:

    映射配置文件:

    	
        <delete id="delUsersByIds">
            DELETE FROM t_user  WHERE id IN (${ids})
        delete>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    处理动态设置表名

    接口:

    	 /**
         * 根据动态表名查询
         *
         * @param tableName
         * @return
         */
        List<User> queryUserByTableName(@Param("tableName") String tableName);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

    	 /**
         * 吃根据动态表名的查询功能
         *
         * @throws Exception
         */
        @Test
        public void testQueryUserByTableName() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
            List<User> userList = mapper.queryUserByTableName("t_user");
            for (User user : userList) {
                System.out.println(user);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    映射配置文件

    	
        <select id="queryUserByTableName" resultType="com.test.pojo.User">
            SELECT * FROM #{tableName}
        select>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    解决方案:

    
        <select id="queryUserByTableName" resultType="com.test.pojo.User">
            SELECT * FROM ${tableName}
        select>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    添加功能获取自增的主键

    当我们使用自增主键的时候,当我们需要获取添加到数据库后的自增主键使用。

    接口:

    	/**
         * 添加User
         *
         * @param user
         * @return
         */
        int insertUser(User user);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

    	/**
         * 测试添加User,并返回带自增主键的user
         *
         * @throws Exception
         */
        @Test
        public void testInsertUser() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
            User user = new User(null, "lisi", "121223", 33, "女", "1112@123.com");
            mapper.insertUser(user);
            System.out.println(user);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    映射文件:

    	
        
        <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
          INSERT INTO t_user
             (
             `username`,
             password,
             age,
             sex,
             email
            )
          VALUES
            (
            #{username},
            #{password},
            #{age},
            #{sex},
            #{email}
            )
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    搭建MyBatis框架

    自定义映射resultMap

    如果默认java的属性名与数据库中表的列名一致,则可以实现自动映射

    resultMap是如果java的属性名与实际数据库中表字段的列名不一致的解决方案,以及一对多等场景的处理。

    数据准备
    -- 数据准备
    USE mybatis;
    
    DROP TABLE IF EXISTS t_emp;
    
    -- 创建员工表
    CREATE TABLE IF NOT EXISTS t_emp(
    	eid INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '主键' ,
    	emp_name VARCHAR(20) COMMENT '员工姓名',
    	age INT COMMENT '年龄',
    	sex CHAR(1) COMMENT '性别',
    	email VARCHAR(20) COMMENT '邮箱',
    	did INT COMMENT '部门id'
    );
    
    -- 添加测试数据
    INSERT INTO t_emp VALUES
    (null,'zhangsan',20,'男','1234@12.com',1),
    (null,'lisi',21,'男','1234@12.com',1),
    (null,'wangwu',22,'男','1234@12.com',1),
    (null,'zhaoliu',23,'女','1234@12.com',1),
    (null,'maqi',24,'女','1234@12.com',1);
    
    -- 创建部门表
    DROP TABLE IF EXISTS t_dept;
    
    CREATE TABLE IF NOT EXISTS t_dept(
    	did INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '主键' ,
    	dept_name VARCHAR(20) COMMENT '部门名称'
    );
    
    -- 添加部门测试数据
    INSERT INTO t_dept VALUES
    (null,'A'),
    (null,'B'),
    (null,'C');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    背景

    接口:

    	/**
         * 查询emp列表
         *
         * @return
         */
        List<Emp> queryEmpList();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    测试代码:

    	/**
         * 测试查询emp列表
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpList() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
            List<Emp> emps = mapper.queryEmpList();
            for (Emp emp : emps) {
                System.out.println(emp);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    映射配置文件

     
        <select id="queryEmpList" resultType="com.test.pojo.Emp">
            SELECT * FROM  t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4

    查询结果
    在这里插入图片描述

    中间有一列值为null,但是查询并没报错。

    解决方案一:为查询出来的字段设置别名:

    映射配置文件:

      
        <select id="queryEmpList" resultType="com.test.pojo.Emp">
            SELECT
              eid,
              emp_name AS empName,
              age,
              sex,
              email
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    解决方案二:全局配置:下划线映射为驼峰

    字段必须满字段的规则,属性必须符合属性规则

    MyBatis核心配置文件

        
        <settings>
            
            <setting name="mapUnderscoreToCamelCase" value="true"/>
        settings>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    映射配置文件

    
        <select id="queryEmpList" resultType="com.test.pojo.Emp">
            SELECT
              *
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    映射配置文件(别名+下划线转驼峰组合)

     <select id="queryEmpList" resultType="com.test.pojo.Emp">
            SELECT
              eid,
              emp_name AS empName,
              age,
              sex,
              email
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可映射到数据

    解决方案三:resuleMap自定义映射

    resultType只能用来解决,字段名和属性名一致的情况。

    用了resultMap建议把所有的映射关系全部设置出来。

    映射配置文件

    <resultMap id="empResultMap" type="com.test.pojo.Emp">
            
            <id property="eid" column="eid"/>
            
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
        resultMap>
    
        
        <select id="queryEmpList" resultMap="empResultMap">
            SELECT
              *
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    resultMap:设置自定义映射关系

    id:resultMap的唯一标识

    type:设置映射关系中的实体类型

    子标签

    id:设置主键的映射关系

    result:设置普通字段的映射关系

    属性:

    property:设置映射关系中的属性名,必须是type属性所设置的实体类型的属性名

    column:设置映射关系中的字段名,必须是SQL语句查询出的字段名

    在这里插入图片描述

    多对一映射

    当表与表之间存在关系时,实体与实体之间也是存在关系的。

    package com.test.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    /**
     * 员工表实体
     *
     * @author zhangzengxiu
     * @date 2022/9/11
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Emp {
    
        /**
         * 主键
         */
        private Integer eid;
    
        /**
         * 员工姓名
         */
        private String empName;
    
        /**
         * 年龄
         */
        private Integer age;
    
        /**
         * 性别
         */
        private String sex;
    
        /**
         * 邮箱
         */
        private String email;
    
        /**
         * 部门
         */
        private Dept dept;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    接口

     	/**
         * 查询员工和部门
         *
         * @param eid
         * @return
         */
        Emp queryEmpAndDeptByEid(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码:

        /**
         * 测试查询emp员工和部门
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpAndDeptByEid() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
            Emp emp = mapper.queryEmpAndDeptByEid(2);
            System.out.println(emp);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    方式一:级联属性赋值

    映射配置文件:

        <resultMap id="empResultMapOne" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
            
            <result property="dept.did" column="did"/>
            <result property="dept.deptName" column="dept_name"/>
        resultMap>
    
        
        <select id="queryEmpAndDeptByEid" resultMap="empResultMapOne">
          SELECT
            *
          FROM
            t_emp AS te
          LEFT JOIN
            t_dept AS td
          ON
            te.did = td.did
          WHERE
            te.eid =#{eid}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    执行结果:

    Emp(eid=2, empName=lisi, age=21, sex=, email=1234@12.com, dept=Dept(did=1, deptName=A))
    
    • 1

    方式二:association

    映射配置文件

       <resultMap id="empResultMapTwo" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
            <association property="dept" javaType="com.test.pojo.Dept">
                <id property="did" column="did"/>
                <result property="deptName" column="dept_name"/>
            association>
        resultMap>
    
      
        <select id="queryEmpAndDeptByEid" resultMap="empResultMapTwo">
          SELECT
            *
          FROM
            t_emp AS te
          LEFT JOIN
            t_dept AS td
          ON
            te.did = td.did
          WHERE
            te.eid =#{eid}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    association:处理多对一映射关系

    property:需要处理多对一映射关系的属性名(是属性名不是类型别名)

    javaType:该属性的类型

    有了类型便可以通过反射来获取类型中的属性,将查询出来的字段的值,赋值给我们制定的属性。

    方式三:分步查询

    第一步:

    接口(EmpMapper.java)

     	/**
         * 分步查询:
         * 第一步:查询员工信息,获取部门的did
         * @param eid
         * @return
         */
        Emp queryEmpAndDeptByStepOne(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件:

        <resultMap id="empAndStepResultMap" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
            
           <association property="dept"
                        select="com.test.mapper.DeptMapper.queryEmpAndDeptByStepTwo"
                        column="did">
           association>
        resultMap>
    
        <select id="queryEmpAndDeptByStepOne" resultMap="empAndStepResultMap">
            SELECT
              *
             FROM
              t_emp
             WHERE
              eid=#{eid}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    第二步:

    接口(DeptMapper.java)

     	/**
         * 分步查询:
         * 第二步:根据did查询员工所对应的部门
         *
         * @param did
         * @return
         */
        Dept queryEmpAndDeptByStepTwo(@Param("did") Integer did);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    映射配置文件

        <resultMap id="deptresultMap" type="com.test.pojo.Dept">
            <id property="did" column="did"/>
            <result property="deptName" column="dept_name"/>
        resultMap>
    
        
        <select id="queryEmpAndDeptByStepTwo" resultMap="deptresultMap">
            SELECT
              *
             FROM
              t_dept
             WHERE
              did=#{did}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    测试代码

    	 /**
         * 测试分步查询
         * 多对一
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpAndDeptByStepOne() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
            Emp emp = mapper.queryEmpAndDeptByStepOne(2);
            System.out.println(emp);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    执行结果:

    是分两步来执行的
    在这里插入图片描述

    延迟加载

    分步查询的好处:延迟加载

    延迟加载MyBatis中默认是不开启的。但是必须在全局配置文中设置全局配置信息:

    lazyLoadingEnabled:延迟加载的全局开关,当开启时,所有关联的对象都会延迟加载;

    aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性,否则,,每个属性会按需加载。

    配置:
    lazyLoadingEnabled:true

    aggressiveLazyLoading:false

    核心配置文件

     <settings>
            
            <setting name="lazyLoadingEnabled" value="true"/>
     settings>
    
    • 1
    • 2
    • 3
    • 4

    当开启延迟加载的时候。上述分步查询时:

    如果只查询emp的相关信息,则只会执行一条SQL。

    但是,如果要查询员工的部门信息的时候,则会执行两条SQL。

    例如:查询员工的信息和部门的信息

    开启延迟:SQL是一条一条执行的,而不是全部执行完毕后再获取我们需要的数据。

    不开启延迟:SQL一块儿执行,执行完成后,才能获取我们要的数据。

    配置了全部延迟加载后,通过fetchType来单独控制延迟加载和立即加载:

    
           <association property="dept"
                        select="com.test.mapper.DeptMapper.queryEmpAndDeptByStepTwo"
                        column="did"
                        fetchType="lazy"    >
           association>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    一对多映射

    多对一实体:(对应对象)

    package com.test.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    /**
     * 员工表实体
     *
     * @author zhangzengxiu
     * @date 2022/9/11
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Emp {
    
        /**
         * 主键
         */
        private Integer eid;
    
        /**
         * 员工姓名
         */
        private String empName;
    
        /**
         * 年龄
         */
        private Integer age;
    
        /**
         * 性别
         */
        private String sex;
    
        /**
         * 邮箱
         */
        private String email;
    
        /**
         * 部门
         */
        private Dept dept;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    一对多实体:(对应集合)

    package com.test.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import java.util.List;
    
    /**
     * 部门表实体
     *
     * @author zhangzengxiu
     * @date 2022/9/11
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Dept {
    
        /**
         * 主键
         */
        private Integer did;
    
        /**
         * 部门名称
         */
        private String deptName;
    
        /**
         * 多个员工
         */
        private List<Emp> emps;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    接口

        /**
         * 根据did查询部门及员工的信息
         *
         * @param did
         * @return
         */
        Dept queryDeptAndEmp(@Param("did") Integer did);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码

     	/**
         * 测试根据did查询部门及员工的信息
         */
        @Test
        public void testQueryDeptAndEmp() throws Exception{
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
            Dept dept = mapper.queryDeptAndEmp(1);
            System.out.println(dept);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    方式一:collection

    映射配置文件

    	<resultMap id="deptAndEmpResultMap" type="com.test.pojo.Dept">
            <id property="did" column="did"/>
            <result property="deptName" column="dept_name"/>
            
            <collection property="emps" ofType="com.test.pojo.Emp">
                <id property="eid" column="eid"/>
                <result property="empName" column="emp_name"/>
                <result property="age" column="age"/>
                <result property="sex" column="sex"/>
                <result property="email" column="email"/>
            collection>
        resultMap>
        
        
        <select id="queryDeptAndEmp" resultMap="deptAndEmpResultMap">
            SELECT
              *
            FROM
              t_dept AS td
            LEFT JOIN
              t_emp AS te
            ON
              td.did = te.did
            WHERE
              td.did=#{did}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    查询结果

    Dept(did=1, deptName=A, emps=[Emp(eid=1, empName=zhangsan, age=20, sex=, email=1234@12.com, dept=null), Emp(eid=2, empName=lisi, age=21, sex=, email=1234@12.com, dept=null), Emp(eid=3, empName=wangwu, age=22, sex=, email=1234@12.com, dept=null), Emp(eid=4, empName=zhaoliu, age=23, sex=, email=1234@12.com, dept=null), Emp(eid=5, empName=maqi, age=24, sex=, email=1234@12.com, dept=null)])
    
    • 1

    方式二:分步查询

    接口

    DeptMapper.xml

        /**
         * 根据did查询部门及员工的信息,分步查询
         * 第一步:查询部门信息
         *
         * @param did
         * @return
         */
        Dept queryDeptAndEmpByStepOne(@Param("did") Integer did);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    EmpMapper.xml

        /**
         * 根据did查询部门及员工的信息,分步查询
         * 第二步:查询员工信息
         * 查询出来的结果为 List emps 赋值
         * 所以查询出来的结果一定是集合
         * 
         *
         * @param did
         * @return
         */
        List<Emp> queryDeptAndEmpByStepTwo(@Param("did") Integer did);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试代码

     	/**
         * 分步查询:
         * 查询部门和员工信息
         *
         * @throws Exception
         */
        @Test
        public void testQueryDeptAndEmpByStepOne() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
            Dept dept = mapper.queryDeptAndEmpByStepOne(1);
            System.out.println(dept);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    映射配置文件

    DeptMapper.xml

        <resultMap id="deptAndEmpResultMapStepOne" type="com.test.pojo.Dept">
            <id property="did" column="did"/>
            <result property="deptName" column="dept_name"/>
            
            <collection property="emps"
                        select="com.test.mapper.EmpMapper.queryDeptAndEmpByStepTwo"
                        column="did">collection>
        resultMap>
    
        <select id="queryDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapStepOne">
            SELECT
              *
            FROM
              t_dept AS td
            WHERE
              td.did=#{did}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    EmpMapper.xml

        <resultMap id="empResultMap" type="com.test.pojo.Emp">
            
            <id property="eid" column="eid"/>
            
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
        resultMap>
    
    	
        <select id="queryDeptAndEmpByStepTwo" resultMap="empResultMap">
            SELECT
              *
            FROM
              t_emp
            WHERE
              did=#{did}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    动态SQL

    根据特定条件动态拼接SQL语句的功能,解决了拼接SQL语句字符串的痛点。

    动态SQL主要是动态拼接关键字和条件。

    if标签

    接口

        /**
         * 根据条件查询员工信息
         * 动态SQL参数
         *
         * @param emp
         * @return
         */
        List<Emp> queryEmpByCondition(Emp emp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试代码

        /**
         * 测试动态SQL的id标签
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpByCondition() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
            Emp emp = new Emp(null, "zhangsan", 20, "男", "1234@12.com", null);
            List<Emp> emps = mapper.queryEmpByCondition(emp);
            for (Emp emp1 : emps) {
                System.out.println(emp1);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    映射配置文件

        <resultMap id="empResultMap" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
        resultMap>
    
        
        <select id="queryEmpByCondition" resultMap="empResultMap">
            SELECT
           	 *
            FROM
           	 t_emp
            
            where 1=1
                <if test="empName!=null and empName!='' ">
                    emp_name = #{empName}
                if>
                <if test="age!=null and age!='' ">
                    AND age = #{age}
                if>
                <if test="sex!=null and sex!='' ">
                    AND sex = #{sex}
                if>
                <if test="email!=null and email!='' ">
                    AND email = #{email}
                if>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    目前存在的问题:where关键字,如果后面,没有条件成立会多where关键字出来,如果后面第一个条件都不成立,会where 后直接跟and 也会报错。

    目前的解决方案:使用恒等式 1=1的方式来解决

    但是!!!如果第一个条件就满足就会报错, where 1=1 emp_name=#{empName}

    where标签

    动态生成where关键字。能动态添加where 关键字还能将内容前多余的AND或OR去掉;

    以及在全部条件都不满足的情况下,能动态去掉where关键字。

    使用where标签的SQL

    映射配置文件:

        
        <select id="queryEmpByCondition" resultMap="empResultMap">
            SELECT
           	 *
            FROM
          	  t_emp
            <where>
                <if test="empName!=null and empName!='' ">
                    emp_name = #{empName}
                if>
                <if test="age!=null and age!='' ">
                    AND age = #{age}
                if>
                <if test="sex!=null and sex!='' ">
                    AND sex = #{sex}
                if>
                <if test="email!=null and email!='' ">
                    AND email = #{email}
                if>
            where>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    注意:where关键字不能将内容后的AND或者OR去掉,只能将内容前的去掉。后面的有多余的时,会报错。

    trim标签

    若标签中有内容时:

    prefix、suffix:将trim标签中的内容前面或后面添加指定内容

    prefixOverrides、suffixOverrides:将trim标签中的内容前面或后面去掉指定内容

    若标签中没有内容时:

    trim标签也没有任何效果

    
        <select id="queryEmpByCondition" resultMap="empResultMap">
            SELECT
              *
            FROM
             t_emp
            
            <trim prefix="where" prefixOverrides="AND|OR">
                <if test="empName!=null and empName!='' ">
                    emp_name = #{empName}
                if>
                <if test="age!=null and age!='' ">
                    AND age = #{age}
                if>
                <if test="sex!=null and sex!='' ">
                    AND sex = #{sex}
                if>
                <if test="email!=null and email!='' ">
                    AND email = #{email}
                if>
            trim>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    
        <select id="queryEmpByCondition" resultMap="empResultMap">
            SELECT
              *
            FROM
             t_emp
            
            <trim prefix="where" prefixOverrides="AND|OR">
                <if test="empName!=null and empName!='' ">
                    
                    AND emp_name = #{empName}
                if>
                <if test="age!=null and age!='' ">
                    AND age = #{age}
                if>
                <if test="sex!=null and sex!='' ">
                    AND sex = #{sex}
                if>
                <if test="email!=null and email!='' ">
                    AND email = #{email}
                if>
            trim>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    
        <select id="queryEmpByCondition" resultMap="empResultMap">
            SELECT
              *
            FROM
             t_emp
            
            <trim prefix="where" suffixOverrides="AND|OR">
                <if test="empName!=null and empName!='' ">
                    emp_name = #{empName} AND
                if>
                <if test="age!=null and age!='' ">
                    age = #{age} AND
                if>
                <if test="sex!=null and sex!='' ">
                    sex = #{sex} AND
                if>
                <if test="email!=null and email!='' ">
                   
                    email = #{email} AND
                if>
            trim>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    choose、when、otherwise

    相当于if…else if…else

    choose是父标签,when和otherwise是写到父标签中的。

    when相当于if else if。

    与if标签的区别:if是每个条件都会判断。

    when相当于 if else if,相当于只走一个条件

    otherwise相当于else

    when最少要有一个

    otherwise最多只能有一个

    接口

        /**
         * 测试choose标签
         * 根据emp查询emp列表
         *
         * @param emp
         * @return
         */
        List<Emp> queryEmpByChoose(Emp emp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试代码

        /**
         * 测试choose
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpByChoose() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
            Emp emp = new Emp(null, "zhangsan", 20, "男", "1234@12.com", null);
            List<Emp> emps = mapper.queryEmpByChoose(emp);
            for (Emp emp1 : emps) {
                System.out.println(emp1);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    映射配置文件

    
        <select id="queryEmpByChoose" resultMap="empResultMap">
            SELECT
              *
            FROM
              t_emp
            <where>
               <choose>
                   <when test="empName!=null and empName!='' ">
                       emp_name=#{empName}
                   when>
                   <when test="age!=null and age!='' ">
                       age=#{age}
                   when>
                   <when test="sex!=null and sex!='' ">
                       sex=#{sex}
                   when>
                   <when test="email!=null and email!='' ">
                       email=#{email}
                   when>
                   <otherwise>
                       did = 1
                   otherwise>
               choose>
            where>
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    注意:

    when相当于java中的,if(){}else if(){} else if(){}

    otherwise相当于最后的else

    foreach标签

    批量操作

    接口

        /**
         * 测试根据eid数组进行批量删除
         *
         * @param eids
         * @return
         */
        int delEmpByeids(@Param("eids") Integer[] eids);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码

        /**
         * 测试根据eid数组进行批量删除
         *
         * @throws Exception
         */
        @Test
        public void testDelEmpByeids() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
            Integer[] eids = {9, 10, 11};
            int res = mapper.delEmpByeids(eids);
            Assert.assertEquals(res, eids.length);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    映射配置文件

    方式一:

        
        <delete id="delEmpByeids">
            DELETE FROM t_emp
            WHERE
            
            <foreach collection="eids" open="eid IN(" item="eid" separator="," close=")">
                #{eid}
            foreach>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    方式二:

        
        <delete id="delEmpByeids">
            DELETE FROM t_emp
            WHERE
            <foreach collection="eids" item="eid" separator="OR">
                eid= #{eid}
            foreach>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    批量添加

    接口

        /**
         * 测试批量添加
         *
         * @param emps
         * @return
         */
        int insertEmpList(@Param("emps") List<Emp> emps);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码

        /**
         * 测试集合批量添加
         *
         * @throws Exception
         */
        @Test
        public void testInsertEmpList() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
            List<Emp> emps = new ArrayList<Emp>();
            Emp emp1 = new Emp(null, "a", 22, "男", "112@12.com", null);
            Emp emp2 = new Emp(null, "b", 22, "男", "112@12.com", null);
            Emp emp3 = new Emp(null, "c", 22, "男", "112@12.com", null);
            Emp emp4 = new Emp(null, "d", 22, "男", "112@12.com", null);
            emps.add(emp1);
            emps.add(emp2);
            emps.add(emp3);
            emps.add(emp4);
            int res = mapper.insertEmpList(emps);
            Assert.assertEquals(res, emps.size());
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    映射配置文件

        
        <insert id="insertEmpList">
            INSERT INTO t_emp VALUES
            <foreach collection="emps" item="emp" separator=",">
                (null,#{emp.empName},#{emp.age},#{emp.sex},#{emp.email},null)
            foreach>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    	
        <insert id="insertEmps">
            INSERT INTO t_emp
            <trim prefix="(" suffixOverrides="," suffix=")">
                emp_name,
                age,
                sex,
                email
            trim>
            VALUES
            <foreach collection="empList" item="emp" separator=",">
                <trim prefix="(" suffixOverrides="," suffix=")">
                	#{emp.empName},
                    #{emp.age},
                    #{emp.sex},
                    #{emp.email},
                    if>
                trim>
            foreach>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如果传入的值有null的话,SQL会报错,个数不匹配:

        
        <insert id="insertEmpList">
            INSERT INTO t_emp
            <trim prefix="(" suffix=")">
                emp_name,
                age,
                sex,
                email
            trim>
            VALUES
            
            <foreach collection="emps" item="emp" separator=",">
                
                <trim prefix="(" suffixOverrides="," suffix=")">
                    <if test="emp.empName!=null and emp.empName!=''">
                       #{emp.empName},
                    if>
                    <if test="emp.age!=null and emp.age!=''">
                        #{emp.age},
                    if>
                    <if test="emp.sex!=null and emp.sex!=''">
                        #{emp.sex},
                    if>
                    <if test="emp.email!=null and emp.email!=''">
                        #{emp.email},
                    if>
                trim>
            foreach>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    sql标签

    将常用的sql,抽取出来到一个sql片段中

    举例:

        
        <select id="queryEmpList" resultMap="empResultMap">
            SELECT
              *
            FROM
              t_emp
        select>    
    
    	<select id="queryEmpList" resultMap="empResultMap">
            SELECT
              eid,
              emp_name,
              age,
              sex,
              email
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用sql片段

        <sql id="empColumn">
             eid,
              emp_name,
              age,
              sex,
              email
        sql>
        
        
        <select id="queryEmpList" resultMap="empResultMap">
            SELECT
            <include refid="empColumn"/>
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    抽取出来的sql片段,其他sql可复用

    动态SQL的CRUD组合拳
    添加

    接口

    	/**
         * 添加emp
         *
         * @param emp
         * @return
         */
        int insertEmp(Emp emp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <insert id="insertEmp">
            INSERT INTO t_emp
            <trim prefix="(" suffixOverrides="," suffix=")">
                <if test="empName!=null and empName!=''">
                    emp_name,
                if>
                <if test="age!=null and age!=''">
                    age,
                if>
                <if test="sex!=null and sex!=''">
                    sex,
                if>
                <if test="email!=null and email!=''">
                    email,
                if>
            trim>
            VALUES
            <trim prefix="(" suffixOverrides="," suffix=")">
                <if test="empName!=null and empName!=''">
                    #{empName},
                if>
                <if test="age!=null and age!=''">
                    #{age},
                if>
                <if test="sex!=null and sex!=''">
                    #{sex},
                if>
                <if test="email!=null and email!=''">
                    #{email},
                if>
            trim>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    添加并赋值主键

    并将自增后的主键值赋值给eid属性

    接口

    	/**
         * 添加emp
         * 并返回自增的主键eid
         *
         * @param emp
         * @return
         */
        int insertEmpReturnEid(Emp emp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    映射配置文件

    
        <insert id="insertEmpReturnEid" useGeneratedKeys="true" keyProperty="eid">
            INSERT INTO t_emp
            <trim prefix="(" suffixOverrides="," suffix=")">
                <if test="empName!=null and empName!=''">
                    emp_name,
                if>
                <if test="age!=null and age!=''">
                    age,
                if>
                <if test="sex!=null and sex!=''">
                    sex,
                if>
                <if test="email!=null and email!=''">
                    email,
                if>
            trim>
            VALUES
            <trim prefix="(" suffixOverrides="," suffix=")">
                <if test="empName!=null and empName!=''">
                    #{empName},
                if>
                <if test="age!=null and age!=''">
                    #{age},
                if>
                <if test="sex!=null and sex!=''">
                    #{sex},
                if>
                <if test="email!=null and email!=''">
                    #{email},
                if>
            trim>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    批量添加

    接口

    	/**
         * 批量添加emp
         *
         * @param empList
         * @return
         */
        int insertEmps(@Param("empList") List<Emp> empList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    	
        <insert id="insertEmps">
            INSERT INTO t_emp
            <trim prefix="(" suffixOverrides="," suffix=")">
                emp_name,
                age,
                sex,
                email
            trim>
            VALUES
            <foreach collection="empList" item="emp" separator=",">
                <trim prefix="(" suffixOverrides="," suffix=")">
                	#{emp.empName},
                    #{emp.age},
                    #{emp.sex},
                    #{emp.email},
                    if>
                trim>
            foreach>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    如果值有null的话,下面的SQL会报错,参数个数不匹配:

    
        <insert id="insertEmps">
            INSERT INTO t_emp
            <trim prefix="(" suffixOverrides="," suffix=")">
                emp_name,
                age,
                sex,
                email
            trim>
            VALUES
            <foreach collection="empList" item="emp" separator=",">
                <trim prefix="(" suffixOverrides="," suffix=")">
                    <if test="emp.empName!=null and emp.empName!=''">
                        #{emp.empName},
                    if>
                    <if test="emp.age!=null and emp.age!=''">
                        #{emp.age},
                    if>
                    <if test="emp.sex!=null and emp.sex!=''">
                        #{emp.sex},
                    if>
                    <if test="emp.email!=null and emp.email!=''">
                        #{emp.email},
                    if>
                trim>
            foreach>
        insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    当批量添加的数据为空时,会报错,而不是占用空行

    删除

    接口

    	/**
         * 根据eid删除emp
         *
         * @param eid
         * @return
         */
        int delEmpByEid(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <delete id="delEmpByEid">
            DELETE FROM
            	t_emp
            WHERE
            	eid = #{eid}
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    批量删除

    接口

    	/**
         * 根据eid列表批量删除
         *
         * @param eids
         * @return
         */
        int delEmpsByEids(@Param("eids") List<Integer> eids);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    where动态标签如果失效的话,会删表!!!! 别用这个写法

    
        <delete id="delEmpsByEids">
            DELETE FROM t_emp
            
            <where>
            	<foreach collection="eids" item="eid" separator="OR">
            		eid = #{eid}
            	foreach>
            where>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    方式二:

    集合里没数据的时候,多个WHERE关键字,会报错。宁愿报错也不能删表!!!

    
        <delete id="delEmpsByEids">
            DELETE FROM t_emp
            WHERE
            <foreach collection="eids" item="eid" separator="OR">
                eid = #{eid}
            foreach>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    方式三:

    	<delete id="delEmpsByEids2">
            DELETE FROM t_emp
            WHERE
            <foreach collection="eids" open="eid IN(" item="eid" separator="," close=")">
                #{eid}
            foreach>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    方式四:

    	<delete id="delEmpsByEids3">
            DELETE FROM t_emp
            WHERE eid IN
            <foreach collection="eids" open="(" item="eid" separator="," close=")">
                #{eid}
            foreach>
        delete>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    更新

    接口

    	/**
         * 更新emp
         *
         * @param emp
         * @return
         */
        int updateEmp(Emp emp);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <update id="updateEmp">
            UPDATE t_emp
            <set>
                <if test="empName!=null and empName!=''">
                    emp_name = #{empName},
                if>
                <if test="age!=null and age!=''">
                    age = #{age},
                if>
                <if test="sex!=null and sex!=''">
                    sex = #{sex},
                if>
                <if test="email!=null and email!=''">
                    email = #{email},
                if>
            set>
            WHERE eid = #{eid}
        update>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    查询

    接口

        /**
         * 根据eid查询emp
         *
         * @param eid
         * @return
         */
        Emp queryEmpByEid(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

    
        <select id="queryEmpByEid" resultMap="empResultMap">
            SELECT
            	<include refid="empColumn"/>
            FROM
            	t_emp
            WHERE
            	eid = #{eid}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    查询列表

    接口

        /**
         * 查询emp列表
         *
         * @return
         */
        List<Emp> queryEmpList();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    映射配置文件

    
        <select id="queryEmpList" resultMap="empResultMap">
            SELECT
            	<include refid="empColumn"/>
            FROM
            	t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    缓存

    缓存只针对查询功能有效。

    一级缓存(默认开启)

    一级缓存是SqlSession级别的,同一个sqlsession查询的数据会被缓存,是不区分Mapper 的,下次查询相同的数据,会从缓存中直接取,而不走数据库查询了。

    接口

        /**
         * 根据eid获取emp
         *
         * @param eid
         * @return
         */
        Emp queryEmp(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    映射配置文件

        <resultMap id="empResultMap" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
        resultMap>
    
        <sql id="empColumn">
            eid,
            emp_name,
            age,
            sex,
            email
        sql>
    
        
        <select id="queryEmp" resultMap="empResultMap">
            SELECT
              <include refid="empColumn"/>
            FROM
              t_emp
            WHERE
              eid = #{eid}
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    测试代码1

        /**
         * 测试同一个Sqlsession中查询两次同样的数据
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmp1() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
            Emp emp1 = mapper.queryEmp(1);
            System.out.println(emp1);
    
            System.out.println("=======================");
    
            Emp emp2 = mapper.queryEmp(1);
            System.out.println(emp2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行情况
    在这里插入图片描述

    同一个Sqlsession的情况下,执行两次相同的查询,只执行了一次SQL。

    说明,只查了一次数据库。另一次是从缓存中获取得到的。

    测试代码2

        /**
         * 测试同一个sqlsession情况下,不同mapper执行情况
         * @throws Exception
         */
        @Test
        public void testQueryEmp2() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            CacheMapper mapper1 = sqlSession.getMapper(CacheMapper.class);
            Emp emp1 = mapper1.queryEmp(1);
            System.out.println(emp1);
    
            System.out.println("=======================");
    
            CacheMapper mapper2 = sqlSession.getMapper(CacheMapper.class);
            Emp emp2 = mapper2.queryEmp(1);
            System.out.println(emp2);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    执行情况
    在这里插入图片描述

    测试代码3

        /**
         * 测试不同sqlsession
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmp3() throws Exception {
            SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
            CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
            Emp emp1 = mapper1.queryEmp(1);
            System.out.println(emp1);
    
            System.out.println("=======================");
    
            SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
            CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
            Emp emp2 = mapper2.queryEmp(1);
            System.out.println(emp2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行情况
    在这里插入图片描述

    缓存失效情况
    • 不同的sqlsession对应不同的一级缓存;
    • 同一个sqlsession但是查询条件不同;
    • 同一个sqlsession两次查询期间执行了任何一次增删改的操作;
    • 同一个sqlsession两次查询期间手动清空了缓存;

    缓存只是用来提高我们的查询速度的,并不能影响查询的真实性。

    执行任意一次增删改之后,都会将一级缓存中的数据清空。

    手动清空缓存:sqlSession.clearCache();

    测试代码(测试清空缓存)

        /**
         * 测试手动清空缓存后是否还从缓存中取数据
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmp5() throws Exception {
            SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
            CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
            Emp emp1 = mapper1.queryEmp(1);
            System.out.println(emp1);
    
            System.out.println("=======================");
    
            //手动清空缓存
            sqlSession1.clearCache();
    
            System.out.println("=======================");
    
            Emp emp2 = mapper1.queryEmp(1);
            System.out.println(emp2);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    执行结果
    在这里插入图片描述

    二级缓存

    二级缓存是sqlsessionFactory级别,且需要手动开启。

    通过同一个sqlsessionFactory创建的sqlsession查询的结果会被缓存。此后,若再次执行相同的查询语句,结果就会从缓存中获取。

    二级缓存开启条件:

    • 在核心配置文件中,设置全局配置属性:cacheEnabled=“true” ,默认为true,不需设置;
    • 在映射配置文件中设置标签
    • 二级缓存必须在sqlsession关闭或提交之后才有效;(当sqlsession没有提交或关闭时,会保存到一级缓存)
    • 查询的数据所转换的实体类型必须实现序列化接口;

    接口

        /**
         * 根据eid查询emp
         *
         * @param eid
         * @return
         */
        Emp queryEmp(@Param("eid") Integer eid);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实体类(实现序列化接口)

    package com.test.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import java.io.Serializable;
    
    /**
     * 员工表实体
     *
     * @author zhangzengxiu
     * @date 2022/9/11
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class Emp implements Serializable {
        private static final long serialVersionUID = 1490329483937671473L;
    
        /**
         * 主键
         */
        private Integer eid;
    
        /**
         * 员工姓名
         */
        private String empName;
    
        /**
         * 年龄
         */
        private Integer age;
    
        /**
         * 性别
         */
        private String sex;
    
        /**
         * 邮箱
         */
        private String email;
    
        /**
         * 部门
         */
        private Dept dept;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    测试代码

        /**
         * 测试二级缓存
         */
        @Test
        public void testQueryEmp() {
            //加载核心配置文件
            InputStream is = null;
            try {
                is = Resources.getResourceAsStream("mybatis-config.xml");
                //获取SqlSessionFactoryBuilder
                SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
                //获取SqlSessionFactory
                SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
                //获取SqlSession 设置为自动提交
                SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
                CacheMapper2 mapper1 = sqlSession1.getMapper(CacheMapper2.class);
                Emp emp1 = mapper1.queryEmp(1);
                System.out.println(emp1);
    
                SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
                CacheMapper2 mapper2 = sqlSession2.getMapper(CacheMapper2.class);
                Emp emp2 = mapper2.queryEmp(1);
                System.out.println(emp2);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    映射配置文件(手动开启二级缓存)

        <resultMap id="empResultMap" type="com.test.pojo.Emp">
            <id property="eid" column="eid"/>
            <result property="empName" column="emp_name"/>
            <result property="age" column="age"/>
            <result property="sex" column="sex"/>
            <result property="email" column="email"/>
        resultMap>
    
        <sql id="empColumn">
            eid,
            emp_name,
            age,
            sex,
            email
        sql>
    
        
        <cache/>
    
        
        <select id="queryEmp" resultMap="empResultMap">
            SELECT
            <include refid="empColumn"/>
            FROM
              t_emp
            WHERE
              eid = #{eid}
        select>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    执行结果
    在这里插入图片描述

    缓存并未生效,原因是:未关闭sqlsession。

    测试代码(关闭sqlsession)

        /**
         * 测试二级缓存
         */
        @Test
        public void testQueryEmp() {
            //加载核心配置文件
            InputStream is = null;
            try {
                is = Resources.getResourceAsStream("mybatis-config.xml");
                //获取SqlSessionFactoryBuilder
                SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
                //获取SqlSessionFactory
                SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
                //获取SqlSession 设置为自动提交
                SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
                CacheMapper2 mapper1 = sqlSession1.getMapper(CacheMapper2.class);
                Emp emp1 = mapper1.queryEmp(1);
                System.out.println(emp1);
                //关闭sqlsession1
                sqlSession1.close();
    
                SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
                CacheMapper2 mapper2 = sqlSession2.getMapper(CacheMapper2.class);
                Emp emp2 = mapper2.queryEmp(1);
                System.out.println(emp2);
                
                //关闭sqlsession2
                sqlSession2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    执行结果
    在这里插入图片描述

    SQL只执行了一次,说明缓存生效。
    增删改操作既会失效一级缓存也会失效二级缓存;

    手动清空缓存只针对一级缓存有效。

    缓存失效情况

    两次查询之间执行了任意增删改,会使一级和二级缓存同时失效;

    二级缓存相关配置

    mapper配置文件中,添加的cache标签可以设置属性:

    • eviction:缓存回收策略(缓存是缓存到内存中的)

      LRU:最近最少使用,移除最长时间不被使用的对象。(默认使用)

      FIFO:先进先出,按照缓存顺序进行移除

      SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象

      WEAK:弱引用,更积极地移除基于垃圾回收器状态和弱引用规则的对象

    • flushInterval:刷新间隔,单位:毫秒

      MyBatis缓存默认多长事件刷新一次,默认情况下不设置,缓存仅仅调用语句时刷新(增删改语句)

    • readOnly:只读,true/false

      true:只读缓存,会给所有调用者返回缓存对象的相同实例,就是把缓存实例直接返给我们的用户,不能直接操作这个缓存,会导致与数据库数据不一致。因此,这些对象不能被修改,提供了很重要的性能优势。

      false:读写缓存,会对返回缓存对象的拷贝(通过序列化),操作拷贝对象不会影响原对象,速度较慢但是安全。默认是false

    • size:引用数目,正整数。

      当前缓存最多能存储多少个对象,设置过大容易导致内存溢出;

    • type:可以使用第三方缓存

    MyBatis缓存查询顺序
    • 先查询大范围的二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以直接使用;
    • 二级缓存未命中的话,再去查询一级缓存;
    • 一级缓存也未命中,则查询数据库;
    • sqlsession未关闭前,数据是保存到一级缓存中的。当sqlsession提交后,一级缓存的数据会写入到二级缓存
    整合第三方缓存EHCache

    MyBatis作为一个持久层框架,MyBatis缓存可提高查询效率,MySQL是将数据存储到磁盘上,查询MySQL上的数据会设计到IO操作,查询缓存的时候自然比磁盘文件快。MyBatis可以使用第三方技术来代替二级缓存,一级缓存不能被第三方技术代替。

    pom依赖

            
            <dependency>
                <groupId>org.mybatis.cachesgroupId>
                <artifactId>mybatis-ehcacheartifactId>
                <version>1.2.1version>
            dependency>
            
            <dependency>
                <groupId>ch.qos.logbackgroupId>
                <artifactId>logback-classicartifactId>
                <version>1.2.3version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    //TODO

    逆向工程

    //TODO

    分页插件

    pom依赖

           
            <dependency>
                <groupId>com.github.pagehelpergroupId>
                <artifactId>pagehelperartifactId>
                <version>5.1.2version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    配置分页插件(mybatis-config.xml)

        <plugins>
            
            <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
        plugins>
    
    • 1
    • 2
    • 3
    • 4

    接口

        /**
         * 查询emp列表
         *
         * @return
         */
        List<Emp> queryEmpList();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    映射配置文件

        
        <select id="queryEmpList" resultMap="empResultMap">
            SELECT
            <include refid="empColumn"/>
            FROM
              t_emp
        select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试代码

    	/**
         * 测试查询emp列表
         * 分页
         *
         * @throws Exception
         */
        @Test
        public void testQueryEmpListWithPage() throws Exception {
            SqlSession sqlSession = SqlSessionUtil.getSqlSession();
            PageMapper mapper = sqlSession.getMapper(PageMapper.class);
            //开启分页
            PageHelper.startPage(2, 2);
            List<Emp> emps = mapper.queryEmpList();
            for (Emp emp : emps) {
                System.out.println(emp);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行结果
    在这里插入图片描述

    获取返回的Page

    {count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=15, pages=8, reasonable=false, pageSizeZero=false}
    
    • 1

    获取更多参数

    		//开启分页
            PageHelper.startPage(2, 2);
            List<Emp> emps = mapper.queryEmpList();
            //导航页码
            int navigatePages = 3;
            PageInfo<Emp> pageInfo = new PageInfo<Emp>(emps, navigatePages);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果

    PageInfo
    {pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=15, pages=8, 
     
    list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=15, pages=8, reasonable=false, pageSizeZero=false},
    
    prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=3, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    常用数据:

    pageNum:当前页的页码

    pageSize:每页显示条数

    size:当前页显示的真实条数

    total:总记录数

    pages:总页数

    prePage:上一页姨妈

    nextPage:下一页页码

    isFirstPage/isLastPage:是否为第/最后一页

    hasPreviousPage/ hasNextPage:是否存在上/下一页

    navigatePages:导航分页的页码数

    navigatepageNums:导航分页的页码 [1, 2, 3]

  • 相关阅读:
    视频倒放怎么制作?快来学会这几个简单的方法
    【css | linear-gradient】linear-gradient()的用法
    ROS1云课→07基础概念
    【Vivado使用】从0开始 综合后生成门级网表
    uniApp webview 中调用底座蓝牙打印功能异常
    计算摄影——妆造迁移
    京东小程序平台助力快送实现跨端
    磁选机是什么?
    ElasticSearch学习笔记(三)
    前端技能树,面试复习第 56 天—— LeetCode 算法常考题型 | 百题大战
  • 原文地址:https://blog.csdn.net/zhangzengxiu/article/details/126696453