Springboot3+Mybatis3.5
基本框架
环境
springboot3
mysql8+
JDK17
依赖导入
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.5</version>
</dependency>
<!-- springboot3需要使用Mybatisplus3-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!-- 简化操作-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 连接池-->
<dependency>
<groupId>cn.benma666</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.22</version>
</dependency>
配置文件
yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=false
#mysql8需要添加serverTimeZone=GMT%2B8
username: root
password: xxxxxxx
#mybatisplus配置
mybatis-plus:
configuration:
#日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
实体类
java
@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.NONE)
private Long id;
private String name;
private Integer age;
private String mail;
}
-
表明不同有两种方式
-
使用
@TableName
("数据库对应表名") -
如果只是数据库多了前缀------设置全局前缀(慎用)
yamlglobal-config: db-config: table-prefix:
-
-
主键相关
- BP默认使用id变量作为主键
- 如果变量名和数据库字段名不同意,可以使用
@TableId
、@TableField
指定 - BP的键默认使用雪花算法,(不指定Id默认自动生成),如果需要使用自增id,在
@TableId(type = IdType.AUTO)
或者在配置文件中指定mybatis-plus.global-config.db-config.id-type
- 插入对象默认会有主键回显
业务类结构
定义mapper.XXMapper
接口
java
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
- 说明
- BaseMapper提供了默认的单表实现,不需要自己完成
- 如果需要自定义实现可以添加并实现
- 可以在mapper类上使用
@Mapper
或者在启动类上添加@MapperScan("mapper包路径")
,进行mapper接口扫描
基本功能------提供的mapper接口及实现
插入
删除------返回受影响行数
-
更具id删除------雪花算法使用Long类型
-
根据实体类指定id删除
-
根据map删除------指明条件map
javaHashMap<String, Object> condition = new HashMap<>(); condition.put("name","lisi"); condition.put("age",14); int i = userMapper.deleteByMap(condition); System.out.println("return result:"+i); // ==> Preparing: DELETE FROM t_user WHERE (name = ? AND age = ?) // ==> Parameters: lisi(String), 14(Integer) // <== Updates: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@36525ab] // return result:1
-
id列表批量删除
javaList<Long> ids = Arrays.asList(1L, 3L, 4L); int i = userMapper.deleteBatchIds(ids); System.out.println("return result:"+i); // ==> Preparing: DELETE FROM t_user WHERE id IN ( ? , ? , ? ) // ==> Parameters: 1(Long), 3(Long), 4(Long) // <== Updates: 3 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b362f1] // return result:3
-
根据
Wrapper
条件删除
修改数据
-
更具实体类更新
updateById
(id必须有:id确定记录,Entity指定需要修改的字段)javaUser user = new User(); user.setId(1846522555456847874L); user.setMail("hahahha.@163.com"); int i = userMapper.updateById(user); System.out.println("return result:"+i); // ==> Preparing: UPDATE t_user SET mail=? WHERE id=? // ==> Parameters: hahahha.@163.com(String), 1846522555456847874(Long) // <== Updates: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6451a288] // return result:1
-
根据条件构造器选择数据使用实体类对象更新
查询方法
-
根据id查询
-
根据id列表批量查
javaList<Long> ids = Arrays.asList(1846522555456847874L, 1846525211126554626L); List<User> users = userMapper.selectBatchIds(ids); users.forEach(System.out::println); // ==> Preparing: SELECT id,name,age,mail FROM t_user WHERE id IN ( ? , ? ) // ==> Parameters: 1846522555456847874(Long), 1846525211126554626(Long) // <== Columns: id, name, age, mail // <== Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com // <== Row: 1846525211126554626, dearfriend1, 13, null // <== Total: 2 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1850f2da] // User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com) // User(id=1846525211126554626, name=dearfriend1, age=13, mail=null)
-
更具map指定条件查询(只能用=)
javaHashMap<String, Object> condition= new HashMap<>(); condition.put("age",12); List<User> users1 = userMapper.selectByMap(condition); users1.forEach(System.out::println); // ==> Preparing: SELECT id,name,age,mail FROM t_user WHERE (age = ?) // ==> Parameters: 12(Integer) // <== Columns: id, name, age, mail // <== Row: 8, haha, 12, null // <== Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com // <== Total: 2 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3dbb3fb7] // User(id=8, name=haha, age=12, mail=null) // User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com)
-
条件构造器(可为null)
自定义mapper(和mybatis一样)
-
添加xml映射文件路径
mybatis-plus.mapper-locations:
默认为classpath*:/mapper/**/*.xml
-
添加自定义mapper接口:
mapper.UserMapper.java
java@Repository @Mapper public interface UserMapper extends BaseMapper<User> { Map<String,Object> selectMapById(Long id); }
-
实现mapper接口,编写映射文件:
resources.mapper.UserMapper.xml
xml<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace为接口的全限定符--> <mapper namespace="org.dearfriend.mapper.UserMapper"> <!-- 声明sql语句--> <!-- 每个标签为一个接口的实现--> <select id="selectMapById" resultType="map"> select id, name, t_user.age, t_user.mail from t_user where id = #{id} </select> </mapper>
-
调用
javaMap<String, Object> user = userMapper.selectMapById(1846525252671111169L); System.out.println(user); // ==> Preparing: select id, name, t_user.age, t_user.mail from t_user where id = ? // ==> Parameters: 1846525252671111169(Long) // <== Columns: id, name, age, mail // <== Row: 1846525252671111169, dearfriend3, 14, null // <== Total: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@a69f9d] // {name=dearfriend3, id=1846525252671111169, age=14}
相关功能------提供的Service方法
ibatis封装了IService接口和实现,使用如下前缀区分mapper接口
- get------查询
- save------插入
- update------修改
- remove------删除
- list------查询
- page------分页
注:如果存在自定义方法,推荐创建自己的Service,继承BP提供的基类
IService
提供了单表操作的服务层接口Service Impl
提供了IService的实现
Service层搭建
- 创建自定义Service接口,继承IService
- 实现自定义Serivce接口Service Impl实现了基本的接口,直接继承过来,包含两个范型
Service<M,T>
Mapper接口和实体类对象
如此以来,既能使用BP提供的基本服务,也能够自定义服务
相关方法
添加记录
-
批量添加
saveBatch(T t)
------多次调用insert方法进行javaArrayList<User> users = new ArrayList<>(); for (int i = 0; i < 10; i++) { User user = new User(); user.setName("user"+(i+1)); user.setAge(20+i); user.setName("user"+(i+1)+"@163.com"); users.add(user); } boolean b = userService.saveBatch(users); System.out.println("添加状态:"+(b? "success":"fail")); // ==> Preparing: INSERT INTO t_user ( id, name, age ) VALUES ( ?, ?, ? ) // ==> Parameters: 1846548533952438273(Long), user1@163.com(String), 20(Integer) // ==> Parameters: 1846548534006964225(Long), user2@163.com(String), 21(Integer) // ==> Parameters: 1846548534006964226(Long), user3@163.com(String), 22(Integer) // ==> Parameters: 1846548534006964227(Long), user4@163.com(String), 23(Integer) // ==> Parameters: 1846548534006964228(Long), user5@163.com(String), 24(Integer) // ==> Parameters: 1846548534011158530(Long), user6@163.com(String), 25(Integer) // ==> Parameters: 1846548534011158531(Long), user7@163.com(String), 26(Integer) // ==> Parameters: 1846548534011158532(Long), user8@163.com(String), 27(Integer) // ==> Parameters: 1846548534011158533(Long), user9@163.com(String), 28(Integer) // ==> Parameters: 1846548534015352834(Long), user10@163.com(String), 29(Integer) // 添加状态:success
插入或更新(看是否有id)
常用注解
注解 | 作用 |
---|---|
@TableName |
指定绑定实体类对应的mysql表名 |
@TableId |
指定绑定实体类中主键字段,type可以指定主键策略 |
@TableField |
绑定实体类中字段和mysql中字段 |
@TableLogic |
逻辑删除-可以进行数据恢复,加载逻辑删除字段上 |
@Version |
乐观锁版本字段-使用版本好的方式实现乐观锁 |
-
绑定
@TableLogic
后,删除默认为逻辑删除,(修改逻辑删除字段),查询的查询的时候也会自动排除已逻辑删除的记录javaboolean b = userService.removeBatchByIds(Arrays.asList(8L)); System.out.println("删除状态:"+(b?"success":"fail!")); // ==> Preparing: UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0 // ==> Parameters: 8(Long) // 删除状态:success List<User> list = userService.list(); // ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 // ==> Parameters: // <== Columns: id, name, age, mail, is_deleted // <== Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0 // <== Row: 1846525211126554626, dearfriend1, 13, null, 0
条件构造器
类的基本结构
-
Wrapper:条件构造抽象类,最顶端必类
- AbstractWrapper:用于查询条件封装,生成sql的where条件
- QueryWrapper:查询条件封装
- UpdateWrapper:Update条件封装
- AbstractLambdaWrapper:使用Lambda语法
- LambdaQueryWrapper:用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper: Lambda #iT=J%Wrapper
- AbstractWrapper:用于查询条件封装,生成sql的where条件
-
通过条件锁定记录的操作(select、delete、update)------字段都是条件
QueryWrapper
-
条件中有包含更改目标值(update)------
UpdateWrapper
中可以通过set()
设置值
逻辑条件
-
默认为and
-
调用
.or()
,上下条件为||
javaQueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq("age",28) .or() .eq("name","dearfriend"); User user = new User(); user.setMail("123456@123.com"); boolean update = userService.update(user, userQueryWrapper); System.out.println("更新结果:"+(update?"success!":"fail!")); // ==> Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (age = ? OR name = ?) // ==> Parameters: 123456@123.com(String), 28(Integer), dearfriend(String) // == Updates: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@73b0ed03] // 更新结果:success!
-
有优先级的逻辑判断------显式调用
.and()/.or()
,传入的参数为Consumer<Param> consumer
,其实还是一个WrapperjavaQueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.like("name", "a") .and(i -> i.gt("age", 20) .or() .isNull("mail")); List<User> list = userService.list(userQueryWrapper); list.forEach(System.out::println); // // ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR mail IS NULL)) // ==> Parameters: %a%(String), 20(Integer) // <== Total: 0
条件查询------QueryWrapper
注:cloumn字段需要使用数据库表的字段名称,而不是实体类的名称
-
查询指定字段
.select(String... cloumns)
,serivce.listMaps(QueryWrapper wrapper)
javaQueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.select("name","age"); List<Map<String, Object>> maps = userService.listMaps(userQueryWrapper); maps.forEach(System.out::println); // ==> Preparing: SELECT name,age FROM t_user WHERE is_deleted=0 // ==> Parameters: // <== Columns: name, age // <== Row: dearfriend, 12 // <== Total: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@344f9467] // {name=dearfriend, age=12}
-
Like、Between、notNull
java
//用户名包含a,邮箱不为null,年龄(10,30)
QueryWrapper<User> condition = new QueryWrapper<>();
//链式编程,构造条件
condition.like("name","a")
.isNotNull("mail")
.between("age",10,30);
List<User> list = userService.list(condition);
list.forEach(System.out::println);
// ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND mail IS NOT NULL AND age BETWEEN ? AND ?)
// ==> Parameters: %a%(String), 10(Integer), 30(Integer)
// <== Columns: id, name, age, mail, is_deleted
// <== Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0
// <== Total: 1
// Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ec3d8e4]
// User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com, isDeleted=0)
- 排序查询------调用升降序方法,指定排序字段
java
//根据age升序,id降序
QueryWrapper<User> condition = new QueryWrapper<>();
condition.orderByAsc("age")
.orderByDesc("id");
List<User> list = userService.list(condition);
list.forEach(System.out::println);
// ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age ASC,id DESC
// ==> Parameters:
// <== Columns: id, name, age, mail, is_deleted
// <== Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0
// <== Row: 1846525211126554626, dearfriend1, 13, null, 0
// <== Row: 1846525252671111169, dearfriend3, 14, null, 0
// <== Row: 1846548381057470465, user1@163.com, 20, null, 0
// <== Row: 1846548381120385025, user2@163.com, 21, null, 0
// <== Row: 1846548381120385026, user3@163.com, 22, null, 0
// <== Row: 1846548381120385027, user4@163.com, 23, null, 0
// <== Row: 1846548381120385028, user5@163.com, 24, null, 0
// <== Row: 1846548381124579330, user6@163.com, 25, null, 0
// <== Row: 1846548381124579331, user7@163.com, 26, null, 0
// <== Row: 1846548381124579332, user8@163.com, 27, null, 0
// <== Row: 1846548381124579333, user9@163.com, 28, null, 0
// <== Row: 1846548381124579334, user10@163.com, 29, null, 0
// <== Total: 13
- 组装子查询
.insql(cloumn,inval)
------cloumn字段名,inval可以使用sql语句写(里面的内容会直接放入sql语句中,包括明确的值集合,是一个拼接)
删除条件------QueryWrapper
java
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.isNull("mail");
boolean remove = userService.remove(userQueryWrapper);
System.out.println("删除状态:"+(remove? "success!":"fail!"));
// ==> Preparing: UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (mail IS NULL)
// ==> Parameters:
// <== Updates: 12
// Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1ed9d173]
// 删除状态:success!
更新操作
-
queryWrapper+Entity
javaQueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq("age",28) .or() .eq("name","dearfriend"); User user = new User(); user.setMail("123456@123.com"); boolean update = userService.update(user, userQueryWrapper); System.out.println("更新结果:"+(update?"success!":"fail!")); // ==> Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (age = ? OR name = ?) // ==> Parameters: 123456@123.com(String), 28(Integer), dearfriend(String) // == Updates: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@73b0ed03] // 更新结果:success!
-
updateWrapper
(条件+修改值)/updateWrapper
+Entity
javaUpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); // 锁定记录 userUpdateWrapper.isNull("mail"); userUpdateWrapper.set("mail","default@123.com"); boolean update = userService.update(userUpdateWrapper); System.out.println("更新结果:"+(update?"success!":"fail")); // ==> Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (mail IS NULL) // ==> Parameters: default@123.com(String) // <== Updates: 0 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1aeff8ca] // 更新结果:fail
模拟条件组装
-
方式一:Wrapper使用链式编程,可以通过判断+链式条件添加
-
方式二:Wrapper中可以通过方法中的condition指定添加的条件(如果满足指定条件bool类型,才会添加字段限制)
boolean condition, R column, Object val
javaString name=""; Integer age = 14; QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq(!StringUtils.isBlank(name),"name",name) .eq(!ObjectUtils.isEmpty(age),"age",age); List<User> list = userService.list(userQueryWrapper); list.forEach(System.out::println); // ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (age = ?) // ==> Parameters: 14(Integer) // <== Columns: id, name, age, mail, is_deleted // <== Row: 1846525252671111169, dearfriend3, 14, null, 0 // <== Total: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@143413cd] // User(id=1846525252671111169, name=dearfriend3, age=14, mail=null, isDeleted=0)
其他功能
Lamda表达式------防止mysql名称写错,直接使用实体类字段
-
LamdaQuerryWrapper
javaLambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>(); userLambdaQueryWrapper.eq(User::getName,"dearfriend"); List<User> list = userService.list(userLambdaQueryWrapper); list.forEach(System.out::println); // ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name = ?) // ==> Parameters: dearfriend(String) // <== Columns: id, name, age, mail, is_deleted // <== Row: 1846522555456847874, dearfriend, 12, 123456@123.com, 0 // <== Total: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1ed9d173] // User(id=1846522555456847874, name=dearfriend, age=12, mail=123456@123.com, isDeleted=0)
-
LamdaUpdateWrapper
javaLambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>(); userLambdaUpdateWrapper.set(User::getName,"Lambda") .eq(User::getName,"dearfriend"); boolean update = userService.update(userLambdaUpdateWrapper); System.out.println("更新状态:"+(update?"success!":"fail")); // ==> Preparing: UPDATE t_user SET name=? WHERE is_deleted=0 AND (name = ?) // ==> Parameters: Lambda(String), dearfriend(String) // <== Updates: 1 // Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14590fe2] // 更新状态:success!
-
注:主要是在原来的cloumn中使用Lamda表达式使用实体类的方法获取字段,而不是mysql中的列名
分页插件
- 配置分页插件
java
@Configuration
public class BPconfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor();
//设置数据库类型------穿件分页拦截器
mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor1;
}
}
- 分页业务代码
- 方式一:传入Page参数,仅作为查询条件page无法存储记录
java
Page<User> userPage = new Page<>(2,3);
List<User> list = userService.list(userPage, null);
System.out.println(list);
// ==> Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0
// ==> Parameters:
// <== Columns: total
// <== Row: 6
// <== Total: 1
// ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
// ==> Parameters: 3(Long), 3(Long)
// <== Columns: id, name, age, mail, is_deleted
// <== Row: 1846525252671111169, dearfriend3, 14, null, 0
// <== Row: 1846548381057470465, user1@163.com, 20, null, 0
// <== Row: 1846548381120385025, user2@163.com, 21, null, 0
// <== Total: 3
- 方式二:调用
page()
方法,所有记录存在于page对象中、mapper层也提供了selectPage()
方法
java
Page<User> userPage = new Page<>(2,2);
userService.page(userPage, null);
// System.out.println(list);
System.out.println("总页数:"+userPage.getPages());
System.out.println("当前页:"+userPage.getCurrent());
System.out.println("-------------------------------");
System.out.println("本页记录为:");
userPage.getRecords().forEach(System.out::println);
System.out.println("总记录数:"+userPage.getTotal());
System.out.println("-------------------------------");
System.out.println("是否有下一页"+userPage.hasNext());
System.out.println("是否有上一页"+userPage.hasPrevious());
// ==> Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0
// ==> Parameters:
// <== Columns: total
// <== Row: 6
// <== Total: 1
// ==> Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
// ==> Parameters: 2(Long), 2(Long)
// <== Columns: id, name, age, mail, is_deleted
// <== Row: 1846525211126554626, dearfriend1, 13, null, 0
// <== Row: 1846525252671111169, dearfriend3, 14, null, 0
// <== Total: 2
// Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70485aa]
// 总页数:3
// 当前页:2
// -------------------------------
// 本页记录为:
// User(id=1846525211126554626, name=dearfriend1, age=13, mail=null, isDeleted=0)
// User(id=1846525252671111169, name=dearfriend3, age=14, mail=null, isDeleted=0)
// 总记录数:6
// -------------------------------
// 是否有下一页true
// 是否有上一页true
- 自定义mapper结构的分页实现
接口定义------传入Page类型参数
java
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
/*自定sql语句分页查询*/
Page<User> selectPageV(@Param("page") Page<User> page, @Param("age") Integer age);
}
接口实现使用别名指定User,需要添加别名配置mybatis-plus.type-aliases-package: 包名
java
<select id="selectPageV" resultType="User">
select t_user.id,t_user.age,t_user.name,t_user.mail
from t_user
where age > #{age}
</select>
方法调用
java
@Test
public void testSelfPage(){
Page<User> userPage = new Page<>(1,3);
userMapper.selectPageV(userPage,10);
userPage.getRecords().forEach(System.out::println);
}
乐观锁和悲观锁
-
悲观锁:一方操作资源,其他人全部阻塞
-
乐观锁:此处通过版本号实现,每次修改查询版本号,修改后版本号改变,操作失败;操作成功,更改值,更改版本号+1
-
mybatis-plus实现乐观锁
-
添加version字段使用@Version注解(还是需要自己实现循环的业务代码判断重试)
-
插件配置类配置乐观锁插件
java@Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor(); //设置数据库类型------穿件分页拦截器 mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //添加乐观锁插件 mybatisPlusInterceptor1.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor1; }
-
通用枚举
-
数据库中添加存储枚举数据的字段(就使用普通的类型,枚举类有多个属性选择一个存储)
-
创建枚举类,实体类添加枚举类属性
java@Data @TableName("t_user") public class User { @TableId(type = IdType.NONE) private Long id; private String name; private Integer age; private String mail; // 指定的逻辑删除存储字段 @TableLogic private Integer isDeleted; @Version private Integer version; private Sex sex; @Getter public enum Sex{ MALE(1,"男"), FEMALE(2,"女"); @EnumValue private final Integer code; private final String sexName; Sex(int code, String sexName) { this.code = code; this.sexName = sexName; } } }
注:需要在枚举类中使用
@EnumValue
在需要保存的到数据库中的枚举类属性上方进行注解(低版本的BP还要在配置文件中指定枚举类位置mybatis-plus.type-aliases-package------当前版本以弃用)
代码生成器
3.5.1以上代码生成器------此处使用的版本3.5.5
3.5.1以下版本代码生成器
-
依赖的导入
xml<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.5</version> </dependency>
-
根据自己的需要,选择对应的生成模版(),还可以选择生成方式(快速生成、交互式生成)
文件时时模版javaimport com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.config.rules.DbColumnType; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.sql.Types; import java.util.Collections; //相关依赖 // <!--BP代码生成依赖--> // <dependency> // <groupId>com.baomidou</groupId> // <artifactId>mybatis-plus-generator</artifactId> // <version>3.5.5</version> // </dependency> // <!--生成模版依赖--> // <dependency> // <groupId>org.freemarker</groupId> // <artifactId>freemarker</artifactId> // <version>2.3.33</version> // </dependency> //--------------------------------------- public class ${ClassName} { public static void main(String[] args) { // 1.配置数据库连接 FastAutoGenerator.create("${mysqlurl}", "${username}", "${passworld}") .globalConfig(builder -> { builder.author("${author}") // 设置作者 .enableSwagger() // 开启 swagger 模式 //2.指定输出目录 .outputDir("$file_out_dir"); // 指定输出目录 }) .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> { int typeCode = metaInfo.getJdbcType().TYPE_CODE; if (typeCode == Types.SMALLINT) { // 自定义类型转换 return DbColumnType.INTEGER; } return typeRegistry.getColumnType(metaInfo); }) ) .packageConfig(builder -> // 3.指定父包目录 builder.parent("${groupId}") // 设置父包名 // 4.指定模块目录 .moduleName("${artifactId}") // 设置父包模块名 // 5.指定xml映射文件目录 .pathInfo(Collections.singletonMap(OutputFile.xml, "${file_out_dir}")) // 设置mapperXml生成路径 ) // 策略配置 .strategyConfig(builder -> // 6.指定需要生成的表 builder.addInclude("${table_name}") // 设置需要生成的表名 .addTablePrefix("t_", "c_") // 设置过滤表前缀 ) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }
MybatisX插件
-
能够自动跳转mapper接口和映射文件
-
能够自动生成代码
-
自动生成CRUD操作(包括xml的sql映射)
多数据源官网
-
依赖导入
xml<!--spring-boot 1.5.x 2.x.x--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${version}</version> </dependency> <!--spring-boot3及以上--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot3-starter</artifactId> <version>${version}</version> </dependency>
-
配置数据源
yamlspring: datasource: dynamic: enabled: true #启用动态数据源,默认true primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 grace-destroy: false #是否优雅关闭数据源,默认为false,设置为true时,关闭数据源时如果数据源中还存在活跃连接,至多等待10s后强制关闭 datasource: master: url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置 slave_1: url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave_2: url: ENC(xxxxx) # 内置加密,使用请查看详细文档 username: ENC(xxxxx) password: ENC(xxxxx) driver-class-name: com.mysql.jdbc.Driver #......省略 #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
-
使用
@DS
指定操作的数据库
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。注解 结果 没有@DS 默认数据源 有@DS("dsName") dsName可以为组名也可以为具体某个库的名称
适用场景
存粹多库、读写分离、一主多从、混合模式
相关概念
雪花算法
分布式主键生成算法,能够保证不同表的主键不重复,相同表的有序性(有利于索引)
核心思想
- 长度为64bit------Long类型
- 结构
- 第一位:符号位
- 2-42(41bit): 时间戳(当前时间-开始时间)
- 43-52(10bit): 机器id(5bit数据中心,5bit机器id)(可以部署在1024个节点)
- 53-64(12 bit): 毫秒内的流水号(每毫秒可以产生4096个id)
优点
整体上按照时间自增排序,并且整个分布式系统内不会发生id碰撞,且效率高