目录
一、MyBatis-Plus简介
1、简介
(简称
MP
)是一个
MyBatis
的增强工具
,在
MyBatis
的基础上
只做增强不做改变
,为
。
MyBatis
最好的搭档,就像魂斗罗中的
1P
、
2P
,基友搭配,效率翻倍。
2、特性
:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
:启动即会自动注入基本
CURD
,性能基本无损耗,直接面向对象操作
CRUD
操作
:内置通用
Mapper
、通用
Service
,仅仅通过少量配置即可实现单表大部分
操作,更有强大的条件构造器,满足各类使用需求
Lambda
形式调用
:通过
Lambda
表达式,方便的编写各类查询条件,无需再担心字段写错
:支持多达
4
种主键策略(内含分布式唯一
ID
生成器
– Sequence
),可自由
ActiveRecord
模式
:支持
ActiveRecord
形式调用,实体类只需继承
Model
类即可进行强
CRUD
操作
:支持全局通用方法注入(
Write once, use anywhere
)
:采用代码或者
Maven
插件可快速生成
Mapper
、
Model
、
Service
、
层代码,支持模板引擎,更有超多自定义配置等您来使用
:基于
MyBatis
物理分页,开发者无需关心具体操作,配置好插件之后,写分页等
List
查询
:支持
MySQL
、
MariaDB
、
Oracle
、
DB2
、
H2
、
HSQL
、
SQLite
、
、
SQLServer
等多种数据库
:可输出
SQL
语句以及其执行时间,建议开发测试时启用该功能,能快速揪出
:提供全表
delete
、
update
操作智能分析阻断,也可自定义拦截规则,预防
3、支持数据库
MyBatis
进行
CRUD,
并且支持标准
SQL
的数据库,具体支持情况如下
,
Oracle
,
DB2
,
H2
,
HSQL
,
SQLite
,
PostgreSQL
,
SQLServer
,
Phoenix
,
Gauss
,
,
Sybase
,
OceanBase
,
Firebird
,
Cubrid
,
Goldilocks
,
csiidb
(
华库
)
数据库,南大通用数据库,神通数据
4、框架结构
5、代码及文档地址
:
http://mp.baomidou.com
:
https://github.com/baomidou/mybatis-plus
https://gitee.com/baomidou/mybatis-plus
:
https://baomidou.com/pages/24112f
二、入门案例
1、创建数据库及表
a>创建表
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
b>添加数据
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
3、创建Spring Boot工程
a>初始化工程
使用 Spring Initializr 快速初始化一个 Spring Boot 工程
b>引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mybatis-plus的启动器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- lombok用于简化实体类的开发-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mysql的驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
4、编写代码
a>配置application.yml
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
username: root
password: woaini520
b>启动类
@SpringBootApplication
//扫描mapper接口所在的包
@MapperScan("com.javastudy.mybatisplus.mapper")
public class Mybatisplus01Application {
public static void main(String[] args) {
SpringApplication.run(Mybatisplus01Application.class, args);
}
}
c>添加实体
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
d>添加mapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
e>测试
@SpringBootTest
public class MybatisPlusTest {
@Autowired
UserMapper mapper;
@Test
public void testSelectList(){
//通过条件构造器查询一个list集合,若没有条件,可以设置null
List<User> users = mapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
结果
f>添加日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
三、基本CRUD
1、BaseMapper
中的基本
CRUD
在内置的
BaseMapper
中都已得到了实现,我们可以直接使用,接口如 下:
2、插入
@Test
/**
* 新增用户信息
*/
public void testInsert() {
//通过条件构造器查询一个list集合,若没有条件,可以设置null
User user = new User();
user.setName("张选宁");
user.setAge(19);
user.setEmail("15641554@qq.com");
System.out.println("id:" + user.getId());
//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
int insert = mapper.insert(user);
System.out.println("产生条数:" + insert);
System.out.println("id:" + user.getId());
}
3、删除
a>通过id删除记录
@Test
public void testDeleteById() {
//通过id删除用户信息
// DELETE FROM user WHERE id=?
int result = mapper.deleteById(1475754982694199298L);
System.out.println("受影响行数:" + result);
}
b>通过id批量删除记录
@Test
public void testDeleteBatchIds(){
//通过多个id批量删除
//DELETE FROM user WHERE id IN ( ? , ? , ? )
List<Long> idList = Arrays.asList(1L, 2L, 3L);
int result = mapper.deleteBatchIds(idList);
System.out.println("受影响行数:"+result);
}
c>通过map条件删除记录
@Test
public void testDeleteByMap() {
//根据map集合中所设置的条件删除记录
//DELETE FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("age", 23);
map.put("name", "张三");
int result = mapper.deleteByMap(map);
System.out.println("受影响行数:" + result);
}
4、修改
@Test
public void testUpdateById(){
User user = new User(4L, "admin", 22, null);
//UPDATE user SET name=?, age=? WHERE id=?
int result = mapper.updateById(user);
}
5、查询
a>根据id查询用户信息
@Test
public void testSelectBatchIds(){
//根据多个id查询多个用户信息
//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
List<Long> idList = Arrays.asList(4L, 5L);
List<User> list = mapper.selectBatchIds(idList);
list.forEach(System.out::println);
}
b>根据多个id查询多个用户信息
@Test
public void testSelectById(){
//根据id查询用户信息
//SELECT id,name,age,email FROM user WHERE id=?
User user = mapper.selectById(4L);
System.out.println(user);
}
c>通过map条件查询用户信息
@Test
public void testSelectByMap(){
//通过map条件查询用户信息
//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("age", 22);
map.put("name", "admin");
List<User> list = mapper.selectByMap(map);
list.forEach(System.out::println);
}
d>查询所有数据
@Test
public void testSelectList(){
//查询所有用户信息
//SELECT id,name,age,email FROM user
List<User> list = mapper.selectList(null);
list.forEach(System.out::println);
}
6、自定义功能
/**
* 根据id查询用户信息为Mapper集合
* @param id
* @return
*/
Map<String,Object> selectMapById(Long id);
<?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.javastudy.mybatisplus.mapper.UserMapper">
<select id="selectMapById" resultType="map">
select id,name,age,email from user where id=#{id};
</select>
</mapper>
@Test
/**
* 测试查询功能
*/
public void testSelect() {
Map<String, Object> map = mapper.selectMapById(1L);
System.out.println(map);
}
结果:
{name=张选宁, id=1, age=19, email=147450@qq.com}
7、通用Service
:
Service CRUD
封装
IService
接口,进一步封装
CRUD
采用
get
查询单行
remove
删
list
查询集合
page
分页
前缀命名方式区分
Mapper
层避免混淆,
T
为任意实体对象
Service
方法的可能,请创建自己的
IBaseService
继承
–
Plus
提供的基类
https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%
a>IService
中有一个接口
IService
和其实现类
ServiceImpl
,封装了常见的业务层逻辑
IService
和
ServiceImpl
b>创建Service接口和实现类
public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
c>测试查询记录数
@Test
public void testGetCount(){
//SELECT COUNT( * ) FROM user
long count = service.count();
System.out.println("总数量:"+count);
}
d>测试批量插入
@Test
public void testInsertMore(){
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("zxn"+i);
user.setAge(20+i);
user.setEmail("147450@qq.com");
users.add(user);
}
//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
boolean b = service.saveBatch(users);
System.out.println(b);
}
四、常用注解
1、@TableName
MyBatis-Plus
实现基本的
CRUD
时,我们并没有指定要操作的表,只是在
接口继承
BaseMapper
时,设置了泛型
User
,而操作的表为
user
表
BaseMapper
的泛型决定,即实体类型决
a>问题
当表名和实体类的类名不一致时,会出现以下问题
b>通过@TableName解决问题
@Data
//设置实体类所对应的表名
@TableName("t_user")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
c>通过全局配置解决问题
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置mybatisplus的全局配置,设置实体类所对应表的统一前缀
global-config:
db-config:
table-prefix: t_
2、@TableId
当作为主键的字段的名字不为id时,加入@TableId将其变为主键
//将属性所对应的字段指定为主键
@TableId
private Long id;
@TableId的value属性
@TableId
的
value
属性,来进行一一对应
@TableId(value = "uid")
private Long id;
@TableId的type属性
默认的为雪花算法
值
|
描述
|
IdType.ASSIGN_ID
(默
认)
|
基于雪花算法的策略生成数据
id ,与数据库 id 是否设置自增无关 |
IdType.AUTO
|
使用数据库的自增策略,注意,该类型请确保数据库设置了
id 自增,
否则无效
|
改变为主键自增
//@TableId注解的type属性设置主键生成策略
@TableId(value = "uid",type = IdType.AUTO)
private Long id;
注意:只在数据库里面将字段设置为主键自增是没有效果的
当我们自己设置了id的值,insert添加数据到表中,是不会用雪花算法的
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置mybatisplus的全局配置,设置实体类所对应表的统一前缀
global-config:
db-config:
table-prefix: t_
#设置统一的主键生成策略
id-type: auto
e>雪花算法
nickname
和
description
字段,假设我们是一个婚恋网站,用户在筛选其他用 户的时候,主要是用 age
和
sex
两个字段进行查询,而
nickname
和
description
两个字段主要用于展 示,一般不会在业务查询中用到。description
本身又比较长,因此我们可以将这两个字段独立到另外 一张表中,这样在查询 age
和
sex
时,就能带来一定的性能提升。
5000
万就必须进行分表,这个数字可以 作为参考,但并不是绝对标准,关键还是要看表的访问性能。对于一些比较复杂的表,可能超过 1000 万就要分表了;而对于一些简单的表,即使存储数据超过 1
亿行,也可以不分表。
id
该如何处理
ID
为例,可以按照
1000000
的范围大小进行分段,
1 ~ 999999
放到表
1
中,
放到表
2
中,以此类推。
万至
2000
万之间,具体需要根据业务选取合适 的分段大小。
100
万,如果增加到
1000
万, 只需要增加新的表就可以了,原有的数据不需要动。
1000
万来进行分表,有可能某个分段实际存储的数据量只有
1
条,而另外一个分段实际存储的数据量有 1000
万条。
ID
为例,假如我们一开始就规划了
10
个数据库表,可以简单地用
user_id % 10
的值来
ID
为
985
的用户放到编号为
5
的子表中,
ID
为
10086
的用户放到编号 为 6
的子表中。
公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的
64bit
(一个
long
型)。
1bit
标识,由于
long
基本类型在
Java
中是带符号的,最高位是符号位,正数是
0
,负数是1
,所以
id
一般是正数,最高位是
0
。
时间截
(
毫秒级
)
,存储的是时间截的差值(当前时间截
–
开始时间截
)
,结果约等于
69.73
年。
作为机器的
ID
(
5
个
bit
是数据中心,
5
个
bit
的机器
ID
,可以部署在
1024
个节点)。
作为毫秒内的流水号(意味着每个节点在每毫秒可以产生
4096
个
ID
)。
②优点:整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高。
3、@TableField
MyBatis-Plus
在执行
SQL
语句时,要保证实体类中的属性名和
a>情况1
userName
,表中字段
user_name
MyBatis-Plus
会自动将下划线命名风格转化为驼峰命名风格
MyBatis
中配置以下:
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
b>情况2
1
name
,表中字段
username
@TableField(“username”)
设置属性所对应的字段名
//指定属性所对应的字段名
@TableField("user_name")
private String name;
4、@TableLogic
a>逻辑删除
“
被删除状态
”
,之后在数据库
b>实现逻辑删除
在表中添加字段is_delete
实体类中添加属性,并加上@TableLogic注解
@TableLogic
private int isDelete;
之后的删除操作变为
UPDATE t_user SET is_delete=1 WHERE uid IN ( ? , ? , ? ) AND is_delete=0
原本
删除之后变为
SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user WHERE is_delete=0
便查不到is_delete为1的数据了
五、条件构造器和常用接口
1、wapper介绍
: 条件构造抽象类,最顶端父类
: 用于查询条件封装,生成
sql
的
where
条件
: 查询条件封装
:
Update
条件封装
: 使用
Lambda
语法
语法使用的查询
Wrapper
更新封装
Wrapper
e>例5:组装select子句
2、QueryWrapper
a>例1:组装查询条件
@Test
public void test01(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
QueryWrapper<User> queryWrapper = wrapper.like("user_name", "宁").
between("age", 15, 30).isNotNull("email");
//SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user
// WHERE is_delete=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
List<User> users = mapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
b>例2:组装排序条件
@Test
public void test02(){
//查询用户信息按照年龄的降序排序,若年龄相同,则按照id升序排序
QueryWrapper<User> wrapper = new QueryWrapper<>();
QueryWrapper<User> userQueryWrapper = wrapper.orderByDesc("age").orderByAsc("uid");
//SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user
// WHERE is_delete=0 ORDER BY age DESC,uid ASC
List<User> users = mapper.selectList(userQueryWrapper);
for (User user : users) {
System.out.println(user);
}
}
c>例3:组装删除条件
@Test
public void test03(){
//删除邮箱的地址为null的用户信息
QueryWrapper<User> wrapper = new QueryWrapper<>();
QueryWrapper<User> queryWrapper = wrapper.isNull("email");
//UPDATE t_user SET is_delete=1 WHERE is_delete=0 AND (email IS NULL)
int delete = mapper.delete(queryWrapper);
System.out.println("删除记录数为:"+delete);
}
d>例4:条件的优先级
@Test
public void test04(){
//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
UpdateWrapper<User> updateWrapper = wrapper.gt("age", 20).like("user_name", "宁")
.or().isNull("email");
User user = new User();
user.setName("小宁子");
user.setAge(18);
//UPDATE t_user SET user_name=?, age=? WHERE is_delete=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)
int update = mapper.update(user, updateWrapper);
System.out.println("更新了条数:"+update);
}
@Test
public void test05(){
//将用户名中包含有"宁"并且(年龄大于20或邮箱为null)的用户信息修改
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
UpdateWrapper<User> updateWrapper = wrapper.like("user_name", "宁").
and(i -> i.gt("age", 20).or().isNull("email"));
User user = new User();
user.setName("张选宁");
user.setAge(20);
//UPDATE t_user SET user_name=?, age=?
// WHERE is_delete=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
int update = mapper.update(user, updateWrapper);
System.out.println("更新了条数:"+update);
}
e>例5:组装select子句
@Test
public void test06(){
//查询用户的用户名、年龄、邮箱信息
QueryWrapper<User> wrapper = new QueryWrapper<>();
QueryWrapper<User> select = wrapper.select("user_name", "age", "email");
List<Map<String, Object>> maps = mapper.selectMaps(select);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
f>例6:实现子查询
@Test
public void test07(){
//查询id小于等于100的用户信息
QueryWrapper<User> wrapper = new QueryWrapper<>();
QueryWrapper<User> queryWrapper = wrapper.inSql("uid", "select uid from t_user where uid<=100");
//SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user
// WHERE is_delete=0 AND (uid IN (select uid from t_user where uid<=100))
List<User> users = mapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
3、UpdateWrapper
@Test
public void test08(){
//将用户名中包含有"宁"并且(年龄大于20或邮箱为null)的用户信息修改
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
UpdateWrapper<User> updateWrapper = wrapper.like("user_name", "宁").
and(i -> i.gt("age", 20).or().isNull("email"));
UpdateWrapper<User> updateWrapper1 = updateWrapper.set("user_name", "刘子").set("age", 19);
//UPDATE t_user SET user_name=?,age=?
// WHERE is_delete=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
int update = mapper.update(null,updateWrapper1);
System.out.println("更新了条数:"+update);
}
4、condition
模拟开发中组装条件的情况
@Test
public void test09(){
String username="";
Integer ageBegin=20;
Integer ageEnd=30;
QueryWrapper<User> wrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(username)){
wrapper.like("user_name", username);
}
if(ageBegin!=null){
wrapper.ge("age",ageBegin);
}
if(ageEnd!=null){
wrapper.le("age",ageEnd);
}
//SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user
// WHERE is_delete=0 AND (age >= ? AND age <= ?)
List<Map<String, Object>> maps = mapper.selectMaps(wrapper);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
使用condition组装条件 ———–>推荐
@Test
public void test10(){
String username="";
Integer ageBegin=20;
Integer ageEnd=30;
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(username),"user_name",username);
wrapper.ge(ageBegin!=null,"age",ageBegin);
wrapper.le(ageEnd!=null,"age",ageEnd);
List<User> users = mapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
5、LambdaQueryWrapper
@Test
public void test11(){
String username="";
Integer ageBegin=20;
Integer ageEnd=30;
LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
userLambdaQueryWrapper.like(StringUtils.isNotBlank(username),User::getName,username);
userLambdaQueryWrapper.ge(ageBegin!=null,User::getAge,ageBegin);
userLambdaQueryWrapper.ge(ageEnd!=null,User::getAge,ageEnd);
List<User> users = mapper.selectList(userLambdaQueryWrapper);
for (User user : users) {
System.out.println(user);
}
}
6、LambdaUpdateWrapper
@Test
public void test12(){
//将用户名中包含有"宁"并且(年龄大于20或邮箱为null)的用户信息修改
LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
LambdaUpdateWrapper<User> updateWrapper = userLambdaUpdateWrapper.like(User::getName, "刘").
and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail));
LambdaUpdateWrapper<User> updateWrapper1 = updateWrapper.set(User::getName, "刘子").set(User::getAge, 21);
//UPDATE t_user SET user_name=?,age=?
// WHERE is_delete=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
int update = mapper.update(null,updateWrapper1);
System.out.println("更新了条数:"+update);
}
六、插件
1、分页插件
自带分页插件,只要简单的配置即可实现分页功能
a>添加配置类
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.javastudy.mybatisplus.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
b>测试
@Test
public void testPage(){
Page<User> userPage = new Page<>(3,3);
//SELECT uid AS id,user_name AS name,age,email,is_delete FROM t_user WHERE is_delete=0 LIMIT ?,?
Page<User> userPage1 = mapper.selectPage(userPage, null);
System.out.println(userPage1.getRecords());
//[User(id=7, name=小宁子, age=18, email=15641554@qq.com, isDelete=0),
// User(id=8, name=刘子, age=19, email=15641554@qq.com, isDelete=0),
// User(id=9, name=刘子, age=21, email=null, isDelete=0)]
System.out.println(userPage1.getPages());//4
System.out.println(userPage1.getTotal());//10
System.out.println(userPage1.hasNext());//true
System.out.println(userPage1.hasPrevious());//true
}
2、xml自定义分页
a>UserMapper中定义接口方法
Page<User> selectVo(@Param("page") Page<User> page,@Param("age") Integer age);
b>UserMapper.xml中编写SQL
<select id="selectVo" resultType="user">
select * from t_user where age>#{age}
</select>
c>测试
@Test
public void testVo(){
Page<User> userPage = new Page<>(1,3);
Page<User> userPage1 = mapper.selectVo(userPage, 20);
List<User> records = userPage1.getRecords();
System.out.println(records);
}
结果
Preparing: select * from t_user where age>? LIMIT ?
==> Parameters: 20(Integer), 3(Long)
<== Columns: uid, user_name, age, email, is_delete
<== Row: 3, 乔浪, 26, 147450@qq.com, 0
<== Row: 4, 李四, 21, 147450@qq.com, 0
<== Row: 5, Billie, 24, test5@baomidou.com, 0
<== Total: 3
3、乐观锁
a>场景
80
元,售价是
100
元。老板先是通知小李,说你去把商品价格增加
50
元。小
150
元,价格太
30
元。
100
元;小王
100
元。小李将价格加了
50
元,并将
100+50=150
元存入了数据
30
元,并将
100-30=70
元存入了数据库。是的,如果没有锁,小李的操作就
70
元,比成本价低
10
元。几分钟后,这个商品很快出售了
1
千多件商品,老板亏
1
b>乐观锁与悲观锁
150
元,这样他会将
120
元存入数据库。
120
元。
c>模拟修改冲突
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, ‘外星人笔记本‘, 100);
添加实体
@Data
public class Product {
private Long id;
private String name;
private Integer price;
private Integer version;
}
添加mapper
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}
测试
@Test
public void test11(){
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李查询到的商品:"+productLi);
//小王查询到的价格
Product productWang = productMapper.selectById(1);
System.out.println("小王查询到的商品:"+productWang);
//小李将商品价格加50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格减30
productWang.setPrice(productWang.getPrice()-30);
productMapper.updateById(productWang);
//老板查询价格
Product productBoos = productMapper.selectById(1);
System.out.println("老板查询到的商品:"+productBoos);
}
最后产生的结果
老板查询到的商品:Product(id=1, name=外星人笔记本, price=70, version=0)
d>乐观锁实现流程
@Data
public class Product {
private Long id;
private String name;
private Integer price;
@Version
private Integer version;
}
@Configuration
//扫描mapper接口所在的包
@MapperScan("com.javastudy.mybatisplus.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//添加分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
@Test
public void test11(){
//小李查询商品价格
Product productLi = productMapper.selectById(1);
System.out.println("小李查询到的商品:"+productLi);
//小王查询到的价格
Product productWang = productMapper.selectById(1);
System.out.println("小王查询到的商品:"+productWang);
//小李将商品价格加50
productLi.setPrice(productLi.getPrice()+50);
productMapper.updateById(productLi);
//小王将商品价格减30
productWang.setPrice(productWang.getPrice()-30);
int result = productMapper.updateById(productWang);
while(result==0){
//操作失败,重试
Product productWang2 = productMapper.selectById(1);
System.out.println("小王查询到的商品:"+productWang2);
productWang2.setPrice(productWang2.getPrice()-30);
result = productMapper.updateById(productWang2);
}
//老板查询价格
Product productBoos = productMapper.selectById(1);
System.out.println("老板查询到的商品:"+productBoos);
}
七、通用枚举
MyBatis-Plus
的通用枚举
a>数据库表添加字段sex
b>创建通用枚举类型
@Getter
public enum SexEnums {
Male(0,"男"),
Female(1,"女");
@EnumValue //将注解所表示的属性值存储到数据库中
private Integer sex;
private String sexName;
SexEnums(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}
c>配置扫描通用枚举
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#设置mybatisplus的全局配置,设置实体类所对应表的统一前缀
global-config:
db-config:
table-prefix: t_
#设置统一的主键生成策略
id-type: auto
#配置类型别名所对应的包
type-aliases-package: com.javastudy.mybatisplus.entity
#扫描通用枚举的包
type-enums-package: com.javastudy.mybatisplus.enums
d>测试
@SpringBootTest
public class MyBatisPlusEnumTest {
@Autowired
UserMapper userMapper;
@Test
public void test01(){
User user = new User();
user.setName("薛子");
user.setAge(18);
user.setEmail("147450@qq.com");
user.setSex(SexEnums.Male);
int insert = userMapper.insert(user);
System.out.println("result:"+insert);
}
}
八、代码生成器
1、引入依赖
<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>
2、快速生成
public class FastAutoGeneratorTest {
public static void main(String[] args) {
FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC",
"root", "woaini520")
.globalConfig(builder -> {
builder.author("Chooker") // 设置作者
//.enableSwagger() // 开启 swagger 模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://mybatis_plus"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.javastudy") // 设置父包名
.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();
}
}
生成的结果
九、多数据源
mybatis_plus
(以前的库不动)与
mybatis_plus_1
(新建),将
库的
product
表移动到
mybatis_plus_1
库,这样每个库一张表,通过一个测试用例
1、创建数据库及表
mybatis_plus_1
和表
product
CREATE
DATABASE `mybatis_plus_1`
/*!40100 DEFAULT CHARACTER SET utf8mb4 */
;use `mybatis_plus_1`;CREATE TABLE
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
product (id, NAME, price)
VALUES
(
1
,
‘
外星人笔记本
‘
,
100
);
删除mybatis_plus库的product表
use mybatis_plus;DROP TABLE
IF EXISTS product;
2、引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
3、配置多数据源
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: woaini520
slave_1:
url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: woaini520
4、创建用户service
public interface UserService extends IService<User> {
}
@Service
@DS("master")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
5、创建商品service
public interface ProductService extends IService<Product> {
}
@Service
@DS("slave_1")
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}
6、测试
@SpringBootTest
class Mybatisplus02ApplicationTests {
@Autowired
UserService userService;
@Autowired
ProductService productService;
@Test
public void test01(){
User byId = userService.getById(1L);
System.out.println(byId);
Product byId1 = productService.getById(1L);
System.out.println(byId1);
}
}
十、MyBatisX插件
为我们提供了强大的
mapper
和
service
模板,能够大大的提高开发效率
MyBatis-Plus
并不能为我们解决所有问题,例如一些复杂的
SQL
,多表
SQL
语句,我们该如何快速的解决这个问题呢,这个时候可
MyBatisX
插件
一款基于
IDEA
的快速开发插件,为效率而生。
插件用法:
https://baomidou.com/pages/ba5b24/
1.生成代码
1.安装
下载安装使用,重启
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
username: root
password: woaini520
配置Mysql
2. 快速生成CRUD
1.先写出关键字
2.选择
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/101086.html