近期也是计划学习mybatis-plus,扩展知识;
推荐官方文档食用学习–>https://baomidou.com/
Mybatis-plus官方文档
本次学习根据B站尚硅谷教学视频:【尚硅谷】2022版MyBatisPlus教程(一套玩转mybatis-plus)
1.常用注解
1.1 @TableName
在之前学习的时候,注意到并没有指定操作哪个数据表,但是操作时它就会找到用户user
数据表;这是根据实体类User来判定找到的;
那么此时将数据库中的用户表名修改后,注意观察效果; 将
user 表名改为 t_user
找到之前编写的测试类MybatisPlusTest
运行测试方法;
此时发现程序报错数据表user
不存在;因为默认识别的是查询数据表user
,但是将数据表user
改名为t_user
了,也就无法匹配.
那么如何自动识别到要查询的数据表t_user
呢?
有两种方式:
- 首先,可以选择在
实体类User
处使用注解@TableName
来标注数据表的名称
再运行测试方法试试,可成功操作对应的数据表t_user
全局配置
- 当然,也可以选择第二种做法,在配置文件
application.yml
中进行配置数据表的识别;
先将刚才在实体类User写的注解
@TableName("t_user")
注释掉;
在application.yml
中配置mybatis的全局配置;对于项目使用的数据表公共前缀进行标注;
# 设置数据源类型,数据库信息;
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#可配置mybatis的全局配置
global-config:
db-config:
table-prefix: t_
同样测试一下,也可以正常使用
1.2 @TableId
通过前面的学习,了解到mybatis-plus是默认将数据表中的id作为主键的,要是将数据表的字段id
改为uid
呢?是否还能正确识别到主键?
将数据表中的id修改为
uid
当然,实体类User的属性id也修改为
uid
在MybatisPlusTest
中执行测试的添加功能;
//测试新增功能;
@Test
public void startAdd() {
User user = new User();
user.setName("小智");
user.setAge(22);
user.setEmail("xiaozhi@ceshi.com");
//新增数据;
//INSERT INTO user ( Uid, name, age, email ) VALUES ( ?, ?, ?, ? )
int insert = userMapper.insert(user);
//是否添加成功;
System.out.println("新增了" + insert + "条数据----------");
//立即获取到添加数据的主键Id;
System.out.println("立即获取新增的用户主键:" + user.getUid());
}
运行之,显而易见出现了sql错误.提示uid这个字段没有设定的默认值,即无法识别它的主键身份.
那么解决处理,可使用注解@TableId
来进行标注.
打开实体类User
;在属性uid
上使用注解;即可将属性uid
对应的字段uid
标识为主键;
@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User {
@TableId
private Long uid;
private String name;
private Integer age;
private String email;
}
测试执行刚才的添加方法,数据成功存入;
键入注解TableId
,可看到value和type方法;这两个方法可操作的.
模拟场景,此时要是将用户User的属性
uid
改为id
. 而数据表的字段仍然是uid
,那么属性该如何识别到对应的字段uid
呢?
可使用value属性
进行标注即可;
再看看type
的功能; 可操作属性的策略;
先将数据表中的uid字段设置为自增;
首先测试一下添加数据方法;
运行之,发现uid还是默认的雪花算法生成的,并不是自增的;
那么实际上就需要用注解@TableId
的属性type
进行标注自增属性;
可以看注解@TableId
源码中的type()
方法返回值类型IdType
的源码,这是个枚举类,ok很容易找到这样一个方法来标注自增
.
在实体类User
设置即可;
@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User {
//将属性对应的字段标注为主键;
//value属性可标注对应的字段;
@TableId(value = "uid",type = IdType.AUTO )
private Long id;
private String name;
private Integer age;
private String email;
}
测试执行添加数据的方法;OK,确实有自增效果了;
常见的主键设定策略:
- 默认的:
IdType.ASSIGN_ID
基于雪花算法的策略生成数据id,与数据库id是否设置自增无关 IdType.AUTO
使用数据库的自增策略,该类型请确保数据库设置了id自增,否则无效.
全局配置
当然,不使用注解也是可以的,在application.yml
中进行全局配置即可.使用参数id-type
配置主键生成策略即可.
# 设置数据源类型,数据库信息;
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#可配置mybatis的全局配置
global-config:
db-config:
#设置实体类表的统一前缀;
table-prefix: t_
#可设置统一的主键生成策略;
id-type: auto
测试新增数据,可发现执行了自增策略.
1.3 雪花算法介绍
为应对数据规模的增长,需要分析访问压力和数据量
数据库的三种扩展方式:业务分库、主从复制,数据库分表。
关于数据库分表:
垂直分表:
水平分表
1.4 @TableField
首先模拟场景,数据表字段用下划线分隔,在实体类中属性用驼峰命名.
将user中的name
字段改为user_name
.
在实体类User中也进行修改.
执行测试方法;
执行sql时,名称字段还是user_name
,那么也就是说在mybatis-plus中有默认的下划线匹配对应驼峰
.
那要是不在实体类中使用驼峰命名法呢?
执行测试方法,
在执行sql时,无法识别到对应的字段
那么,即要不用驼峰命名,还要匹配对应字段,使用注解@TableField
即可.
执行测试方法;已正确识别到字段user_name.
1.5 @TableLogic
关于逻辑删除,也就是在代码逻辑上数据已经被删除,但是数据库中实际只是改变了数据的状态,数据并没有消除.\
在数据表user中创建一个字段is_deleted
,表示该数据行是否删除的转态,默认为0
表示未删除,删除时修改该字段即可.
在实体类User中添加该属性.可用注解@TableLogic
表明逻辑删除.
现在测试执行删除方法;一次性删除3个.
但是注意到它执行的sql语句并不是delete
,而是update
更新数据,将字段is_deleted
由0变为了1.
当前的user数据表包含了22条数据,刚才逻辑删除3条.实际总数据应该是19条.
现在执行查询语句查看总数据量;
执行后,注意到总数据量为19条. 也就是说,逻辑删除已被认可.
执行的sql也用where来筛选is_deleted
为0的数据.
2. 条件构造器
![在这里插入图片描述](https://img-blog.csdnimg.cn/4f222f0bcb444022a1a0cd3a950269b6.png)
关于条件构造器的说明
Wrapper
:条件构造器的抽象类
AbstractWrapper
封装查询条件,可生成sql语句中的where条件.
QueryWrapper
封装查询条件
UpdateWrapper
封装更新条件
AbstractLambdaWrapper
,LambdaQueryWrapper
,LambdaUpdateWrapper
可使用Lambda语法
2.1 组装查询条件案例
先创建测试类MybatisPlusWrapperTest
;
import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus
* @Author: 信计1801 李智青
* @Date: 2022/7/1 20:27
* @Description: 条件构造器测试
*/
@SpringBootTest
public class MybatisPlusWrapperTest {
//自动装配;
@Autowired
private UserMapper userMapper;
}
运行测试方法1,查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.
@Test
public void testOne() {
//查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.like("user_name", "xiaozhi")
.between("age", 20, 50)
.isNotNull("email");
//查询集合;
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
执行结果;
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
2.2 组装排序案例
运行测试方法2;查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.
@Test
public void testTwo() {
//查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age")
.orderByAsc("uid");
//查询集合;
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之;
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC
2.3 组装删除条件案例
运行测试方法3:删除user_name
为空的数据
@Test
public void testThree() {
//删除user_name不为空的数据
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.isNotNull("user_name");
int delete = userMapper.delete(queryWrapper);
System.out.println("删除了" + delete + "条数据");
}
运行之,实际是逻辑删除.
UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (user_name IS NOT NULL)
2.4 修改功能案例
测试方法4:修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.
@Test
public void testFour() {
//修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20)
.like("user_name", "xiaozhi")
.or()
.isNull("email");
User user = new User();
user.setAge(20);
int update = userMapper.update(user, queryWrapper);
System.out.println("修改了" + update + "条数据");
}
运行之.
UPDATE t_user SET age=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)
2.5 条件的优先级设置
测试方法5:修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
注意需要设置条件的优先级,不然写出来就和测试方法4差不多了.
@Test
public void testFive() {
//修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("user_name", "xiaozhi")
.and(i -> i.gt("age", 20).or().isNull("email"));
User user = new User();
user.setAge(20);
int update = userMapper.update(user, queryWrapper);
System.out.println("修改了" + update + "条数据");
}
运行之,实际执行sql为:
UPDATE t_user SET age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
2.6 组装select精确查询案例
测试方法6:查询用户的名称,年龄,邮箱;;
@Test
public void testSix() {
//查询用户的名称,年龄,邮箱;;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("user_name", "age", "email");
//查询集合;
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之,实际执行SQL为:
SELECT user_name,age,email FROM t_user WHERE is_deleted=0
2.7 组装子查询案例
测试方法7:查询uid小于100的用户.
@Test
public void testSeven() {
//查询uid小于100的用户.
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.inSql("uid", "select uid from t_user where uid < 100");
//查询集合;
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之,实际执行sql为:
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid < 100))
2.8 UpdateWrapper的修改功能案例
测试方法8: 修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
@Test
public void testEight() {
//修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.like("user_name", "xiaozhi")
.and(i -> i.gt("age", "20").or().isNull("email"));
updateWrapper.set("user_name", "小智RE0").set("age", 22);
int update = userMapper.update(null, updateWrapper);
System.out.println("修改了" + update + "条数据");
}
运行之,实际运行SQL为:
UPDATE t_user SET user_name=?,age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
2.9 模拟开发组装条件案例
编写一个模拟数据输入的案例
@Test
public void testNine() {
//模拟前端输入数据;
String userName = "xiaozhi";
Integer ageStart = 22;
Integer ageEnd = 230;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//isNotBlank 判断字符串序列不是 null ,不是空白
if (StringUtils.isNotBlank(userName)) {
queryWrapper.like("user_name", userName);
}
if (ageStart != null) {
queryWrapper.ge("age", ageStart);
}
if (ageEnd != null) {
queryWrapper.le("age", ageEnd);
}
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之,实际运行SQL为:
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)
2.10 使用Condition组装条件案例
测试方法10:
@Test
public void testTen() {
//模拟前端输入数据;
String userName = "xiaozhi";
Integer ageStart = 20;
Integer ageEnd = 230;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//isNotBlank 判断字符串序列不是 null ,不是空白;
//这里用了布尔类型的参数condition作为判断先行条件;
queryWrapper.like(StringUtils.isNotBlank("user_name"), "user_name", userName)
.ge(ageStart != null, "age", ageStart)
.le(ageEnd != null, "age", ageEnd);
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之,实际执行sql为:
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)
2.11 LambdaQueryWrapper案例
测试方法11:
@Test
public void testEleven() {
//模拟前端输入数据;
String userName = "xiaozhi";
Integer ageStart = 20;
Integer ageEnd = 230;
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank("user_name"), User::getName, userName)
.ge(ageStart != null, User::getAge, ageStart)
.le(ageEnd != null, User::getAge, ageEnd);
List<User> userList = userMapper.selectList(queryWrapper);
userList.forEach(System.out::println);
}
运行之,实际运行SQL为:
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)
2.12 LambdaUpdateWrapper使用案例
测试方法12:
@Test
public void testTwelve() {
//修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.like(User::getName, "xiaozhi")
.and(i -> i.gt(User::getAge, "20").or().isNull(User::getEmail));
updateWrapper.set(User::getName, "小智RE0").set(User::getAge, 22);
int update = userMapper.update(null, updateWrapper);
System.out.println("修改了" + update + "条数据");
}
运行之,实际SQL为:
UPDATE t_user SET user_name=?,age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
3.Mybatis-Plus分页插件
创建一个配置类即可使用分页插件
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus.config
* @Author: 信计1801 李智青
* @Date: 2022/7/2 12:47
* @Description: 分页配置类;
*/
@Configuration
//标注扫描映射接口所在的包;
@MapperScan("com.xiaozhi.mybatisplus.mapper")
public class PaginationConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new
PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
创建测试类,写一个测试的分页方法试试;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaozhi.mybatisplus.entity.User;
import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus
* @Author: 信计1801 李智青
* @Date: 2022/7/2 12:53
* @Description: 插件测试类
*/
@SpringBootTest
public class PlginTest {
@Autowired
private UserMapper userMapper;
@Test
public void testOne() {
//创建分页对象;当前页的页码,当前页的显示条数;
Page<User> page = new Page<>(2, 5);
//查询,此处就不放条件了
Page<User> userPage = userMapper.selectPage(page, null);
System.out.println(userPage);
}
}
运行之,分页使用的SQL
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
分页数据获取
getRecords()
方法 来获取数据列表getCurrent()
获取当前页getPages()
获取总页数getTotal()
获取总记录数
@Test
public void testOne() {
//创建分页对象;当前页的页码,当前页的显示条数;
Page<User> page = new Page<>(2, 5);
//查询,此处就不放条件了
Page<User> userPage = userMapper.selectPage(page, null);
//getRecords() 获取数据列表
System.out.println("getRecords() 获取数据列表----------->");
System.out.println(userPage.getRecords());
//getCurrent() 获取当前页
System.out.println("getCurrent() 获取当前页------------->");
System.out.println(userPage.getCurrent());
//getPages() 获取总页数
System.out.println("getPages() 获取总页数-------------->");
System.out.println(userPage.getPages());
//getTotal() 获取总记录数
System.out.println("getTotal() 获取总记录数------------>");
System.out.println(userPage.getTotal());
}
自定义分页功能
在UserMapper
接口中定义功能方法;
@Repository
public interface UserMapper extends BaseMapper<User> {
/*自定义测试方法,根据Id查询集合数据*/
Map<String, Object> selectMapById(Long id);
//根据年龄查询分页;
Page<User> selfPage(@Param("page") Page<User> page, @Param("age") Integer age);
}
在application.yml
中配置对应类型别名.
在UserMapper.xml
中编写sql
<?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.xiaozhi.mybatisplus.mapper.UserMapper">
<!--根据Id查询集合数据-->
<select id="selectMapById" resultType="map">
select id,name,age,email from user where id = #{id}
</select>
<!--根据年龄查询分页;-->
<select id="selfPage" resultType="User" >
select uid,user_name,age,email
from t_user
where age >= #{age}
</select>
</mapper>
在PlginTest
测试类中写个测试方法2
@Test
public void testTwo() {
//创建分页对象;当前页的页码,当前页的显示条数;
Page<User> page = new Page<>(1, 5);
//根据年龄作为条件进行查询;
Page<User> userPage = userMapper.selfPage(page, 20);
System.out.println(userPage);
}
运行之,执行sql
select uid,user_name,age,email from t_user where age >= ? LIMIT ?
4.乐观锁悲观锁
场景假设
模拟修改冲突
首先在数据库中新建一个商品表
CREATE TABLE t_product(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);
添加数据
INSERT INTO t_product (id, NAME, price) VALUES (1, '小智笔记', 80);
在entity
目录下创建商品实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus.entity
* @Author: 信计1801 李智青
* @Date: 2022/7/2 13:49
* @Description: 商品实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
//商品Id
private Long id;
//商品名
private String name;
//商品价格;
private Integer price;
//版本号
private Integer version;
}
在mapper
目录下创建ProductMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaozhi.mybatisplus.entity.Product;
import org.springframework.stereotype.Repository;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus.mapper
* @Author: 信计1801 李智青
* @Date: 2022/7/2 13:59
* @Description: 商品类对应映射类
*/
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}
在之前的测试类PlginTest
中创建方法模拟冲突进行测试;
@Autowired
private ProductMapper productMapper;
//测试商品表的数据操作;
@Test
public void testProOne() {
//杰哥根据Id查询商品信息;
Product AJieRest = productMapper.selectById(1);
System.out.println("杰哥得到的结果-->" + AJieRest.getPrice() + "元");
//阿伟根据Id查询商品信息;
Product AWeiRest = productMapper.selectById(1);
System.out.println("阿伟得到的结果-->" + AWeiRest.getPrice() + "元");
//杰哥让商品涨价了50元;
AJieRest.setPrice(AJieRest.getPrice() + 50);
productMapper.updateById(AJieRest);
//阿伟让商品降价20元;
AWeiRest.setPrice(AWeiRest.getPrice() - 20);
productMapper.updateById(AWeiRest);
//彬彬查询商品价格;
Product BinBinRest = productMapper.selectById(1);
System.out.println("彬彬得到的结果-->" + BinBinRest.getPrice() + "元");
}
运行之
乐观锁插件
在实体类中,可使用注解@Version
来标注乐观锁字段
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
//商品Id
private Long id;
//商品名
private String name;
//商品价格;
private Integer price;
//版本号 标注乐观锁.
@Version
private Integer version;
}
当然,也需要在PaginationConfig
中进行配置
@Configuration
//标注扫描映射接口所在的包;
@MapperScan("com.xiaozhi.mybatisplus.mapper")
public class PaginationConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页插件
interceptor.addInnerInterceptor(new
PaginationInnerInterceptor(DbType.MYSQL));
//添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
注意,测试刚才执行的模拟修改冲突;
实际也可以在语句中进行判断,
5.通用枚举
在数据表中有的字段需要使用固定值,则可以使用通用枚举来声明
案例,在数据表t_user
中创建性别字段sex
;
那么,既然使用枚举类,则创建一个枚举类型的性别类;
先创建enums
目录,然后创建SexEnums
类
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus.enums
* @Author: 信计1801 李智青
* @Date: 2022/7/4 22:17
* @Description: 性别描述
*/
@Getter
public enum SexEnums {
MALE(1, "男"),
FEMALE(2, "女");
private Integer sex;
private String sexName;
SexEnums(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
在用户类编写sex属性
可进行测试,创建测试类MybatisEnumTest
import com.xiaozhi.mybatisplus.entity.User;
import com.xiaozhi.mybatisplus.enums.SexEnums;
import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @BelongsProject: mybatis-plus
* @BelongsPackage: com.xiaozhi.mybatisplus
* @Author: 信计1801 李智青
* @Date: 2022/7/4 22:23
* @Description: 通用枚举测试类
*/
@SpringBootTest
public class MybatisEnumTest {
@Autowired
private UserMapper userMapper;
@Test
public void testOne() {
User user = new User();
user.setName("小智W");
user.setAge(22);
user.setEmail("xaiozhi@qq.com");
user.setSex(SexEnums.MALE);
int insert = userMapper.insert(user);
System.out.println("成功插入" + insert + "条数据");
}
}
运行之,此时出现问题:
注意使用注解@EnumValue
将该性别属性存入数据库中;
当然,需要配置到yml文件中配置扫描通用枚举类
type-enums-package:
此时运行无问题
6 代码生成器
先引入依赖
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
创建快速生成测试类FastAutoGeneratorTest
public class FastAutoGeneratorTest {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL = false", "root", "123456")
.globalConfig(builder -> {
builder.author("atguigu") // 设置作者
//.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("F://mybatis_plus_auto"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.xiaozhi") // 设置父包名
.moduleName("mybatisplus") // 设置父包模块名
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus"));
// 设置mapperXml生成路径
})
//策略配置
.strategyConfig(builder -> {
builder.addInclude("t_user") // 设置需要生成的表名
.addTablePrefix("t_", "c_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默认的是Velocity引擎模板
.execute();
}
}
运行之,即可生成项目
7.mybatis-X插件生成代码
快速创建一个新的项目
创建yml配置文件application.yml
,存入基础的数据源配置
# 设置数据源类型,数据库信息;
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 数据库密码
driver-class-name: com.mysql.cj.jdbc.Driver
注意将数据库连接
对数据库选择MybatisX构造
配置
生成目录成功