发布时间:2024-10-06 13:01
目录
1. Mybatis-Plus简介
1.1 Mybatis-Plus介绍
1.2 代码以及文档
1.3 特性
1.4 框架结构
1.5 作者
2. 快速入门
2.0 准备工作
2.1 Mybatis整合Mybatis-Plus
2.1.1 原生Mybatis查询
2.1.2 使用Mybatis-Plus查询
2.2 Spring&Mybatis整合Mybatis-Plus
2.3 SpringBoot、Mybatis整合Mybatis-Plus
3. 通用增删改查
3.1 插入操作
3.1.1 insert
3.1.2 @TableId
3.1.3 @TableField
3.2 更新操作
3.2.1 updateById
3.2.2 update
3.3 删除操作
3.3.1 deleteById
3.3.2 deleteByMap
3.3.3 delete
3.3.4 deleteBatchIds
3.4 查询操作
3.4.1 selectById
3.4.2 selectBatchIds
3.4.3 selectOne
3.4.4 selectCount
3.4.5 selectList
3.4.6 selectPage
4. 配置
4.1 基本配置
4.1.1 configLocation
4.1.2 mapperLocations
4.1.3 typeAliasesPackage
4.2 进阶配置
4.2.1 mapUnderscoreToCamelCase
4.2.2 cacheEnabled
4.3 DB策略配置
4.3.1 idType
4.3.2 tablePrefix
5. 条件构造器
5.1 allEq
5.2 基本比较操作
5.3 模糊查询
5.4 排序
5.5 逻辑查询
5.6 select
6. ActiveRecord
6.1 开启ActiveRecord
6.2 根据id查询
6.3 插入数据
6.4 更新数据
6.5 删除数据
6.6 根据条件查询
7. 其他
7.1 SQL注入器
7.1.1 编写MyBaseMapper
7.1.2 编写MySqlInjector
7.1.3 编写FindAll
7.1.4 注册到Spring容器
7.1.5 进行测试
7.2 自动填充功能
7.2.1 添加@TableField注解
7.2.2 编写MyMetaObjectHandler
7.2.3 测试
7.3 逻辑删除
7.3.1 修改表结构
7.3.2 配置
7.3.3 测试
7.4 通用枚举
7.4.1 修改表结构
7.4.2 定义枚举
7.4.3 配置
7.4.4 修改实体类
7.4.5 测试
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
官网:mybatis.plus或Redirect
文档地址:mybatis.plus
源码地址:https://github.com/baomidou/mybatis-plus
对于Mybatis整合MP有常常有三种用法,分别是Mybatis+MP、Spring+Mybatis+MP、Spring Boot+Mybatis+MP。
建立测试用的数据库和表,SQL以及如下:
/*
Navicat MySQL Data Transfer
Source Server : MYSQL5_3306
Source Server Version : 50518
Source Host : localhost:3306
Source Database : db_mp_test
Target Server Type : MYSQL
Target Server Version : 50518
File Encoding : 65001
Date: 2021-05-23 10:45:35
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(20) NOT NULL,
`name` varchar(20) NOT NULL,
`age` int(11) NOT NULL,
`email` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (\'1\', \'zhangsan\', \'123456\', \'张三\', \'18\', \'zhangsan@qq.com\');
INSERT INTO `tb_user` VALUES (\'2\', \'lisi\', \'123456\', \'李四\', \'20\', \'lisi@qq.com\');
INSERT INTO `tb_user` VALUES (\'3\', \'wangwu\', \'123456\', \'王五\', \'21\', \'wangwu@qq.com\');
INSERT INTO `tb_user` VALUES (\'4\', \'zhaoliu\', \'654321\', \'赵六\', \'19\', \'zhaoliu@qq.com\');
INSERT INTO `tb_user` VALUES (\'5\', \'sunqi\', \'852369\', \'孙七\', \'22\', \'sunqi@qq.com\');
第一步,创建一个基于maven的JavaWeb项目
第二步,导入相关的依赖
mybatis-plus的坐标如下:
com.baomidou
mybatis-plus
3.4.3
导入其他需要的依赖
mysql
mysql-connector-java
5.1.38
com.alibaba
druid
1.1.22
junit
junit
4.13
org.slf4j
slf4j-log4j12
1.7.12
第三步,配置日志文件log4j.properties在resources目录下
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
第四步,在resources目录下创建mybatis的核心配置文件sqlMapConfig.xml文件,并且配置数据源
第五步,编写User实体类
public class User {
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private String email;
// 无参和全参构造器、get和set方法、toString方法
}
第六步,创建UserMapper接口
public interface UserMapper {
List findAll();
}
第六步,创建接口对应的UserMapper.xml
在SqlMapConfig.xml配置文件中添加此映射
第七步,编写TestMybatis
public class TestMybatis {
@Test
public void testFindAll() throws IOException {
InputStream inputStream = Resources.getResourceAsStream(\"SqlMapConfig.xml\");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取UserMapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行findAll方法
List userList = mapper.findAll();
// 打印结果
for (User user : userList) {
System.out.println(user);
}
}
}
控制台打印如下:
在原生的Mybatis基础上使用Mybatis-Plus查询只需要进行两步操作:
第一步,将UserMapper继承BaseMapper
第二步,将原来的SqlSessionFactoryBuilder替换成MybatisSqlSessionFactoryBuilder进行构建
public class TestMybatisPlus {
@Test
public void testFindAll() throws IOException {
InputStream inputStream = Resources.getResourceAsStream(\"SqlMapConfig.xml\");
SqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取UserMapper接口
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行findAll方法
List userList = mapper.findAll();
// 打印结果
for (User user : userList) {
System.out.println(user);
}
}
}
打印结果如下:
本节源码请参考:GitHub的Demo
引入了spring框架,数据源、构建工作交由Spring来管理。
第一步,创建一个基于web的maven项目并导入相关的包
com.baomidou
mybatis-plus
3.4.3
mysql
mysql-connector-java
5.1.38
com.alibaba
druid
1.1.22
junit
junit
4.13
org.slf4j
slf4j-log4j12
1.7.12
org.springframework
spring-webmvc
5.3.4
org.springframework
spring-jdbc
5.3.4
org.springframework
spring-test
5.3.4
第二步,编写jdbc.properties,将链接数据库的参数配置在里面
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/db_mp_test
jdbc.username=root
jdbc.password=root
第二步,编写spring的配置文件applicationContext.xml
第三步,编写User实体类,使用@TableName(\"tb_user\")注解映射数据库表和实体类的关系
@TableName(\"tb_user\")
public class User {
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private String email;
// 无参和全参构造器、get和set方法、toString方法
}
第四步,创建UserMapper接口,只需要继承BaseMapper
public interface UserMapper extends BaseMapper {
}
第五步,编写测试用例
public class TestMybatisPlus {
@Test
public void testFindAll() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
List userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
}
打印结果如下:
在本例中没有写Mapper.xml,也没有写mybatis的配置文件了。
本节源码参考:GitHub的Demo
第一步,创建一个基于web的maven工程,然后导入相关的依赖坐标
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-test
com.baomidou
mybatis-plus-boot-starter
3.1.1
mysql
mysql-connector-java
5.1.48
org.slf4j
slf4j-log4j12
注意,还需要在pom.xml中引入parent
org.springframework.boot
spring-boot-starter-parent
2.3.4.RELEASE
第二步,日志文件log4j.properties如下,在resources目录下
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
第三步,编写springboot的配置文件application.properties
spring.application.name=springboot-mybatisplus
# 配置数据源连接参数
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_mp_test
spring.datasource.username=root
spring.datasource.password=root
第四步,编写实体类User,使用@TableName(\"tb_user\")注解完成实体类和数据库表的映射
@TableName(\"tb_user\")
public class User {
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private String email;
// 无参和全参构造器、get和set方法、toString方法
}
第四步,创建UserMapper接口,只需要继承BaseMapper
public interface UserMapper extends BaseMapper {
}
第五步,编写springboot启动类
@MapperScan(\"com.demo.mapper\")// 设置mapper接口的扫描包
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
第六步,编写测试类进行测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestMybatisPlus {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
}
打印结果如下:
本节源码参考:GitHub的Demo
通过前面的学习,我们了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这些操作。
在BaseMapper中的insert方法如下:
// 插入一条记录,返回受影响的行数
int insert(T entity);
测试方法如下:
public class TestMybatisPlus {
@Test
public void testInsert() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 创建测试实体类并封装数据
User user = new User();
user.setUsername(\"tangseng\");
user.setPassword(\"123456\");
user.setName(\"唐僧\");
user.setAge(18);
user.setEmail(\"tangseng@qq.com\");
// 调用insert方法进行插入操作,返回受影响的行数
int result = userMapper.insert(user);
// 打印结果
System.out.println(\"受影响行数:\" + result);// 打印受影响行数
System.out.println(user.getId());// 自增后的id会回填到对象中
}
}
虽然数据写入到数据库中,但是id值不正确,我们期望数据库id主键自增长,实际是MybatisPlus生成了id的值写入到了数据库中。
但我们可以通过设置id的生成策略来进行设置。
Mybatis支持的id策略,可以查看IdType枚举类。
public enum IdType {
AUTO(0),// 数据库ID自增
NONE(1),//该类型为未设置主键类型
INPUT(2),// 用户输入ID
ASSIGN_ID(3),
ASSIGN_UUID(4);
private final int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
所以,如果我们想要id值自增长,可以在实体类的id字段上添加@TableId(type=IdType.AUTO)注解来指定id类型为自增长。
@TableName(\"tb_user\")
public class User {
@TableId(type = IdType.AUTO)// 设置id字段为自增长
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private String email;
// 无参和全参构造器、get和set方法、toString方法
}
再来执行测试,就会发现id字段是自增长了,并且这条插入数据的id会封装在User对象中返回。
在MybatisPlus中通过@TableField注解可以指定字段的一些属性,常解决的问题有:
更新操作有2种,一种是根据id更新,另一种是根据条件更新。
方法的定义是:
// 根据ID进行更新数据库表记录,返回受影响行数
int updateById(@Param(Constants.ENTITY) T entity);
使用示例如下:
@Test
public void testUpdateById() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 创建要更新的字段,将主键id字段和其他要更新的字段封装在对象中
User user = new User();
user.setId(4L);// 待更新的主键ID
user.setPassword(\"abcdef\");// 更新的字段
user.setAge(22);// 更新的字段
// 调用updateById方法进行更新操作,返回受影响的行数
int result = userMapper.updateById(user);
System.out.println(\"受影响的行数:\" + result);
}
根据条件更新的方法如下:
// 根据where多条件更新记录
// 有两个参数:第一个参数是entity指的是实体对象(set 条件值,可以为null)
// 第二个参数updateWrapper是实体对象封装操作类(可以为null,里面的entity用于生成where语句)
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper);
使用示例如下:
@Test
public void testUpdate() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 创建要更新的字段,将主键id字段和其他要更新的字段封装在对象中
User user = new User();
user.setPassword(\"abcdef\");// 更新的字段
user.setAge(22);// 更新的字段
// 添加更新的条件
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq(\"id\", 6);
// 执行更新操作
// 第一个参数是设置SQL语句中的set后面的参数(如set username=\'zhangsan\',age=13)
// 第二个参数是设置SQL语句中的where后面的参数(如where id=3 and name=\'张三\')
int result = userMapper.update(user, wrapper);
System.out.println(\"受影响的行数:\" + result);
}
也可以通过UpdateWrapper类来封装条件和更新的参数。
@Test
public void testUpdate2() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 设置更新的条件及更新的字段
UpdateWrapper wrapper = new UpdateWrapper();
// eq相当于设置where后面的条件;set相当于设置set后面的字段
wrapper.eq(\"id\", 6).set(\"password\", \"123456\");
// 执行更新操作
int result = userMapper.update(null, wrapper);
System.out.println(\"受影响的行数:\" + result);
}
方法如下:
// 根据id进行删除记录,返回受影响的行数
int deleteById(Serializable id);
使用示例如下:
@Test
public void testDeleteById() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 执行删除操作
int result = userMapper.deleteById(5L);
System.out.println(\"受影响的行数:\" + result);
}
方法定义如下:
// 根据条件删除记录,columnMap是一个Map集合,存储着条件字段和对应的值
int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
示例如下:
@Test
public void testDeleteByMap() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 将条件放到集合中
Map columnMap = new HashMap();
columnMap.put(\"age\", \"20\");
columnMap.put(\"name\", \"张三\");
// 执行多条件删除操作,多个条件之间为AND关系
int result = userMapper.deleteByMap(columnMap);
System.out.println(\"受影响的行数:\" + result);
}
方法定义:
// 根据实体类条件,删除记录,wrapper就是实体类对象封装操作类,可以为null
int delete(@Param(Constants.WRAPPER) Wrapper wrapper);
示例如下:
@Test
public void testDelete() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 封装条件
User user = new User();
user.setAge(20);
user.setId(3L);
user.setName(\"李四\");
// 将实体对象进行封装,包装为操作条件
QueryWrapper wrapper = new QueryWrapper(user);
// 执行删除操作,多个条件之间为AND关系
int result = userMapper.delete(wrapper);
System.out.println(\"受影响的行数:\" + result);
}
批量按照id进行删除,方法定义如下:
// 删除,根据id批量删除
int deleteBatchIds(@Param(\"coll\") Collection extends Serializable> idList);
示例如下:
@Test
public void testDeleteBatchIds() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 将要删除的id放到集合中
List list = new ArrayList();
list.add(1L);
list.add(12L);
list.add(22L);
// 根据id集合批量删除
int result = userMapper.deleteBatchIds(list);
System.out.println(\"受影响的行数:\" + result);
}
方法定义如下:
// 根据id进行查询
T selectById(Serializable id);
示例如下:
@Test
public void testSelectById() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 根据id进行查询
User user = userMapper.selectById(2L);
System.out.println(user);
}
方法定义:
// 根据id集合批量查询,返回实体类集合
List selectBatchIds(@Param(\"coll\") Collection extends Serializable> idList);
示例:
@Test
public void testSelectBatchIds() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 根据id集合进行查询
List idList = new ArrayList();
idList.add(1L);
idList.add(2L);
idList.add(3L);
idList.add(4L);
// 调用方法进行查询
List userList = userMapper.selectBatchIds(idList);
for (User user : userList) {
System.out.println(user);
}
}
方法如下:
// 查询一条数据
T selectOne(@Param(\"ew\") Wrapper queryWrapper);
示例:
@Test
public void testSelectOne() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 设定条件
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq(\"name\", \"李四\");
// 根据条件查询一条数据,如果结果超过一条就会报错
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
方法定义:
// 根据wrapper条件,查询总记录数,其中参数可以为null
Integer selectCount(@Param(\"ew\") Wrapper queryWrapper);
示例如下:
@Test
public void testSelectCount() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 设定条件
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt(\"age\", 15);// 查询年龄大于15岁的人
// 根据条件查询记录总数
Integer count = userMapper.selectCount(wrapper);
System.out.println(\"记录总数:\" + count);
}
方法定义:
// 根据条件查询符合条件的全部记录
List selectList(@Param(\"ew\") Wrapper queryWrapper);
示例:
@Test
public void testSelectList() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 设定条件
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt(\"age\", 15);// 查询年龄大于15岁的人
// 根据条件查询记录
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
该方法是分页查询,方法的定义:
// 根据条件分页查询记录,第一个参数分页查询条件,第二个参数为对象封装操作类(可以为null)
IPage selectPage(IPage page, @Param(\"ew\") Wrapper queryWrapper);
在使用该方法之前,现需要配置分页插件,如果是spring整合MybatisPlus,则需要在spring的核心配置文件中添加如下内容:
如果是SpringBoot整合MybatisPlus则需要创建一个配置类,类中如下内容:
@Configuration
@MapperScan(\"com.demo.mapper\")
public class CustomMyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(paginationInnerInterceptor());
return interceptor;
}
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor page = new PaginationInnerInterceptor();
page.setDbType(DbType.MYSQL);
return page;
}
}
示例如下:
@Test
public void testSelectPage() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 设定分页参数,第一个参数是页码(从1开始),第二个参数是页显示条数
Page page = new Page(1L, 2L);
// 设定筛选条件
QueryWrapper wrapper = new QueryWrapper();
wrapper.gt(\"age\", 15);// 查询年龄大于15岁的人
// 根据条件查询记录
IPage userPage = userMapper.selectPage(page, null);
System.out.println(\"数据总条数:\" + userPage.getTotal());
System.out.println(\"总页数:\" + userPage.getPages());
// 打印分页记录
List userList = userPage.getRecords();// 获取分页记录数
for (User user : userList) {
System.out.println(user);
}
}
打印结果如下:
本节源码参考:GitHub的Demo
Mybatis-Plus各种配置的官方参考文档:mybatis.plus
MyBatis 配置文件位置,如果您有单独的 MyBatis 配置,请将其路径配置到 configLocation 中。 MyBatisConfiguration 的具体内容请参考MyBatis 官方文档。
spring整合mybatis-plus,SqlMapConfig.xml配置文件是mybatis的配置文件
springboot整合mybatis-plus,需要在application.properties中配置:
mybatis-plus.config-location = classpath:SqlMapConfig.xml
MyBatis Mapper 所对应的 XML 文件位置,如果您在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置。
spring整合mybatis-plus:
springboot整合mybatis-plus,需要在application.properties中配置:
mybatis-plus.mapper-locations = classpath*:com/demo/mapper/*.xml
注意:maven多模块的扫描路径以classpath*:开头,即加载多个jar包下的XML文件。
UserMapper.xml
UserMapper.java
public interface UserMapper extends BaseMapper {
List findAll();
}
进行测试
@Test
public void testFindAll(){
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
List all = userMapper.findAll();
for (User user : all) {
System.out.println(user);
}
}
MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)。
spring整合mybatis-plus:
springboot整合mybatis-plus,需要在application.properties中配置:
mybatis-plus.type-aliases-package = com.demo.bean
注意,这里IDEA工具会爆红,但是代码是能够运行成功的,因为已经成功配置了的。
本部分(Configuration)的配置大都为 MyBatis 原生支持的配置,这意味着您可以通过 MyBatis XML 配置文件的形式进行配置。
该配置表示十分开启自动驼峰命名规则(camel case)映射,即从数据库列名如user_name到Java属性名userName(驼峰命名)的映射。
该属性是一个Boolean类型,默认值是true,表示开启了自动驼峰命名规则映射。
注意:此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body如果您的数据库命名符合规则无需使用@TableField注解指定数据库字段名。
springboot整合mybatis-plus,需要在application.properties中配置:
#关闭自动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false
全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为 true。
springboot配置示例:
mybatis-plus.configuration.cache-enabled=false
全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置。
springboot整合mybatis-plus,需要在application.properties中配置:
mybatis-plus.global-config.db-config.id-type=auto
spring整合mybatis-plus:
配置表名前缀,全局配置后可省略@TableName()配置。
如\"tb_user\"表,那么就可以配置前缀\"tb_\"。
springboot整合mybatis-plus,需要在application.properties中配置:
mybatis-plus.global-config.db-config.table-prefix=tb_
spring整合mybatis-plus:
官方文档地址:https://mybatis.plus/guide/wrapper.html
在MybatisPlus中,Wrapper接口的实现类关系如下:
可以看到,AbstractWrapper和AbstractChainWrapper是重点实现,接下来我们重点学习AbstractWrapper以及其子类。
说明:
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
allEq()方法如下:
allEq(Map params)
allEq(Map params, boolean null2IsNull)
allEq(boolean condition, Map params, boolean null2IsNull)
参数说明:
示例1:如果是allEq(params)方法,那么如果有字段为null,那么SQL语句就会按照is null处理。
@Test
public void testAllEq() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
Map map = new HashMap();
map.put(\"id\", 2);
map.put(\"name\", \"李四\");
map.put(\"age\", null);
Wrapper wrapper=new QueryWrapper();
((QueryWrapper) wrapper).allEq(map);
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
示例1:如果是allEq(params, null2IsNull)方法,那么如果有字段为null并且null2IsNull参数为false,那么SQL语句就会忽略值为null的字段。
@Test
public void testAllEq2() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
Map map = new HashMap();
map.put(\"id\", 2);
map.put(\"name\", \"李四\");
map.put(\"age\", null);
Wrapper wrapper = new QueryWrapper();
((QueryWrapper) wrapper).allEq(map, false);// 添加一个参数为false
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
allEq()方法还有下面这些重载方法:
allEq(BiPredicate filter, Map params)
allEq(BiPredicate filter, Map params, boolean null2IsNull)
allEq(boolean condition, BiPredicate filter, Map params, boolean null2IsNull)
参数说明:
示例:
@Test
public void testAllEq3() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
Map map = new HashMap();
map.put(\"id\", 2);
map.put(\"name\", \"李四\");
map.put(\"age\", null);
Wrapper wrapper = new QueryWrapper();
// 意思是Map中的键名存在\"name\"或\"age\"才进行查询
((QueryWrapper) wrapper).allEq((k, v) -> (k.equals(\"name\") || k.equals(\"age\")), map, false);
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
方法如下:
示例:
@Test
public void testEq() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
QueryWrapper wrapper = new QueryWrapper<>();
/*
等价于
select * from tb_user where passowrd=? and age>=? and name in (?,?,?)
*/
wrapper.eq(\"password\", \"123456\")
.ge(\"age\", 15)
.in(\"name\", \"张三\", \"李四\", \"王五\");
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
模糊查询有的方法如下:
示例:
@Test
public void testLike() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
QueryWrapper wrapper = new QueryWrapper<>();
/*
等价于
select * from tb_user where name like ?
*/
wrapper.like(\"name\", \"王\");
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
排序用的方法有:
示例:
@Test
public void testOrderBy() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
QueryWrapper wrapper = new QueryWrapper<>();
/*
等价于
select * from tb_user order by age desc
*/
wrapper.orderByDesc(\"age\");
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
逻辑查询就是AND或OR,方法有:
示例:
@Test
public void testOr() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
QueryWrapper wrapper = new QueryWrapper<>();
/*
等价于
select * from tb_user where name=? or age=?
*/
wrapper.eq(\"name\", \"李四\").or().eq(\"age\", 24);
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
在MybatisPlus查询中,默认是查询表中的所有字段,如果有需要可以通过select方法指定要查询的字段。示例:
@Test
public void testSelect() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
QueryWrapper wrapper = new QueryWrapper<>();
/*
等价于
select name,password from tb_user where name=? or age=?
*/
wrapper.eq(\"name\", \"李四\").or().eq(\"age\", 24).select(\"name\", \"password\");
List userList = userMapper.selectList(wrapper);
for (User user : userList) {
System.out.println(user);
}
}
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很大程度的快速实现模型的操作,而且简洁易懂。
ActiveRecord的主要思想是:
意思就是实例化一个实体类对象,就可以在该实例对象上执行增删改查的方法。
只需要让实体类继承Model
例如:
@TableName(\"tb_user\")
public class User extends Model {// 继承extend Model即可
@TableId(value = \"id\", type = IdType.AUTO)// 设置id字段为自增长
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private String email;
// 无参和全参构造器、get和set方法、toString方法
直接在实体类对象上调用selectById()方法即可。
@Test
public void testAR1() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");// 加载配置文件是必要的
// 实例化对象
User user = new User();
user.setId(4L);// 设置主键id
// 调用AR的查询方法selectById()
User resultUser = user.selectById();
System.out.println(resultUser);
}
注意:这里面的ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");代码是为了加载spring和mybatis配置文件,是必须的,但却不是AR使用必须的。
插入数据在封装好实体类对象后,直接调用insert方法即可,返回一个布尔值表示是否插入成功。
@Test
public void testAR2() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
// 实例化对象,并封装要插入的数据
User user = new User();
user.setName(\"张飞\");
user.setAge(20);
user.setPassword(\"abcdefg\");
user.setUsername(\"zhangfei\");
user.setEmail(\"zhangfei@qq.com\");
// 调用插入方法insert
boolean result = user.insert();
System.out.println(\"是否插入成功:\" + result);
}
根据id进行更新,调用updateById方法即可。
@Test
public void testAR3() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
// 实例化对象,封装id和要更新的数据
User user = new User();
user.setId(3L);
user.setPassword(\"xxxxxx\");
// 执行更新操作
boolean result = user.updateById();
System.out.println(\"是否更新成功:\" + result);
}
删除数据根据id进行删除,调用deleteById方法。
@Test
public void testAR4() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
// 实例化对象,封装要删除的id
User user = new User();
user.setId(2L);
// 执行删除操作
boolean result = user.deleteById();
System.out.println(\"是否删除成功:\" + result);
}
根据条件查询就是设定QueryWrapper条件。
@Test
public void testAR5(){
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
// 实例化对象
User user=new User();
// 封装查询条件
QueryWrapper wrapper=new QueryWrapper<>();
wrapper.eq(\"username\",\"zhangsan\");
// 进行查询
List userList = user.selectList(wrapper);
for (User u : userList) {
System.out.println(u);
}
}
在MP中,通过AbstractSqlInjector将BaseMapper中的方法注入到了Mybatis容器,这样这些方法才可以正常执行。
我们如果要扩充BaseMapper接口中的方法,就可以使用SQL注入器来进行扩展方法。
下面以findById方法为例学习。
定义一个接口MyBaseMapper
public interface MyBaseMapper extends BaseMapper {
// 定义自己想要扩展的方法
List findAll();
}
然后其他的Mapper就可以继承我们自己写的MyBaseMapper
// 继承自己写的MyBaseMapper接口
public interface UserMapper extends MyBaseMapper {
}
如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的方法将失效,所以我们选择继承DefaultSqlInjector进行扩展。
public class MySqlInjector extends DefaultSqlInjector {// 继承DefaultSqlInjector类
// 重写里面的getMethodList()方法
@Override
public List getMethodList(Class> mapperClass) {
// 获取方法列表
List methodList = super.getMethodList(mapperClass);
// 在列表中添加自定义的方法
methodList.add(new FindAll());
// 最后返回列表
return methodList;
}
}
然后写一个类FindAll(类名就是刚才自定义的方法名,首字母大写),继承AbstractMethod类。
public class FindAll extends AbstractMethod {// 继承AbstractMethod类
// 并重写injectMappedStatement方法
@Override
public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {
// 定义的方法名
String methodName = \"findAll\";
// 拼接SQL语句
String sql = \"select * from \" + tableInfo.getTableName();// 获取表名
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
return addSelectMappedStatementForTable(mapperClass, methodName, sqlSource, tableInfo);
}
}
将自定义的ySqlInjector类注册到Spring的容器中。
如果是使用xml文件进行注册组件,需要在spring的核心配置文件applicationContext.xml添加配置:
如果是通过注解注册组件:
@Bean
public MySqlInjector mySqlInjector(){
return new MySqlInjector();
}
@Test
public void testFindById() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 调用自定义的方法findAll
List userList = userMapper.findAll();
for (User user : userList) {
System.out.println(user);
}
}
注意:我这里自定义并不能成功,请参考官网Demo
所谓的自动填充就是在插入或更新数据的时候,某些字段自动填入我们想要的值,相当于设置默认值。
只需要在需要自动填充的字段上添加@TableField注解即可。
FieldFill是一个枚举值,有多个模式可以选择:
public enum FieldFill {
DEFAULT,// 默认不处理
INSERT,// 插入时填充字段
UPDATE,// 更新时填充字段
INSERT_UPDATE;// 插入和更新时填充字段
private FieldFill() {
}
}
编写一个MyMetaObjectHandler类实现MetaObjectHandler接口,重写里面的insertFill方法和updateFill方法,如果要在插入时自动填充则重写insertFill方法,如果要在更新时自动填充则重写updateFill方法,如果既要在插入时自动填充又要在更新时自动填充则两个方法都重写。其中getFieldValByName()方法可以通过字段名来获取这个字段,来进行操作。setFieldValByName()方法可以设置某个字段的值。
@Component // 可以用该注解将该类Bean化
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 获取密码字段
Object password = getFieldValByName(\"password\", metaObject);
// 判断密码字段是否为空,如果为空则进行自动填充,如果不为空则不进行自动填充
if (null == password) {
// 字段为空,进行填充
setFieldValByName(\"password\", \"123456\", metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
@Test
public void testAutoInsert() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
User user = new User();
user.setName(\"猪八戒\");
user.setUsername(\"zhubajie\");
user.setEmail(\"zhubajie@qq.com\");
user.setAge(1999);
int result = userMapper.insert(user);
System.out.println(result);
}
注意:关于自动填充功能使用spring整合mybatis-plus失败,但是使用springboot整合mybatis-plus成功。
所谓的逻辑删除就是不执行delete语句删除表中的记录,而是执行update语句修改记录的某个表示状态的属性(通常设定一个status字段,1表示已经逻辑删除,0表示未逻辑删除)
执行如下语句,为我们的测试表tb_user添加一个deleted字段,表示数据是否被删除,1表示被删除了,0表示未删除。
ALTER TABLE tb_user ADD COLUMN deleted int(1) null default 0;
同时修改User实体类,添加deleted属性并添加@TableLogic注解,表示这个字段可能要进行逻辑删除。
@TableLogic
private Integer deleted;
如果是springboot则在application.properties文件中添加如下:
# 逻辑已删除值(默认为1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
如果是spring整合mybatis-plus,则在spring的核心配置文件applicationContext.xml中配置:
注意,这里的logicDeleteValue值为1是因为我在数据库表中规定1表示已经被逻辑删除了,logicNotDeleteValue值为0是因为我在数据库表中规定0表示未逻辑删除,这两个值你可以是1和-1,可以是任何你想标记的数字。
执行deleteById方法进行逻辑删除。
@Test
public void testLogicDelete() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 执行逻辑删除
int result = userMapper.deleteById(2L);
System.out.println(result);
}
枚举就是让一个字段的值只在某几个值中选择。比如性别只能是“男”或者“女”,不能是其他性别。
执行下面的SQL语句,为我们的tb_user表添加一个性别sex字段,但是我们不在表中直接存储“男”或“女”字符串,而是用数字1表示性别男,数字2表示性别女。
ALTER TABLE tb_user ADD COLUMN sex int(1) NULL DEFAULT 1 COMMENT \'1-男, 2-女\';
创建一个枚举类并实现IEnum
public enum SexEnum implements IEnum {
MAN(1, \"男\"),
WOMAN(2, \"女\");
private int value;
private String desc;
SexEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.desc;
}
}
如果是springboot项目则在application.properties中添加枚举包扫描:
# 枚举包扫描
mybatis-plus.type-enums-package=com.demo.enum
如果是spring整合mybatis-plus项目则需要在applicationContext.xml中配置:
然后将枚举类型应用到实体类中
测试插入数据用枚举类型。
@Test
public void testInsertByEnum() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 封装要插入的数据
User user = new User();
user.setName(\"关银屏\");
user.setUsername(\"guanyinping\");
user.setAge(35);
user.setEmail(\"guanyinping@qq.com\");
user.setPassword(\"xxxxxx\");
user.setSex(SexEnum.WOMAN);// 设置性别用枚举类型
// 执行插入
int result = userMapper.insert(user);
System.out.println(result);
}
测试查询,它会自动映射为中文。
@Test
public void testSelectByEnum() {
ApplicationContext app = new ClassPathXmlApplicationContext(\"classpath:applicationContext.xml\");
UserMapper userMapper = (UserMapper) app.getBean(\"userMapper\");
// 执行查询
List userList = userMapper.selectList(null);
for (User user : userList) {
System.out.println(user);
}
}
本节源码参考:GitHub的Demo