文章目录
- 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 configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--引入properties文件,此时就可以${属性名}的方式访问属性值--> <properties resource="jdbc.properties"></properties> <!--设置连接数据库的环境--> <!-- environments表示配置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 mapper PUBLIC "-//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, email from t_user where id = #{id} </select> </mapper>
-
定义EmpMapper接口
package com.xxxx.lln.mapper; public interface EmpMapper { }
-
配置EmpMapperXML文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.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 {
@Test
public 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程序和数据库之间的会话。
- 代表Java程序和数据库之间的会话。
- HttpSession:工作在Web服务器上,属于表述层。
3. 核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引入properties文件,此时就可以${属性名}的方式访问属性值-->
<properties resource="jdbc.properties"></properties>
<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的会话对象SqlSession SqlSession 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"> delete from t_user where 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 mapper PUBLIC "-//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 < 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_gender
from 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 > 3000">
emp_salary>#{empSalary} and
</if>
<if test="empAge <= 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 generatorConfiguration
PUBLIC "-//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目标