mybatis plus代码生成请参考:https://blog.csdn.net/qq_35573689/article/details/105828867
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.0
com.baomidou
mybatis-plus-boot-starter
3.2.0
com.baomidou
mybatis-plus-extension
3.2.0
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件,没有这个的话,属性total会为0,配置上就可以赋上值
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* mybatis plus 乐观锁插件配置,配置会生效
*/
@Bean
public OptimisticLockerInterceptor optimisticLoker(){
return new OptimisticLockerInterceptor();
}
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wxj.bootmq.genecode.bo.Course;
import com.wxj.bootmq.genecode.dao.CourseMapper;
import com.wxj.bootmq.genecode.service.CourseService;
import com.wxj.bootmq.myannotion.resannotion.annotion.RestApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;
/**
*
* 前端控制器
*
*
* @author wxj
* @since 2020-04-26
* mybatis 两种分页,一种是物理分页,一种是逻辑分页(内存分页)
*
*/
@RestController
@RequestMapping("/mybatisplus")
public class CourseController {
@Autowired
private CourseService courseService;
@Autowired
private CourseMapper courseMapper;
/**
* mybatis plus物理分页
*/
@GetMapping("/courseTruePage")
@RestApi
public IPage getCoursePage(){
QueryWrapper queryWrapper = new QueryWrapper<>();
Page page = new Page<>(1,5);
IPage iPage = courseMapper.selectPage(page, queryWrapper);
System.out.println("查询到的结果数为:"+iPage.getRecords().size());
int size = iPage.getRecords().size();
return iPage;
}
}
updateById就不解释了,演示一下update(Obect object,Wrapper wrapper)方法(非全字段更新,全字段更新比较简单不说明):
@RestController
@RequestMapping("/score")
public class ScoreController {
@Autowired
ScoreMapper scoreMapper;
@GetMapping("/myscore")
public IPage getScore(){
Page page = new Page<>(1,5);
IPage page1 = scoreMapper.selectPage(page, null);
return page1;
}
/**
* 更新score,验证乐观锁@version的作用
*/
@PutMapping("/myscore1")
public void updateScore(@RequestBody Score score) throws InterruptedException {
UpdateWrapper updateWrapper = new UpdateWrapper<>();
/**
* 第一种更新写法
* 下面这种写法会全字段更新 UPDATE score SET score=?, stu_id=?, course_id=?, score=? WHERE (stu_id = ? AND course_id = ?)
*/
//updateWrapper.set("score",score.getScore()).eq("stu_id",score.getStuId()).eq("course_id",score.getCourseId());
//int update = scoreMapper.update(score, updateWrapper);
/**
* 第二种写法
* UPDATE score SET score=? WHERE (stu_id = ? AND course_id = ?)
*/
/* updateWrapper.eq("stu_id",score.getStuId()).eq("course_id",score.getCourseId());
Score tempScore = new Score();
tempScore.setScore(score.getScore());
int update = scoreMapper.update(tempScore, updateWrapper);*/
/**
* 第三种写法
*
*/
LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(Score::getStuId,score.getStuId()).eq(Score::getCourseId,score.getCourseId());
//UPDATE score SET score=?, stu_id=?, course_id=? WHERE (stu_id = ? AND course_id = ?)
//int update = scoreMapper.update(score, lambdaUpdateWrapper);
Score score1 = new Score();
score1.setScore(score.getScore());
//UPDATE score SET score=? WHERE (stu_id = ? AND course_id = ?)
int update = scoreMapper.update(score1, lambdaUpdateWrapper);
System.out.println("更新分数后结果是"+update);
}
}
/**
* mybatis plus 乐观锁插件配置,配置会生效
*/
@Bean
public OptimisticLockerInterceptor optimisticLoker(){
return new OptimisticLockerInterceptor();
}
字段上使用@Version 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
//@ApiModel(value="Score对象", description="")
public class Score implements Serializable {
private static final long serialVersionUID=1L;
private String stuId;
private String courseId;
private Integer score;
@Version
private Integer version;
}
在上面update代码打断点或者在线程休眠的时候去修改数据库值,修改数据会失败。此外不要尝试把业务字段作为乐观锁,比如我原来想把score最为业务字段修改,结果第一次可以修改成功,后面就会有问题
什么是多租户——多租户是一种系统架构技术,在多个系统用户同时使用并保持数据隔离。简单说就是,多个系统或者多个用户例如不同的医院对接了同一个平台,这些医院的业务可以使用相同的表,用一个标识来分离/隔离数据。
数据隔离三种方案和优缺点:
独立数据库:为每个用户提供一个数据库,数据库隔离级别高,安全性好,但是很明显成本高,维护成本也高
共享数据库、隔离数据架构:多个用户使用同一个数据库,但是每个租户对应一个Schema(数据库user)
共享数据库、共享数据架构:使用相同数据库并使用同一个schema,只需要在业务表中配合添加租户Id字段。共享数据程度最高。
mybatis plus 为我们提供了第三种数据隔离的简单实现方法:
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件,没有这个的话,属性total会为0,配置上就可以赋上值
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
//分页只需要用到下面的返回
//return new PaginationInterceptor();
/**
* 配置租户先关内容
*/
//创建分页插件
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
//创建sql解析器集合
List sqlParserList = new ArrayList<>();
//创建租户sql解析器
TenantSqlParser tenantSqlParser = new TenantSqlParser();
//设置租户处理器
tenantSqlParser.setTenantHandler(new TenantHandler() {
@Override
public Expression getTenantId(boolean where) {
//设置当前租户id,项目中可能是从前端传入,获取从缓存或cookie中获取
return new StringValue("wxj");
}
@Override
public String getTenantIdColumn() {
//tenant_id 是数据库租户字段
return "tenant_id";
}
@Override
public boolean doTableFilter(String tableName) {
//是否需要过滤某一张表
/* List tableNameList = Arrays.asList("stu");
if(tableNameList.contains(tableName)){
return true;
}*/
return false;
}
});
sqlParserList.add(tenantSqlParser);
paginationInterceptor.setSqlParserList(sqlParserList);
return paginationInterceptor;
}
/**
* mybatis plus 乐观锁插件配置,配置会生效
*/
@Bean
public OptimisticLockerInterceptor optimisticLoker(){
return new OptimisticLockerInterceptor();
}
}
在数据库表中添加上字段tenant_id,否则查询的时候会报错。到现在所有表的查询都会根据租户id查询。但是有些表我们是不需要进行过滤的,所以要进行排除。可以在Mapper类上或者方法上加上注解@SqlParser(filter = true)即可。例如:
@SqlParser(filter = true)
public interface CourseMapper extends BaseMapper {
}