MyBatis实践:提高持久层数据处理效率

文章目录

  • 1 Mybatis简介
    • 1.1 简介
    • 1.2 持久层框架对比
  • 2 快速入门
    • 2.1 准备数据库
    • 2.2 项目搭建
    • 2.3 依赖导入
    • 2.4 准备MyBatis配置文件
    • 2.5 实体类准备
    • 2.6 准备Mapper接口和MapperXML文件
    • 2.7 运行和测试
  • 3. 核心配置文件
  • 4. MyBatis进阶使用
    • 4.0 以包为单位,引入所有的映射文件
    • 4.1 开启日志功能
    • 4.2 SQL语句传参形式
    • 4.3 MapperXML模版文件
    • 4.4 SqlSessionUtil工具类
    • 4.5 数据输入
      • 4.5.1 Mybatis总体机制概括
      • 4.5.2 概念说明
      • 4.5.3 单个字面量类型的参数
      • 4.5.3 多个字面量类型的参数
      • 4.5.5 map集合类型的参数
      • 4.5.6 实体类类型的参数
      • 4.5.7 使用@Param标识参数
    • 4.6 数据输出
      • 4.6.1 输出概述
      • 4.6.2 单个简单类型
      • 4.6.3 返回实体类对象
      • 4.6.4 返回单条map类型
      • 4.6.5 返回多条map类型
      • 4.6.6 返回list集合类型
      • 4.6.7 返回自增主键值
    • 4.7 增删改查
    • 4.8 自定义映射resultMap
      • 4.8.0 驼峰转换
      • 4.8.1 起别名
      • 4.8.2 resultMap
    • 4.9 模糊查询
    • 4.10 批量删除
    • 4.11 多表映射
      • 4.11.1 多对一映射
      • 4.11.2 一对多映射
    • 4.12 分步查询
    • 4.13 实体类别名
    • 4.14 使用注解增删改查
  • 5.动态SQL
    • if
    • where
    • set
    • trim
    • choose、when、otherwise
    • foreach
    • sql片段
  • 6. MyBatis的缓存
    • 一级缓存
    • 二级缓存
    • 二级缓存的相关配置
    • MyBatis缓存查询的顺序
    • 整合第三方缓存EHCache
  • 7. MyBatis的逆向工程
  • 8. MyBatis X
  • 9. 分页

1 Mybatis简介

1.1 简介

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

1.2 持久层框架对比

  • JDBC
    • SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate 和 JPA
    • 操作简便,开发效率高
    • 程序中的长难复杂 SQL 需要绕过框架
    • 内部自动生成的 SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难。
    • 反射操作太多,导致数据库性能下降
  • MyBatis
    • 轻量级,性能出色
    • SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于 Hibernate,但是完全能够接收

开发效率:Hibernate>Mybatis>JDBC

运行效率:JDBC>Mybatis>Hibernate

2 快速入门

2.1 准备数据库

  • 用户表(t_user)
    在这里插入图片描述

    CREATE DATABASE `mybatis-example`;USE `mybatis-example`;CREATE TABLE `t_user` (`id` int NOT NULL AUTO_INCREMENT,`username` varchar(20),`password` varchar(20),`age` int,`gender` char(1),`email` varchar(50),PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;INSERT INTO `t_user`(username,password,age,gender,email) VALUES("tom","123",25,'男',"12345@abc.com");
    INSERT INTO `t_user`(username,password,age,gender,email) VALUES("jerry","456",23,'男',"45678@abc.com");
    
  • 员工表(t_emp)在这里插入图片描述

    CREATE TABLE `t_emp`(emp_id INT AUTO_INCREMENT,emp_name CHAR(100),emp_salary DOUBLE(10,5),PRIMARY KEY(emp_id)
    );INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("tom",200.33);
    INSERT INTO `t_emp`(emp_name,emp_salary) VALUES("jerry",666.66);
    

2.2 项目搭建

在这里插入图片描述

2.3 依赖导入

pom.xml

<dependencies><!-- mybatis依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version></dependency><!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!--junit5测试--><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.3.1</version></dependency>
</dependencies>

2.4 准备MyBatis配置文件

在resources目录下创建mybatis框架配置文件: 数据库连接信息,mybatis配置,引入mapper.xml配置等!

  • jdbc.properties

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis-example
    jdbc.username=root
    jdbc.password=root
    
  • mybatis-config.xml
    习惯上命名为 mybatis-config.xml,这个文件名仅仅只是建议,并非强制要求。将来整合 Spring 之后,这个配置文件可以省略,所以大家操作时可以直接复制、粘贴。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration><!--引入properties文件,此时就可以${属性名}的方式访问属性值--><properties resource="jdbc.properties"></properties><!--设置连接数据库的环境--><!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 --><environments default="development"><!-- environment表示配置Mybatis开发环境里一个具体的环境 --><environment id="development"><!-- Mybatis的内置的事务管理器 --><transactionManager type="JDBC"/><!--dataSource:配置数据源属性:type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建type="JNDI":调用上下文中的数据源--><dataSource type="POOLED"><!--设置驱动类的全类名--><property name="driver" value="${jdbc.driver}"/><!--设置连接数据库的连接地址--><property name="url" value="${jdbc.url}"/><!--设置连接数据库的用户名--><property name="username" value="${jdbc.username}"/><!--设置连接数据库的密码--><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--引入mybatis映射文件--><mappers><!-- Mapper注册:指定Mybatis映射文件的具体位置 --><!-- mapper标签:配置一个具体的Mapper映射文件 --><!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 --><!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 --><mapper resource="mappers/UserMapper.xml"/><mapper resource="mappers/EmpMapper.xml"/></mappers>
    </configuration>
    

2.5 实体类准备

  • 用户实体类(属性名与数据库字段名一致)

    package com.xxxx.lln.pojo;public class User {private Integer id;private String username;private String password;private Integer age;private String gender;private String email;(此处省略get||set||toString方法)
    }
    
  • 员工实体类

    package com.xxxx.lln.pojo;public class Emp {private Integer empId;private String empName;private Double empSalary;(此处省略get||set||toString方法)
    }
    

2.6 准备Mapper接口和MapperXML文件

MyBatis 框架下,SQL语句编写位置发生改变,从原来的Java类,改成XML或者注解定义!

推荐在XML文件中编写SQL语句,让用户能更专注于 SQL 代码,不用关注其他的JDBC代码。

如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码!!

一般编写SQL语句的文件命名:XxxMapper.xml Xxx一般取表名!!

Mybatis 中的 Mapper 接口相当于以前的 Dao。但是区别在于,Mapper 仅仅只是建接口即可,我们不需要提供实现类,具体的SQL写到对应的Mapper文件,该用法的思路如下图所示:

在这里插入图片描述

  • 定义UserMapper接口

    package com.xxxx.lln.mapper;import com.xxxx.lln.pojo.User;/***  t_user表对应数据库SQL语句映射接口!*  接口只规定方法,参数和返回值!*  mapper.xml中编写具体SQL语句!*/
    public interface UserMapper {/*** 根据用户id查询用户数据方法* @param id* @return 用户实体对象*/User getUserById(Integer id);}
  • 配置UserMapperXML文件
    位置: resources/mappers/UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.xxxx.lln.mapper.UserMapper"><!--mapper接口和映射文件要保证两个一致:1.mapper接口的全类名和映射文件的namespace一致2.mapper接口中的方法的方法名要和映射文件中的sql语句的id保持一致--><!-- 查询使用 select标签id = 方法名resultType = 返回值类型标签内编写SQL语句--><!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 --><!-- resultType属性:指定封装查询结果的Java实体类的全类名 --><select id="getUserById" resultType="com.xxxx.lln.pojo.User"><!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符 --><!-- 给数据库每一个字段设置一个别名,让别名和Java实体类中属性名一致 -->select id, username, password, age, gender, emailfrom t_userwhere id = #{id}</select></mapper>
    
  • 定义EmpMapper接口

    package com.xxxx.lln.mapper;public interface EmpMapper {}
    
  • 配置EmpMapperXML文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.xxxx.lln.mapper.EmpMapper"></mapper>
    
  • 注意:

    • 方法名和SQL的id一致
    • 方法返回值和resultType一致
    • 方法的参数和SQL的参数一致
    • 接口的全类名和映射配置文件的名称空间一致

2.7 运行和测试

package com.xxxx.lln;import com.xxxx.lln.mapper.UserMapper;
import com.xxxx.lln.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;import java.io.IOException;
import java.io.InputStream;public class MyTest {@Testpublic void testSelectUser() throws IOException {//获取核心配置文件的输入流InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");//获取SqlSessionFactoryBuilder对象SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);//获取sql的会话对象SqlSession(不会自动提交事务),是MyBatis提供的操作数据库的对象SqlSession sqlSession = sqlSessionFactory.openSession();//获取sql的会话对象SqlSession(会自动提交事务),是MyBatis提供的操作数据库的对象//SqlSession sqlSession = sqlSessionFactory.openSession(true);//获取UserMapper的代理实现对象getMapper(Class<T> var1)UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//调用mapper接口中的方法,实现根据Id查询用户信息的功能User user = userMapper.getUserById(1);//通过sql语句的唯一标识找到sql并执行,唯一标识是namespace.sqlId//User user = sqlSession.selectOne("com.xxxx.lln.mapper.UserMapper.getUserById",1);System.out.println("返回结果:"+user);//提交事务,查询其实不用sqlSession.commit();//关闭会话sqlSession.close();}}
  • 说明:

    • SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
    • SqlSessionFactory:是“生产”SqlSession的“工厂”。
    • 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。

  • SqlSession和HttpSession区别
    • HttpSession:工作在Web服务器上,属于表述层。
      • 代表浏览器和Web服务器之间的会话。
    • SqlSession:不依赖Web服务器,属于持久化层。
      • 代表Java程序和数据库之间的会话。
         
        在这里插入图片描述

3. 核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--引入properties文件,此时就可以${属性名}的方式访问属性值--><properties resource="jdbc.properties"></properties><settings><!-- 使用Log4j2作为日志实现! --><setting name="logImpl" value="LOG4J2"/><!--将表中字段的下划线自动转换为驼峰--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/></settings><typeAliases><!--typeAlias:设置某个具体的类型的别名属性: type:需要设置别名的类型的全类名alias:设置此类型的别名,若不设置此属性,该类型拥有默认的别名,即类名且不区分大小写若设置此属性,此时该类型的别名只能使用alias所设置的值--><!--<typeAlias type="com.atguigu.mybatis.bean.User"></typeAlias>--><!--<typeAlias type="com.atguigu.mybatis.bean.User" alias="abc"> </typeAlias>--><!--以包为单位,设置改包下所有的类型都拥有默认的别名,即类名且不区分大小写--><package name="com.atguigu.mybatis.bean"/></typeAliases><!--environments:设置多个连接数据库的环境 属性: default:设置默认使用的环境的id --><environments default="mysql_test"><!--environment:设置具体的连接数据库的环境信息属性: id:设置环境的唯一标识,可通过environments标签中的default设置某一个环境的id, 表示默认使用的环境--><environment id="mysql_test"><!--transactionManager:设置事务管理方式 属性:type:设置事务管理方式,type="JDBC|MANAGED" type="JDBC":设置当前环境的事务管理都必须手动处理type="MANAGED":设置事务被管理,例如spring中的AOP--><transactionManager type="JDBC"/><!--dataSource:设置数据源属性:type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI"type="POOLED":使用数据库连接池,即会将创建的连接进行缓存,下次使用可以从缓存中直接获取,不需要重新创建type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建type="JNDI":调用上下文中的数据源--><dataSource type="POOLED"><!--设置驱动类的全类名--><property name="driver" value="${jdbc.driver}"/><!--设置连接数据库的连接地址--><property name="url" value="${jdbc.url}"/><!--设置连接数据库的用户名--><property name="username" value="${jdbc.username}"/><!--设置连接数据库的密码--><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--引入映射文件--><mappers><!-- Mapper注册:指定Mybatis映射文件的具体位置 --><!-- mapper标签:配置一个具体的Mapper映射文件 --><!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 --><!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 --><!--<mapper resource="mappers/UserMapper.xml"/>--><!-- <mapper resource="mappers/EmpMapper.xml"/>--><!--以包为单位,将包下所有的映射文件引入核心配置文件注意:此方式必须保证mapper接口和mapper映射文件必须在相同的包下接口名和映射文件名字一致创建包的时候以斜线为分隔符--><package name="com.atguigu.mybatis.mapper"/></mappers></configuration>

4. MyBatis进阶使用

4.0 以包为单位,引入所有的映射文件

  • 在resource文件下,创建以下文件夹,以斜线为分隔符
    在这里插入图片描述

  • 将刚才的MapperXML文件移动到新创建的文件夹下
    在这里插入图片描述

  • 修改mybatis-config.xml配置文件

        <!--引入mybatis映射文件--><mappers><!--<mapper resource="mappers/UserMapper.xml"/>--><!-- <mapper resource="mappers/EmpMapper.xml"/>--><!--以包为单位,将包下所有的映射文件引入核心配置文件注意:此方式必须保证mapper接口和mapperXML映射文件必须在相同的包下接口名和映射文件名字一致创建包的时候以斜线为分隔符--><package name="com.xxxx.lln.mapper"/></mappers>
    

4.1 开启日志功能

  • 添加以下配置以启用 MyBatis 日志

    <settings><!-- 使用Log4j2作为日志实现! --><setting name="logImpl" value="LOG4J2"/>
    </settings>
    
  • 引入相应的日志实现依赖

    <!--log4j2的依赖-->
    <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version>
    </dependency>
    <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.19.0</version>
    </dependency>
    
  • resources下配置log4j2.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration status="OFF"><properties><!-- 日志打印级别 --><property name="LOG_LEVEL">INFO</property><!-- APP名称 --><property name="APP_NAME" value="framework-project"/><!-- 日志文件存储路径 --><property name="LOG_HOME">./logs/</property><!-- 存储天数 --><property name="LOG_MAX_HISTORY" value="60d"/><!-- 单个日志文件最大值, 单位 = KB, MB, GB --><property name="LOG_MAX_FILE_SIZE" value="10 MB"/><!-- 每天每个日志级别产生的文件最大数量 --><property name="LOG_TOTAL_NUMBER_DAILY" value="10"/><!-- 压缩文件的类型,支持zip和gz,建议Linux用gz,Windows用zip --><property name="ARCHIVE_FILE_SUFFIX" value="zip"/><!-- 日志文件名 --><property name="LOG_FILE_NAME" value="${LOG_HOME}"/><property name="FILE_NAME_PATTERN" value="${LOG_HOME}%d{yyyy-MM-dd}"/><!--格式化输出:%date{yyyy-MM-dd HH:mm:ss.SSS}: 简写为%d 日期 2023-08-12 15:04:30,123%thread: %t 线程名, main%-5level:%p 日志级别,从左往右至少显示5个字符宽度,不足补空格 INFO%msg:%m 日志消息 info msg%n: 换行符{cyan}: 蓝绿色(青色)%logger{36}: %c 表示 Logger 名字最长36个字符%C: 类路径 com.qq.demolog4j2.TestLog4j2%M: 方法名 main%F: 类名 TestLog4j2.java%L: 行号 12%l: 日志位置, 相当于 %C.%M(%F.%L)  com.qq.demolog4j2.TestLog4j2.main(TestLog4j2.java:16)--><!-- %d: 日期%-5level: 日志级别,显示时占5个字符不足[%t]: 线程名%c{1.}: 显示调用者,只显示包名最后一截及方法名,前面的只取首字母.%M(代码行号%L):%msg%n": 需要打印的日志信息,换行:INFO>[MsgToMP:99]Bright: 加粗 --><!--日志输出格式-控制台彩色打印--><property name="ENCODER_PATTERN_CONSOLE">%blue{%d{yyyy-MM-dd HH:mm:ss.SSS}} | %highlight{%-5level}{ERROR=Bright RED, WARN=Bright Yellow, INFO=Bright Green, DEBUG=Bright Cyan, TRACE=Bright White} | %yellow{%t} | %cyan{%c{1.}}  : %white{%msg%n}</property><!--日志输出格式-文件--><property name="ENCODER_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS}  %-5level %5pid --- [%15.15t] %c{1.} [%L] : %m%n</property><!--日志输出格式-控制台彩色打印--><property name="DEFAULT_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight{%-5level} %style{%5pid}{bright,magenta} --- [%15.15t] %cyan{%c{1.} [%L]} : %m%n</property></properties><Appenders><!-- 控制台的输出配置 --><Console name="Console" target="SYSTEM_OUT"><!--输出日志的格式--><PatternLayout pattern="${DEFAULT_PATTERN}" /></Console><!-- 打印出所有的info及以下级别的信息,每次大小超过size进行压缩,作为存档--><RollingFile name="RollingFileAll" fileName="${LOG_FILE_NAME}/${date:yyyy-MM-dd}/info.log" filePattern="${FILE_NAME_PATTERN}/info.log"><!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)--><ThresholdFilter level="${LOG_LEVEL}" onMatch="ACCEPT" onMismatch="DENY" /><!--输出日志的格式--><PatternLayout pattern="${ENCODER_PATTERN}" /><Policies><!-- 归档每天的文件 --><TimeBasedTriggeringPolicy /><!-- 限制单个文件大小 --><SizeBasedTriggeringPolicy size="${LOG_MAX_FILE_SIZE}" /></Policies><!-- 限制每天文件个数 --><DefaultRolloverStrategy compressionLevel="9" max="${LOG_TOTAL_NUMBER_DAILY}"><Delete basePath="${LOG_HOME}" maxDepth="1"><IfFileName glob=".info.*.log" /><IfLastModified age="${LOG_MAX_HISTORY}" /></Delete></DefaultRolloverStrategy></RollingFile><RollingFile name="RollingFileDebug"fileName="${LOG_FILE_NAME}/${date:yyyy-MM-dd}/debug.log"filePattern="${FILE_NAME_PATTERN}/debug.log"><Filters><ThresholdFilter level="DEBUG" /><ThresholdFilter level="INFO" onMatch="DENY"onMismatch="NEUTRAL" /></Filters><PatternLayout pattern="${ENCODER_PATTERN}" /><Policies><!-- 归档每天的文件 --><TimeBasedTriggeringPolicy /><!-- 限制单个文件大小 --><SizeBasedTriggeringPolicy size="${LOG_MAX_FILE_SIZE}" /></Policies><!-- 限制每天文件个数 --><DefaultRolloverStrategy compressionLevel="9"max="${LOG_TOTAL_NUMBER_DAILY}"><Delete basePath="${LOG_HOME}" maxDepth="1"><IfFileName glob="*.debug.*.log" /><IfLastModified age="${LOG_MAX_HISTORY}" /></Delete></DefaultRolloverStrategy></RollingFile><RollingFile name="RollingFileWarn" fileName="${LOG_FILE_NAME}/${date:yyyy-MM-dd}/warn.log"filePattern="${FILE_NAME_PATTERN}.warn.log"><Filters><ThresholdFilter level="WARN" /><ThresholdFilter level="ERROR" onMatch="DENY"onMismatch="NEUTRAL" /></Filters><PatternLayout pattern="${ENCODER_PATTERN}" /><Policies><!-- 归档每天的文件 --><TimeBasedTriggeringPolicy /><!-- 限制单个文件大小 --><SizeBasedTriggeringPolicy size="${LOG_MAX_FILE_SIZE}" /></Policies><!-- 限制每天文件个数 --><DefaultRolloverStrategy compressionLevel="9"max="${LOG_TOTAL_NUMBER_DAILY}"><Delete basePath="${LOG_HOME}" maxDepth="1"><IfFileName glob="*.warn.*.log" /><IfLastModified age="${LOG_MAX_HISTORY}" /></Delete></DefaultRolloverStrategy></RollingFile><RollingFile name="RollingFileError"fileName="${LOG_FILE_NAME}/${date:yyyy-MM-dd}/error.log"filePattern="${FILE_NAME_PATTERN}.error.log"><Filters><ThresholdFilter level="ERROR" /></Filters><PatternLayout pattern="${ENCODER_PATTERN}" /><Policies><TimeBasedTriggeringPolicy /><SizeBasedTriggeringPolicy size="${LOG_MAX_FILE_SIZE}" /></Policies><DefaultRolloverStrategy compressionLevel="9"   max="${LOG_TOTAL_NUMBER_DAILY}"><Delete basePath="${LOG_HOME}" maxDepth="1"><IfFileName glob="*.error.*.log" /><IfLastModified age="${LOG_MAX_HISTORY}" /></Delete></DefaultRolloverStrategy></RollingFile></Appenders><!--只有定义了logger并引入以上Appenders,Appender才会生效--><Loggers><!-- 将业务dao接口所在的包填写进去,并用在控制台和文件中输出 --><logger name="com.xxxx.lln.mapper" level="TRACE" additivity="false"><AppenderRef ref="Console" /></logger><root level="${LOG_LEVEL}"><appender-ref ref="Console"/><appender-ref ref="RollingFileAll"/><appender-ref ref="RollingFileDebug"/><appender-ref ref="RollingFileWarn"/><appender-ref ref="RollingFileError"/></root></Loggers>
    </configuration>
    

4.2 SQL语句传参形式

  • ${}形式
    ${}形式传参,底层Mybatis做的是字符串拼接操作。
    在这里插入图片描述

    通常不会采用${}的方式传值。一个特定的适用场景是:通过Java程序动态生成数据库表,表名部分需要Java程序通过参数传入;而JDBC对于表名部分是不能使用问号占位符的,此时只能使用 ${}。

    结论:实际开发中,能用#{}实现的,肯定不用${}。

    特殊情况: #{}只能替换值,但是有时候动态的不是值,是表名,列名或者关键字,需要使用${}拼接。

  • #{}形式
    Mybatis会将SQL语句中的#{}转换为问号占位符。

    在这里插入图片描述

4.3 MapperXML模版文件

在这里插入图片描述

4.4 SqlSessionUtil工具类

  • 提取工具类

    package com.xxxx.lln.utils;import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
    import java.io.InputStream;public class SqlSessionUtil {public static SqlSession getSqlSession(){//创建sql的会话对象SqlSessionSqlSession sqlSession = null;try {//获取核心配置文件的输入流InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");//获取SqlSessionFactoryBuilder对象SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//获取SqlSessionFactory对象SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);//配置sql的会话对象SqlSession(会自动提交事务),是MyBatis提供的操作数据库的对象sqlSession = sqlSessionFactory.openSession(true);} catch (IOException e) {e.printStackTrace();}return sqlSession;}}
    
  • mapper的接口

    /*** 根据用户id删除用户信息* @param id* @return*/
    int deleteUserById(int id);
    
  • xml文件的sql

        <!--根据用户id删除用户信息--><delete id="deleteUserById">deletefrom t_userwhere id = #{id}</delete>
    
  • 使用工具类进行删除

    /*** 测试删除用户信息*/
    @Test
    public void testDeleteUserById(){SqlSession sqlSession = SqlSessionUtil.getSqlSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);int num = userMapper.deleteUserById(6);System.out.println(num);sqlSession.close();
    }
    

4.5 数据输入

4.5.1 Mybatis总体机制概括

在这里插入图片描述

4.5.2 概念说明

这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。

  • 简单类型:只包含一个值的数据类型
    • 基本数据类型:int、byte、short、double、……
    • 基本数据类型的包装类型:Integer、Character、Double、……
    • 字符串类型:String
  • 复杂类型:包含多个值的数据类型
    • 实体类类型:Employee、Department、……
    • 集合类型:List、Set、Map、……
    • 数组类型:int[]、String[]、……
    • 复合类型:List、实体类中包含集合……

4.5.3 单个字面量类型的参数

若mapper接口中的方法参数为单个的字面量类型 此时可以使用$ { }和 # { }以任意的名称获取参数的值,注意${}需要手动加单引号

但单个字面量其实目前跟参数名字没有关系,但是不能是数值。
在这里插入图片描述

4.5.3 多个字面量类型的参数

若mapper接口中的方法参数为多个时,MyBatis会自动将这些参数放在一个map集合中,以arg0,arg1…为键,以参数为值;以 param1,param2…为键,以参数为值;因此只需要通过${}和#{}访问map集合的键就可以获取相对应的值。

  • 多个字面量正常按参数名字是取不到的
    在这里插入图片描述

  • 通过arg0,arg1或param1,param2取值
    在这里插入图片描述

4.5.5 map集合类型的参数

若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中 只需要通过 $ {}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号

在这里插入图片描述

4.5.6 实体类类型的参数

若mapper接口中的方法参数为实体类对象时
此时可以使用$ {}和#{},通过访问实体类对象中的属性名获取属性值,注意${}需要手动加单引号
只跟get/set方法有关
在这里插入图片描述

在这里插入图片描述

4.5.7 使用@Param标识参数

命名参数
可以通过@Param注解标识mapper接口中的方法参数
此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以 param1,param2…为键,以参数为值;只需要通过${}和#{}访问map集合的键就可以获取相对应的值, 注意 ${}需要手动加单引号

在这里插入图片描述

4.6 数据输出

4.6.1 输出概述

数据输出总体上有两种形式:

  • 增删改操作返回的受影响行数:直接使用 int 或 long 类型接收即可
  • 查询操作的查询结果

我们需要做的是,指定查询的输出数据类型即可!

并且插入场景下,实现主键数据回显示!

4.6.2 单个简单类型

Mybatis 内部给常用的数据类型设定了很多别名。 以 int 类型为例,可以写的名称有:int、integer、Integer、java.lang.Integer、Int、INT、INTEGER 等等。

在这里插入图片描述

4.6.3 返回实体类对象

在这里插入图片描述

4.6.4 返回单条map类型

在这里插入图片描述

4.6.5 返回多条map类型

在这里插入图片描述

4.6.6 返回list集合类型

在这里插入图片描述

在这里插入图片描述

4.6.7 返回自增主键值

  • 自增长类型主键
    Mybatis是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回。在这里插入图片描述

  • 非自增长类型主键
    而对于不支持自增型主键的数据库(例如 Oracle)或者字符串类型主键,则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用!

    使用 selectKey 帮助插入UUID作为字符串类型主键示例:

    <insert id="insertUser" parameterType="User"><selectKey keyProperty="id" resultType="java.lang.String"order="BEFORE">SELECT UUID() as id</selectKey>INSERT INTO user (id, username, password) VALUES (#{id},#{username},#{password})
    </insert>
    

    在上例中,我们定义了一个 insertUser 的插入语句来将 User 对象插入到 user 表中。我们使用 selectKey 来查询 UUID 并设置到 id 字段中。

    通过 keyProperty 属性来指定查询到的 UUID 赋值给对象中的 id 属性,而 resultType 属性指定了 UUID 的类型为 java.lang.String

    需要注意的是,我们将 selectKey 放在了插入语句的前面,这是因为 MySQL 在 insert 语句中只支持一个 select 子句,而 selectKey 中查询 UUID 的语句就是一个 select 子句,因此我们需要将其放在前面。

    最后,在将 User 对象插入到 user 表中时,我们直接使用对象中的 id 属性来插入主键值。

    使用这种方式,我们可以方便地插入 UUID 作为字符串类型主键。当然,还有其他插入方式可以使用,如使用Java代码生成UUID并在类中显式设置值等。需要根据具体应用场景和需求选择合适的插入方式。

4.7 增删改查

  • mapper接口

     //添加用户信息int insertUser();//删除用户信息void deleteUser();//修改用户信息void updateUser();//通过id查询一个实体类对象User getUserById();//查询实体类集合List<User> getUserList();
    
  • MapperXML

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.xxxx.lln.mapper.UserMapper"><!--mapper接口和映射文件要保证两个一致:1.mapper接口的全类名和映射文件的namespace一致2.mapper接口中的方法的方法名要和映射文件中的sql语句的id保持一致--><!--添加用户信息--><insert id="insertUser">insert into t_user(username,password,age,gender,email) values(null,'张三','123',23,'男',"123@163.com")</insert><!--删除用户信息--><delete id="deleteUser">delete from t_user where id = 2</delete><!--修改用户信息--><update id="updateUser">update t_user set username='ybc',password='123' where id = 3</update><!--resultType:自动映射,用于属性名和表中字段名一致的情况resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况--><!--通过id查询一个实体类对象--><select id="getUserById" resultType="com.xxxx.lln.pojo.User">select * from t_user where id = 3</select><!--查询实体类集合--><select id="getUserList" resultType="com.xxxx.lln.pojo.User">select * from t_user</select></mapper>

4.8 自定义映射resultMap

需要解决数据表字段名与实体类属性名对应不上时的情况:
在这里插入图片描述

4.8.0 驼峰转换

全局配置

    <settings><!-- 使用Log4j2作为日志实现! --><setting name="logImpl" value="LOG4J2"/><!--将表中字段的下划线自动转换为驼峰--><setting name="mapUnderscoreToCamelCase" value="true"/></settings>

在这里插入图片描述

4.8.1 起别名

在这里插入图片描述

4.8.2 resultMap

使用resultMap标签定义对应关系,再在后面的SQL语句中引用这个对应关系
在这里插入图片描述

4.9 模糊查询

<!--select * from t_user where username like "%"#{name}"%"-->
<!--select * from t_user where username like '%${name}%'-->
select * from t_user where username like concat('%', #{name}, '%')

在这里插入图片描述

4.10 批量删除

在这里插入图片描述
在这里插入图片描述

4.11 多表映射

4.11.1 多对一映射

假设用户对象里面包含员工对象

public class User {private Integer id;private String username;private String password;private Integer age;private String gender;private String email;private Emp emp;
}

级联方式处理映射关系只用resultMap
在这里插入图片描述

使用association处理映射关系

在这里插入图片描述

4.11.2 一对多映射

懒得动表结构了,直接用之前的笔记
在这里插入图片描述

4.12 分步查询

在这里插入图片描述

  • 开启局部延迟加载

    • 延迟加载的核心原理是:用的时候再执行查询语句,不用的时候不查询

    • 作用:提高性能,尽可能的不查,或者尽可能的少查,来提高效率

    • 在mybatis当中怎么开启延迟加载呢?

      • association标签之哦给你添加fetchType=“lazy”
      • 注意,默认情况下是没有开启延迟加载的,需要设置,fetchType=“lazy”
      • 这种在association标签中配置fetchType=“lazy” 是局部的设置,只对当前association关联的sql语句起作用
      • fetchType=“eager” 表示立即加载
    • 实际的开发中的模式:

      • 把全局的延迟加载打开。
      • 如果某一步不需要使用延迟加载,请设置fetchType=“eager” 即可

    在这里插入图片描述

  • 开启全局延迟加载

        <settings><!-- 使用Log4j2作为日志实现! --><setting name="logImpl" value="LOG4J2"/><!--将表中字段的下划线自动转换为驼峰--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/></settings>
    

    在这里插入图片描述

4.13 实体类别名

差点忘了…核心配置文件里,可以设置类的别名,resultType的时候,就不用每次写类的全类名了。

    <typeAliases><!--typeAlias:设置某个具体的类型的别名属性: type:需要设置别名的类型的全类名alias:设置此类型的别名,若不设置此属性,该类型拥有默认的别名,即类名且不区分大小写若设置此属性,此时该类型的别名只能使用alias所设置的值--><!--<typeAlias type="com.atguigu.mybatis.bean.User"></typeAlias>--><!--<typeAlias type="com.atguigu.mybatis.bean.User" alias="abc"> </typeAlias>--><!--以包为单位,设置改包下所有的类型都拥有默认的别名,即类名且不区分大小写--><package name="com.xxxx.lln.pojo"/></typeAliases>

4.14 使用注解增删改查

mybatis不建议,我也不想学,用到了百度吧。。。

5.动态SQL

Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。

if

if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行。

    <!--List<Emp> getEmpListByMoreTJ(Emp emp);--><select id="getEmpListByMoreTJ" resultType="Emp">select * from t_emp where 1=1<if test="ename != '' and ename != null">and ename = #{ename}</if><if test="age != '' and age != null">and age = #{age}</if><if test="sex != '' and sex != null">and sex = #{sex}</if></select>

where

    <select id="getEmpListByMoreTJ2" resultType="Emp">select * from t_emp<where><if test="ename != '' and ename != null">ename = #{ename}</if><if test="age != '' and age != null">and age = #{age}</if><if test="sex != '' and sex != null">and sex = #{sex}</if></where></select>
  • where和if一般结合使用:
    • 若where标签中的if条件都不满足,则where标签没有任何功能,即不会添加where关键字
    • 若where标签中的if条件满足,则where标签会自动添加where关键字,并将条件最前方多余的 and去掉
    • 注意:where标签不能去掉条件最后多余的and

set

<!-- void updateEmployeeDynamic(Employee employee) -->
<update id="updateEmployeeDynamic">update t_emp<!-- set emp_name=#{empName},emp_salary=#{empSalary} --><!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 --><set><if test="empName != null">emp_name=#{empName},</if><if test="empSalary &lt; 3000">emp_salary=#{empSalary},</if></set>where emp_id=#{empId}<!--第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?第二种情况:部分条件满足 SET emp_salary=?第三种情况:所有条件都不满足 update t_emp where emp_id=?没有set子句的update语句会导致SQL语法错误-->
</update>

trim

使用trim标签控制条件部分两端是否包含某些字符

  • prefix属性:指定要动态添加的前缀
  • suffix属性:指定要动态添加的后缀
  • prefixOverrides属性:指定要动态去掉的前缀,使用“|”分隔有可能的多个值
  • suffixOverrides属性:指定要动态去掉的后缀,使用“|”分隔有可能的多个值
<!-- List<Employee> selectEmployeeByConditionByTrim(Employee employee) -->
<select id="selectEmployeeByConditionByTrim" resultType="com.atguigu.mybatis.entity.Employee">select emp_id,emp_name,emp_age,emp_salary,emp_genderfrom t_emp<!-- prefix属性指定要动态添加的前缀 --><!-- suffix属性指定要动态添加的后缀 --><!-- prefixOverrides属性指定要动态去掉的前缀,使用“|”分隔有可能的多个值 --><!-- suffixOverrides属性指定要动态去掉的后缀,使用“|”分隔有可能的多个值 --><!-- 当前例子用where标签实现更简洁,但是trim标签更灵活,可以用在任何有需要的地方 --><trim prefix="where" suffixOverrides="and|or"><if test="empName != null">emp_name=#{empName} and</if><if test="empSalary &gt; 3000">emp_salary>#{empSalary} and</if><if test="empAge &lt;= 20">emp_age=#{empAge} or</if><if test="empGender=='male'">emp_gender=#{empGender}</if></trim>
</select>

choose、when、otherwise

choose、when、otherwise相当于if…else if…else

    <!--List<Emp> getEmpListByChoose(Emp emp);--><select id="getEmpListByChoose" resultType="Emp">select * from t_emp<where><choose><when test="ename != '' and ename != null">ename = #{ename}</when><when test="age != '' and age != null">age = #{age}</when><when test="sex != '' and sex != null">sex = #{sex}</when><when test="email != '' and email != null">email = #{email}</when><otherwise>1=1</otherwise></choose></where></select>

foreach

    <!--int insertMoreEmp(List<Emp> emps);--><insert id="insertMoreEmp">insert into t_emp values<foreach collection="emps" item="emp" separator=",">(null,#{emp.ename},#{emp.age},#{emp.sex},#{emp.email},null)</foreach></insert><!--int deleteMoreByArray(int[] eids);--><delete id="deleteMoreByArray">delete from t_emp where<foreach collection="eids" item="eid" separator="or">eid = #{eid}</foreach></delete> <!--int deleteMoreByArray(int[] eids);--><delete id="deleteMoreByArray">delete from t_emp where eid in<foreach collection="eids" item="eid" separator="," open="(" close=")">#{eid}</foreach></delete>

sql片段

抽取重复的SQL片段

<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="empColumns">eid,ename,age,sex,did
</sql>

引用已抽取的SQL片段

<!-- 使用include标签引用声明的SQL片段 -->
<select id="xxx" resultMap="deptEmpMap">select <include refid="empColumns"></include> from t_emp
</select>

6. MyBatis的缓存

一级缓存

默认开启

一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问

使一级缓存失效的四种情况:

不同的SqlSession对应不同的一级缓存
同一个SqlSession但是查询条件不同
同一个SqlSession两次查询期间执行了任何一次增删改操作
同一个SqlSession两次查询期间手动清空了缓存 (sqlsession.clearCache())

二级缓存

二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

二级缓存开启的条件:

a>在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置

b>在映射文件中设置标签< cache />

c>二级缓存必须在SqlSession关闭或提交之后有效

d>查询的数据所转换的实体类类型必须实现序列化的接口

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

二级缓存的相关配置

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

eviction属性:缓存回收策略 默认的是 LRU。
LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

flushInterval属性:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

size属性:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出

readOnly属性:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

MyBatis缓存查询的顺序

先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
如果二级缓存没有命中,再查询一级缓存
如果一级缓存也没有命中,则查询数据库
SqlSession关闭之后,一级缓存中的数据会写入二级缓存

整合第三方缓存EHCache

a>添加依赖

<!-- Mybatis EHCache整合包 --> 
<dependency>    <groupId>org.mybatis.caches</groupId>    <artifactId>mybatis-ehcache</artifactId>    <version>1.2.1</version> 
</dependency> 
<!-- slf4j日志门面的一个具体实现 -->
<dependency>    <groupId>ch.qos.logback</groupId>    <artifactId>logback-classic</artifactId>    <version>1.2.3</version> 
</dependency>

b>各jar包功能
在这里插入图片描述

c>创建EHCache的配置文件ehcache.xml

<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <!-- 磁盘保存路径 --> <diskStore path="D:\atguigu\ehcache"/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> 
</ehcache>

d>设置二级缓存的类型

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

e>加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。
创建logback的配置文件logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true"><!-- 指定日志输出的位置 --><appender name="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 日志输出的格式 --><!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 --><pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern></encoder></appender><!--设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR --><!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 --><root level="DEBUG"><!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender --><appender-ref ref="STDOUT"/></root><!-- 根据特殊需求指定局部日志级别 --><logger name="com.atguigu.crowd.mapper" level="DEBUG"/></configuration>

f>EHCache配置文件说明

在这里插入图片描述

7. MyBatis的逆向工程

  • 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程 的。
  • 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
    • Java实体类
    • Mapper接口
    • Mapper映射文件

a>添加依赖和插件

    <!-- 依赖MyBatis核心包 --><dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency></dependencies><!-- 控制Maven在构建过程中相关配置 --><build><!-- 构建过程中用到的插件 --><plugins><!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.0</version><!-- 插件的依赖 --><dependencies><!-- 逆向工程的核心依赖 --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><!-- 数据库连接池 --><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2</version></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency></dependencies></plugin></plugins></build>

b>创建MyBatis的核心配置文件

c>创建逆向工程的配置文件
文件名必须是:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration><!--targetRuntime: 执行生成的逆向工程的版本MyBatis3Simple: 生成基本的CRUD(清新简洁版)MyBatis3: 生成带条件的CRUD(奢华尊享版) --><context id="DB2Tables" targetRuntime="MyBatis3Simple"><!-- 数据库的连接信息 --><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/mybatis"userId="root"password="123456"></jdbcConnection><!-- javaBean的生成策略--><javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /><property name="trimStrings" value="true" /></javaModelGenerator><!-- SQL映射文件的生成策略 --><sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"targetProject=".\src\main\resources"><property name="enableSubPackages" value="true" /></sqlMapGenerator><!-- Mapper接口的生成策略 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper"targetProject=".\src\main\java"><property name="enableSubPackages" value="true" /></javaClientGenerator><!-- 逆向分析的表 --><!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName --><!-- domainObjectName属性指定生成出来的实体类的类名 --><table tableName="t_emp" domainObjectName="Emp"/><table tableName="t_dept" domainObjectName="Dept"/></context></generatorConfiguration>

d>执行MBG插件的generate目标

在这里插入图片描述

8. MyBatis X

9. 分页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/882346.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一次性入门三款分布式定时任务调度框架:Quartz、ElasticJob3.0、xxl-job

分布式定时任务调度框架&#xff08;文末有源码&#xff09; 前言1、Quartz1.1 数据库1.2 maven依赖1.3 代码实现1.3.1 创建一个job1.3.1 为job设置trigger 1.4 配置文件1.5 启动、测试1.1 单机1.2 集群 2、ElasticJob2.1 下载zk2.2 新建三个类型的作业2.3 配置文件2.4 启动项目…

Nature?拿捏~

之前有分享过很多《Nature》论文插图&#xff0c;想着为大家提供更加广阔的作图思路。 但有人说&#xff0c;这些图好看是好看&#xff0c;可惜也就大佬们能画&#xff0c;跟我这个小卡拉米没啥关系。 此言差矣。 如果我说&#xff0c;Matlab就能画呢&#xff1f; 比如&…

AIGC助力小学生编程梦:C++入门不再难!

文章目录 一、AIGC时代下的编程教育新趋势二、小学生C入门趣味编程的意义三、小学生C入门趣味编程的实践策略四、面临的挑战与应对策略五、AIGC技术在小学生C编程中的应用与前景《小学生C趣味编程从入门到精通》编辑推荐内容简介作者简介目录 随着人工智能生成内容&#xff08;…

C++初阶——入门

目录 1、C发展历史 2、C版本更新 3、C参考文档 4、C书籍推荐 5、C的程序 6、命名空间 6.1 namespace的作用 6.2 namespace的定义 6.3 namespace的使用 7、C输入&输出 8、缺省参数 9、函数重载 10、引用 10.1 引用的概念和定义 10.2 引用的特性 10.3 引用的使…

10月9日

肯定是对x求导 刨根问底求导数解析式 区间再现均值不等式 没利用B-E 0 同解方程组 趋于0的时候&#xff0c;看1次项 没有考虑x -1的情况 还要加一&#xff0c;非齐次解

MongoDB如何查找数据以及条件运算符使用的详细说明

以下是关于MongoDB如何查找数据以及条件运算符使用的详细说明&#xff1a; 查找数据的基本方法 在MongoDB中&#xff0c;使用db.collection.find()方法来查找集合中的数据。如果不添加任何条件&#xff0c;直接使用db.collection.find()会返回集合中的所有文档。例如&#xf…

生成两张找不同的图片,仅有一处差异,并且这个差异要不明显且复杂,使得寻找难度增加。

生成两张找不同的图片&#xff0c;仅有一处差异&#xff0c;并且这个差异要不明显且复杂&#xff0c;使得寻找难度增加。 为此&#xff0c;我们需要调整之前的代码&#xff0c;使得差异更为隐蔽。之前的代码中&#xff0c;我们直接在第二张图片中添加了一个红色多边形&#xf…

AdaTAD(CVPR 2024)视频动作检测方法详解

前言 论文&#xff1a;End-to-End Temporal Action Detection with 1B Parameters Across 1000 Frames 代码&#xff1a;AdaTAD 从论文标题可以看出&#xff0c;AdaTAD 可以在 1B 参数且输入视频在 1000 帧的情况下实现端到端的训练&#xff0c;核心创新点是引入 Temporal-Inf…

如何快速学会盲打

今天就来给大家分享一下如何快速学会盲打 盲打的基本方法和步骤 手指放置&#xff1a;将双手放在键盘上&#xff0c;左手食指放在F键上&#xff0c;右手食指放在J键上&#xff0c;其他手指分别放在相邻的键位上。熟悉键盘布局&#xff1a;学习26个字母的位置&#xff0c;以及…

Python Q-learning 算法详解与应用案例

目录 Python Q-learning 算法详解与应用案例引言一、Q-learning 的基本原理1.1 强化学习基础1.2 Q值及其更新1.3 Q-learning 的特性 二、Python 中 Q-learning 的面向对象实现2.1 QTable 类的实现2.2 Environment 类的实现2.3 Agent 类的实现 三、案例分析3.1 简单环境中的 Q-l…

STM32_实验4_控制蜂鸣器

1.设置 PB2 引脚&#xff0c;生成代码。 2.打开蜂鸣器 // 循环反复HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET); // 开启蜂鸣器printf("beep on\n");HAL_Delay(500); // 等待响500msHAL_GPIO_WritePin(…

解锁C++多态的魔力:灵活与高效的编码艺术(下)

文章目录 前言&#x1f3b1;四、多态的原理&#x1f52e;4.1 虚函数表&#xff08;vtable&#xff09;&#x1f52e;4.2 派生类对象中的虚函数表4.2.1 编写程序去访问虚函数表4.2.2 虚表存储位置的验证 &#x1f3b1;五、 多态的静态绑定和动态绑定&#x1f52e;5.1 静态绑定&a…

【Linux】深入 Linux 进程等待机制:阻塞与非阻塞的奥秘

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1. 为什么需要进行进程等待2. 进程等待的方法2…

spring底层原理

本文参考黑马程序员的spring底层讲解&#xff0c;想要更详细的可以去看视频。 另外文章会每日更新&#xff0c;大概持续1个月&#xff01;&#xff01;&#xff01;每天更新一讲 这部分比较抽象&#xff0c;要经常复习&#xff01;&#xff01;&#xff01; 一、BeanFactory与A…

【JPCS独立出版 | 福州大学主办 | 有确定的ISSN号】第三届可再生能源与电气科技国际学术会议(ICREET 2024)

第三届可再生能源与电气科技国际学术会议&#xff08;ICREET 2024&#xff09; 2024 3rd International Conference on Renewable Energy and Electrical Technology ICREET 2024已成功申请JPCS - Journal of Physics: Conference Series (ISSN:1742-6596) 独立出版&#xf…

【算法日记】力扣239 滑动窗口最大值

题目描述 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a;nums [1,3,-1,-3,5,3,6,…

引领智慧文旅新纪元,开启未来旅游新境界

融合创新科技&#xff0c;重塑旅游体验&#xff0c;智慧文旅项目定义旅游新未来 在全球化的浪潮中&#xff0c;旅游已成为连接世界的重要纽带。智慧文旅项目&#xff0c;不仅仅是一次技术的革新&#xff0c;更是对旅游行业未来发展的一次深刻思考。信鸥科技通过运用云计算、大数…

Vue3动态组件原来是这样

什么是Vue3动态组件 在Vue3中&#xff0c;动态组件简单来说就是根据不同的条件进行不同组件的渲染&#xff0c;可以联想一下在前端中常用到的动态样式 基本使用 在Vue3中&#xff0c;动态组件的使用也是非常简单的&#xff0c;只需要使用<component>标签&#xff0c;并…

WPFDeveloper正式版发布

WPFDeveloper WPFDeveloper一个基于WPF自定义高级控件的WPF开发人员UI库&#xff0c;它提供了众多的自定义控件。 该项目的创建者和主要维护者是现役微软MVP 闫驚鏵: https://github.com/yanjinhuagood 该项目还有众多的维护者&#xff0c;详情可以访问github上的README&…

Redis 高可用:从主从到集群的全面解析

目录 一、主从复制 (基础)1. 同步复制a. 全量数据同步b. 增量数据同步c. 可能带来的数据不一致 2. 环形缓冲区a. 动态调整槽位 3. runid4. 主从复制解决单点故障a. 单点故障b. 可用性问题 5. 注意事项a. Replica 主动向 Master 建立连接b. Replica 主动向 Master 拉取数据 二、…