多线程
1、MybatisPlus简介
MybatisPlus
MyBatisPlus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。

2、入门案例环境准备
入门案例
需求:基于资料中提供的mp-demo项目;改造为使用MP实现下列功能:

导入需要的项目,导入需要的数据库表,修改yaml文件的数据库连接信息。
3、快速入门
- MyBatisPlus官方提供了starter,其中继承了Mybatis和MybatisPlus的所有功能,并且实现了自动装配效果。

代码演示:
XML
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
- 自定义的Mapper继承MybatisPlus提供的BaseMapper接口:

代码演示:
java
public interface UserMapper extends BaseMapper<User> {
}
代码演示:
java
@SpringBootTest
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
User user = new User();
user.setId(5L);
user.setUsername("Lucy");
user.setPassword("123");
user.setPhone("18688990011");
user.setBalance(200);
user.setInfo("{\"age\": 24, \"intro\": \"英文老师\", \"gender\": \"female\"}");
user.setCreateTime(LocalDateTime.now());
user.setUpdateTime(LocalDateTime.now());
userMapper.insert(user);
}
@Test
void testSelectById() {
User user = userMapper.selectById(5L);
System.out.println("user = " + user);
}
@Test
void testQueryByIds() {
List<User> users = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));
users.forEach(System.out::println);
}
@Test
void testUpdateById() {
User user = new User();
user.setId(5L);
user.setBalance(20000);
userMapper.updateById(user);
}
@Test
void testDeleteUser() {
userMapper.deleteById(5L);
}
}
对于多表查询,与复杂查询,利用手动写SQL执行。
4、常见注解
常见注解
MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。

- 类名驼峰转下划线作为表名;
- 名为id的字段作为主键;
- 变量名驼峰转下划线作为表的字段名。
MybatisPlus中比较常见的几个注解如下:


5、常见配置
常见配置
MyBatisPlus的配置继承了MyBatis原生配置和一些自己特有的配置。例如:

6、条件构造器-QueryWrapper
条件构造器
MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。
sql
SELECT * FROM products;
UPDATE products SET price=99.9 WHERE id = 3
INSERT INTO products VALUES(3,12,1.2);
DELETE FROM name where ID = 4;
代码演示:
java
//查询user表的id,username,info,balance信息,且username带有o,balance>= 1000的信息
@Test
public void testQueryWrapper1(){
//创建条件构造器
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//查询的列
queryWrapper.select("id","username","info","balance");
//查询条件:名字带"o"的
queryWrapper.like("username","o");
//查询条件:balance >= 1000
queryWrapper.ge("balance","1000");
//查询
List<User> userList = userMapper.selectList(queryWrapper);
//输出
for (User user : userList) {
System.out.println(user);
}
}
//更新用户名为jack的用户的余额为2000
@Test
public void testQueryWrapperUpdate(){
User user = new User();
user.setBalance(2000);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username","jack");
userMapper.update(user,queryWrapper);
}
7、条件构造器-UpdateWrapper&LambdaQueryWrapper
基于UpdateWrapper的更新
需求:更新id为1,2,4的用户的余额,扣200.
代码演示:
java
// 需求:更新id为1,2,4的用户的余额,扣200.
@Test
public void testUpdateWrapper(){
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//自定义更新的语句,设置的是set
updateWrapper.setSql("balance = balance - 200");
//id为1,2,4的用户
updateWrapper.in("id",1,2,4);
userMapper.update(null,updateWrapper);
}
代码演示:
java
@Test
public void testLambdaQueryWrapper1(){
//创建条件构造器
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//查询的列
lambdaQueryWrapper.select(User::getId,User::getUsername,User::getInfo,User::getBalance);
//查询条件:名字带"o"的
lambdaQueryWrapper.like(User::getUsername,"o");
//查询条件:balance >= 1000
lambdaQueryWrapper.ge(User::getBalance,1000);
//查询
List<User> userList = userMapper.selectList(lambdaQueryWrapper);
//输出
for (User user : userList) {
System.out.println(user);
}
}
8、自定义Sql
自定义SQL
我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。
需求:将id在指定范围的用户(例如1、2、4)的余额扣减指定值

代码演示:
java
//自定义拼接SQL
@Test
public void testCustomSqlSeqment(){
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.in(User::getId,1L,2L,4L);
userMapper.updateBalanceByWrapper(200,lambdaQueryWrapper);
}
java
public interface UserMapper extends BaseMapper<User> {
@Update("update user set balance = balance - ${amount} ${ew.customSqlSegment}")
void updateBalanceByWrapper(@Param("amount") int amount, @Param("ew") LambdaQueryWrapper<User> queryWrapper);
}
9、Service接口-接口与类编写
Service接口

10、Service接口-案例基础
案例 基于Restful风格实现下列接口
需求:基于Restful风格实现下面的接口:


步骤:
- 引入起步依赖

- 定义UserController

- 新增业务方法
特殊的业务方法,mybatisPlus中没有提供的;则可以自定义编写。
代码演示:
java
@Api("用户接口管理")
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor //添加注释,不用添加@Autowired
public class UserController {
private final IUserService userService;
@ApiOperation("新增用户")
@PutMapping
public void saveUser(@RequestBody UserFormDTO userFormDto){
//将userFormDto转换为User
User user = BeanUtil.copyProperties(userFormDto, User.class);
userService.save(user);
}
@ApiOperation("删除用户")
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable("id") Long id){
userService.removeById(id);
}
}
11、Service接口-扣减余额

代码演示:
java
/**
* 根据id扣减余额
* @param id 用户id
* @param amount 扣减的金额多少
*/
@ApiOperation("根据id扣减余额")
@PutMapping("/{id}/deduction/{amount}")
public void updateBalanceById(@PathVariable Long id, @PathVariable Integer amount){
userService.deductBalanceById(id,amount);
}
private final UserMapper userMapper;
@Override
public void deductBalanceById(Long id, Integer amount) {
//1、判断用户是否存在
User user = this.getById(id);
if(user == null || user.getStatus() == 2){
throw new RuntimeException("用户有问题");
}
//2、判断余额是否充足 ,当前用户的余额是否大于等于要扣除的金额
if(user.getBalance() < amount){
throw new RuntimeException("余额不足");
}
//3、扣减金额
//update user set balance = balance - #{amount} where id = #{id}
userMapper.deduceBalanceById(amount,id);
}
@Update("update user set balance = balance - #{amount} where id = #{id}")
void deduceBalanceById(Integer amount, Long id);
12、IService的LambdaQuery方法应用
需求:

代码演示:
java
@ApiOperation("根据条件查询用户列表")
@PostMapping("/list")
public List<UserVO> queryList(@RequestBody UserQuery userQuery){
String username = userQuery.getName();
Integer status = userQuery.getStatus();
Integer maxBalance = userQuery.getMaxBalance();
Integer minBalance = userQuery.getMinBalance();
List<User> userList = userService.lambdaQuery()
.like(StrUtil.isNotBlank(username), User::getUsername, username)
.eq(status != null, User::getStatus, status)
.ge(minBalance != null, User::getBalance, minBalance)
.le(maxBalance != null, User::getBalance, maxBalance)
.list(); //最终进行查询
return BeanUtil.copyToList(userList, UserVO.class);
}
13、IService的LambdaUpdate方法应用
案例IService的Lambda更新

代码演示:
java
//3、扣减金额
//update user set balance = balance - #{amount} [,status = 2] where id = #{id}
int remainBalance = user.getBalance() - amount;
this.lambdaUpdate()
.set(User::getBalance, remainBalance)
.set(remainBalance == 0, User::getStatus, 2)
.eq(User::getId, id)
.update();
14、批量插入数据的优化
案例:IService批量新增

代码演示:
java
//批量新增十万条数据
@Test
public void testBatch(){
//记录开始时间与结束时间
long start = System.currentTimeMillis();
List<User> list = new ArrayList<>(1000);
for(int i = 1; i <= 100000; i++) {
list.add(buildUser(i));
if(i % 1000 == 0){
userService.saveBatch(list);
list.clear();
}
}
//记录技术时间
long end = System.currentTimeMillis();
System.out.println(end - start);
}