MyBatis-Plus笔记
主要记录以下内容:
- 整合Mybatis-Plus
- 通用CURD
- Mybatis-Plus的配置
- 条件构造器
MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发,提高效率而生
一、简单认识Mybatis-Plus
特性
- 无侵入: 只做增强不做改变,引入它不会对现有的工程产生影响。
- 损耗小: 启动就会自动注入基本的CURD,性能基本无损耗,直接面向对象操作
- 强大的CRUD操作: 内置通用的Mapper、通用的Service、仅仅通过少量配置即可实现单表大部分的CRUD操作
- 支持Lambda形式调用: 通过Lambda表达式,方便编写各类查询条件,无需担心字段写错
- 支持多种数据库
- 支持主键自动生成: 支持多达四种主键策略(内含分布式唯一ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持XML热加载: Mapper对应的XML热加载,对于简单的CRUD操作,甚至可以无XML启动
- 支持ActiveRecord模式: 支持ActiveRecord形式调用,实体类只需要继承Model类即可进行强大的CRUD操作
- 支持自定义全局通用操作: 支持全局通用方法注入(write once,use anyway)
- 支持关键词自动转义: 支持数据库关键词(order、key…)自动转义,还可自定义关键词
- 内置代码生成器: 采用代码或者Maven插件可快速生成Mapper、Model、Service、Controller层代码、支持模板引擎,更有超多自定义配置
- 内置分页插件: 基于MyBatis物理分页,开发者无需担心具体操作,配置好插件后,写分页等同于普通List查询
- 内置性能分析插件: 可输出SQL语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件: 提供全表delete、update操作只能分析阻断,也可自定义拦截规则,预防误操作
架构
对于Mybatis整合MP常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+Mp、SpringBoot+MyBatis+MP
二、使用Mybatis实现查询User
第一步:编写mybatis-config.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
第二步:编写User实体对象【使用了lombok进行了简化bean操作】
package cn.itcast.mp.simple.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data //简化了getter/setter的书写
@NoArgsConstructor //简化了无参构造的书写
@AllArgsConstructor //简化了全参构造的书写
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
第三步:编写UserMapper接口
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> findAll();
}
第四步:编写UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mp.simple.mapper.UserMapper">
<select id="findAll" resultType="cn.itcast.mp.simple.pojo.User">
select * from tb_user
</select>
</mapper>
第五步:编写测试文件
public class TestMybatis {
@Test
public void testFindAll() throws Exception{
String config = "mybatis-config.xml";
InputStream resourceAsStream = Resources.getResourceAsStream(config);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//测试查询
List<User> users = userMapper.findAll();
for(User user : users){
System.out.println(user);
}
}
}
三、使用Mybatis + MP 实现查询User
第一步:将UserMapper继承BaseMapper,将拥有BaseMapper中的所有方法
package cn.itcast.mp.simple.mapper;
import cn.itcast.mp.simple.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
import java.util.stream.BaseStream;
public interface UserMapper extends BaseMapper<User> {
public List<User> findAll();
}
第二步:使用MP中的MyBatisSqlSessionFactoryBuilder进程构建
public class TestMybatisPlus {
@Test
public void testFindAll() throws Exception{
String config = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
//这里使用的是MyBatisPlus中的MyBatisSqlSessionFactorybuilder
SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//测试查询【此处是BaseMapper中的selectList方法(不使用条件null)】
List<User> users = userMapper.selectList(null);
for(User user : users){
System.out.println(user);
}
}
}
运行报错:
解决方法:在User对象中添加@TableName,指定数据库表名
@Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") //添加数据库表名 public class User { private Long id; private String userName; private String password; private String name; private Integer age; private String email; private String gender; }
简单说明:
- 使用了MyBatisSqlSessionFactoryBuilder进行了构建,继承的BaseMapper中的方法就载入到了SqlSession中,所以就可以直接使用相关的方法;
四、Spring + Mybatis + MP
引入了Spring框架,数据源、构建等工作就交给Spring管理
第一步:创建子Module
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<parent>
<groupId>cn.itcast.mp</groupId>
<artifactId>itcast-mybatis-plus</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>itcast-mybatis-plus-spring</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.1.6.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</project>
实现查询User
第一步:编写jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
jdbc.username=root
jdbc.password=123456
第二步:编写applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd>
<!-- 配置文件的扫描器 -->
<context:property-placeholder location="clathspath:*.properties"/>
<!-- 定义数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destory-method="close">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="maxActive" value="10"></property>
<property name="minIdle" value="5"></property>
</bean>
<!-- 使用MP提供的sqlSessionFactory,完成Spring和Mp的整合 -->
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlsessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 扫描Mapper接口,使用依然是Mybatis原生的扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.mp.simple.mapper" />
</beans>
</beans>
第三步:创建User对象以及UserMapper接口
//User实体类书写如下:
@Data //简化了getter/setter的书写
@NoArgsConstructor //简化了无参构造的书写
@AllArgsConstructor //简化了全参构造的书写
@TableName("tb_user")
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
//接口书写如下:
public interface UserMapper extends BaseMapper<User>{}
编写测试文件
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestMybatisSpring{
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList(){
List<User> users = this.userMapper.selectList(null);
for(User user : users) {
System.out.println(user);
}
}
}
五、SpringBoot + Mybatis + MP
使用SpringBoot将进一步的简化MP的整合,需要注意的是,由于使用了SpringBoot需要继承parent,所以需要重新创建工程,而不是创建子Module
1. 创建项目并编写pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.itcast.mp</groupId>
<artifactId>itcast-mp-springboot</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- mybatis-plus的SpringBoot支持 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 编写log4j.properties文件【日志管理】
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n
3. 编写application.properties文件
spring.application.name=itcast-mp-springboot
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
4. 编写实体类POJO + Mapper接口
//User实体类书写如下:
@Data //简化了getter/setter的书写
@NoArgsConstructor //简化了无参构造的书写
@AllArgsConstructor //简化了全参构造的书写
@TableName("tb_user")
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String email;
}
//UserMapper接口如下:
public interface UserMapper extends BaseMapper<User> {
}
5. 编写启动类
package cn.itcast.mp;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("cn.itcast.mp.mapper") //设置Mapper接口的扫描包
@SpringBootApplication //指定为SpringBoot的启动类
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class,args);
}
}
六、通用CRUD
继承BaseMapper可以获取到各种各样的单表操作,如图所示:
1、插入操作
/**
* 插入一条记录
* @param entity实体对象
*/
int insert(T entity); //返回值是受影响的行数
2、@TableField注解
在MyBatisPlus中通过@TableField注解可以指定字段的一些属性,常常解决的问题有两个:
- 对象中属性名和字段名不一致的问题(非驼峰)
- 对象中属性字段在表中不存在的问题
//示例,在数据库中字段email,而实体类字段为mail时,需要注解@TableField指定
public class User{
@TableField(value = "email") //指定数据库中字段名
private String mail;
}
//示例2,数据库字段不存在address而实体类存在多余字段,此时插入会存在问题因此使用注解
public class User{
@TableField(exist = false) //在数据库中不存在
private String address;
}
3、更新操作
- 在MyBatisPlus中更新操作有两种,一种是根据ID更新,另一种是根据条件更新
/**
* 根据ID修改
* @param entity实体对象
*/
int updateById(@Param(Constant.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象(set 条件值,可以为null)
* @param updateWrapper 实体对象封装操作类(可以为null,里面的entity用于生成where语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T>updateWrapper);
操作示例
- 根据用户的ID查询
@Test
public void testUpdateById(){
User user = new User();
user.setId(12);
user.setAge(19);user.setPassword("666666");
int result = this.userMapper.updateById(user);
}
- 根据多条件更新【使用QueryWrapper对象】
@Test
public void testUpdate(){
User user = new User();
user.setAge(19);user.setPassword("666666");
//构造更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name","zhangsan");
//执行更新操作
int result = this.userMapper.update(user,wrapper);
}
- 根据多条件更新【使用UpdateWrapper对象】
@Test
public void testUpdate(){
//构建更新条件以及更新字段
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("age",23).set("password","333444")
.eq("id",6);
//执行更新操作
int result = this.userMapper.update(null,wrapper);
}
4、删除操作
4.0、deleteById
/**
* 根据 ID 删除
* @param id 主键ID
*/
int deleteById(Serializable id);
4.1、deleteByMap
- 方法定义:
/**
* 根据columnMap条件,删除记录
* @param columnMap 表字段 Map对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP)Map<String,Object>columnMap);
示例:
@Test
public void testDeleteByMap(){
Map<String,Object> map = new HashMap<>();
map.put("user_name","zhangsan");
map.put("password","666666");
//根据map删除数据,多条件之间是AND关系
int result = this.userMapper.deleteByMap(map);
}
4.2、delete
- 方法定义:
/**
* 根据 entity 条件,删除记录
* @param wrapper 实体对象封装操作类(可以为null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
示例:
@Test
public void testDelete(){
//根据包装条件做删除,方法一:
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name","wangwu")
.eq("password","123456");
int result = this.userMapper.delete(wrapper);
//方法二【推荐使用】
User user = new User();
user.setPassword("123456");
user.setUserName("wangwu");
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
int result = this.userMapper.delete(wrapper);
}
4.3、deleteBatchlds
- 方法定义
/**
* 删除(根据ID 批量删除)
* @param idList 主键ID列表(不能为null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION)Collection<? extends Serializable>idList);
示例:
@Test
public void testBatchIds(){
//根据ID批量删除数据
int result = this.userMapper.deleteBatchIds(Arrays.asList(10,11,12));
}
5、查询操作
5.0、selectById
- 方法定义
/**
* 根据 ID 查询
* @param id 主键ID
*/
T selectById(Serialzable id);
5.1、selectBatchIds
- 方法定义
/**
* 查询(根据ID 批量查询)
* @param idList 主键ID列表(不能为null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION)Collection<? extends Serialzable>idList);
示例:
@Test
public void testSelectBatchIds(){
//根据ID批量查询数据
List<User> result = this.userMapper.selectBatchIds(Arrays.asList(10,11,12));
for(User user : result){
System.out.println(user);
}
}
5.2、selectOne
- 方法定义
/**
* 根据entity 条件,查询一条记录
* @param querywrapper 实体对象封装操作类,可以为null
*/
T selectOne(@Param(Constants.WRAPPER) wrapper<T>queryWrapper);
示例
@Test
public void testSelectOne(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//查询条件
wrapper.eq("user_name","zhangsan");
// 查询的数据超过一条的时候,会抛出异常
User user = this.userMapper.selectOne(wrapper);
}
5.3、selectCount
- 方法定义
/**
* 根据 wrapper 条件,查询总记录数
* @param queryWrapper 实体对象封装操作类(可以为null)
*/
Interge selectCount(@Param(Constans.WRAPPER)wrapper<T> queryWrapper);
示例:
@Test
public void testSelectCount(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age",20); //条件:年龄大于20岁
Interge res = this.userMapper.selectCount(wrapper);
}
5.4、selectList
- 方法定义
/**
* 根据 entity 条件,查询全部记录
* @param querywrapper 实体对象封装操作类(可以为null)
*/
List<T> selectList(@Param(Constants.WRAPPER) wrapper<T> querywrapper);
示例:
@Test
public void testSelectList(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email","itcast");
List<User> users = this.userMapper.selectList(wrapper);
}
5.5、selectPage
- 方法定义:
/**
* 根据 entity 条件,查询所有记录(并翻页)
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为null)
*/
IPage<T> selectPage(IPage<T>page, @Param(Constants.WRAPPER)wrapper<T>queryWrapper);
MP的分页插件:
- 创建一个Spring的配置类
@Configuration public class MybatisPlusConfig{ @Bean 配置一个分页插件 public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } }
示例:
@Test
public void testSelectPage(){
Page<User> page = new Page<>(2,5);//查询第二页的五条数据
QueryWrapper<User> wrapper = new QueryWrapper<>();
//设置查询条件
wrapper.like("email","itcast");
IPage<User> iPage = this.userMapper.selectPage(page,wrapper);
System.out.println("数据的总页数:",iPage.getPages);
System.out.println("数据的总条数:",iPage.getTotal);
//获取iPage中的所有数据
List<User> records = iPage.getRecords();
}
七、基本配置
- 在MP中有大量的配置,其中一部分是MyBatis原生的配置,另一部分是MP的配置
1、configuration【配置文件】
MyBatis配置文件位置,如果有单独的Mybatis配置,请将路径配置到configuration中。MyBatis的Configuration的具体内容参考官方文档
SpringBoot:
mybatis-plus.config-location = classpath:mybatis-config.xml
SpringMvc:
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>
2、mapperLocations【Mapper映射】
MyBatis Mapper所对应的XML文件位置,如果在Mapper中有自定义的方法(XML中有自定义实现),需要进行该配置,告诉Mapper所对应的XML文件位置
SpringBoot:
mybatis-plus.mapper-locations = classpath*.mybatis/*.xml
SpringMvc:
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="mapperLocations" value="classpath*:mybatis/*.xml" />
</bean>
Maven多模块项目的扫描路径需以
classpath*:
开头(即加载多个jar包下的XML文件)
3、typeAliasesPackage【别名扫描】
MyBatis别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在Mapper对应的XML文件中可以直接使用类名,而不需要使用全限定的类名(即XML中调用的时候不用包含包名)
SpringBoot:
mybatis-plus.type-aliases-package = cn.itcast.mp.pojo
SpringMvc:
<bean id="sqlSessionFactory"
class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
<property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity" />
</bean>
八、进阶配置
1、mapUnderscoreToCamelCase【驼峰映射】
- 类型:
boolean
- 默认值:
true
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名A_COLUMN(下划线命名)到经典Java属性名aColumn(驼峰命名)的类似映射。
注意:
此属性在MyBatis中原默认值为false,在MyBatis-Plus中,此属性也将用于生成最终的SQL的selectbody
如果数据库命名符合规则则无需使用
@TableField
注解指定数据库字段名
SpringBoot:
# 关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false
2、CacheEnabled
- 类型:
boolean
- 默认值:
true
全局的开启或关闭配置文件中所有映射器已经配置的任何缓存,默认为true
mybatis-plus.configuration.cache-enabled=false
3、idType
- 类型:
com.baomidou.mybatisplus.annotation.IdType
- 默认值:
ID_WORKER
全局默认主键类型,设置后,即可省略实体对象中的@Table(type=IdType.AUTO)配置
Springboot:
mybatis-plus.global-config.db-config.id-type=auto
4、tablePrefiix
- 类型:
String
- 默认值:
null
表名前缀。全局配置后可省略@TableName()配置
SpringBoot:
mybatis-plus.global-config.db-config.table-prefix=tb_