Mybatis Plus基础
1、mybatis-主键生成策略
自动增长 :AUTO Increment(不方便分表操作)
- UUID:每次生成随机唯一值(排序不方便)
-
redis实现
mp自带策略
snowflake算法(雪花算法)
2、修改主键策略
-
在主键上加上@TableId注解
-
属性 作用 INPUT 设置id值 NONE 不用任何策略 AUTO 自动增长 ASSIGN_ID mp自带策略 ASSIGN_UUID 随机唯一值
3、mybatis plus实现自动填充
-
mp实现修改操作
public void updateUser(){ User user = new User(); user.setId(2L); user.setAge(222); int i = userMapper.updateById(user); System.out.println(i); }
-
自动填充功能,在日期时间字段实体类上加入注解@TableFile()
@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
-
添加一个类,实现MetaObjectHandler接口,通过接口中的两个方法实现自动填充
-
@Component
public class MetaHandler implements MetaObjectHandler {
/**
* 使用mp实现添加操作,这个方法执行
* */
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
//属性名称
//属性值
//metaObject源数据
}
/**
* 使用mp实现更新操作,这个方法执行
* */
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、乐观锁:解决某些问题
-
主要解决,丢失更新
- 如果不考虑事务隔离性,产生读问题?
- 脏读
- 不可重复读
- 幻读
- 写问题:丢失更新问题
- 如果不考虑事务隔离性,产生读问题?
-
多个人同时修改同一条记录,最后提交的把之前提交的数据覆盖掉,这个过程就是丢失更新
-
解决方式
- 悲观锁:串行
- 例如:你在电视上看新闻联播,当你在看的时候,全国其他人民都不能看(不怎么恰当,但生动得解释了悲观锁)
- 乐观锁(通过版本号实现)
- 实现方式
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,则执行失败
- 实现方式
- 悲观锁:串行
**所有人都可以看到这张票,但只有最快的人才能支付成功**
- 实现乐观锁得步骤
- 创建version字段,后端加入version得实体类
/**
* 版本号
* */
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
- 编写乐观锁插件
@EnableTransactionManagement
@Configuration
@MapperScan("com.test.mapper")
public class MybatisPlusConfig {
/**
* 乐观锁插件
* */
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
return new OptimisticLockerInnerInterceptor();
}
}
测试乐观锁
- 需要先查询比较,再修改
public void testoptimisticLocker(){
//根据id查询数据
User user = userMapper.selectById(1320996203066904578L);
//修改
user.setAge(220);
int i = userMapper.updateById(user);
System.out.println("更新数目:" + i);
}
5、mp简单查询
-
查询所有信息
public List<User> findall(){ List<User> list = userMapper.selectList(null); return list; }
-
通过id查询单个数据
public List<User> findall(){ List<User> list = userMapper.selectList(null); return list; }
-
通过多个id批量查询
//通过id批量查询 @Test public void testSelecteByIds(){ List<User> userList = userMapper.selectBatchIds(Arrays.asList(1,2,3)); userList.forEach(System.out::println); }
6、简单条件查询
-
map(selectByMap)
//简单条件查询 public void testSelectByMap(){ HashMap<String,Object> map = new HashMap<>(); map.put("name","wukai"); map.put("age",21); List<User> userList = userMapper.selectByMap(map); System.out.println(userList); }
7、分页查询
- mybatisplus 3.4.0 已经舍弃了分页插件,可以直接使用Page
public void page(){
//创建page对象
//传入两个参数:当前页 和 每页显示记录数
Page<User> page = new Page<>(1,3);
//调用mp分页插叙你的方法
//八分也苏偶偶数据分装到page页中
userMapper.selectPage(page,null);
System.out.println("Current" + page.getCurrent());//获取当前页
System.out.println("Records"+page.getRecords());//每页得list集合
System.out.println("Size"+page.getSize());//每页显示记录数
System.out.println("ToTal" + page.getTotal());//得到总记录数
System.out.println("Pages" + page.getPages());//得到总页数
System.out.println(page.hasNext());//是否有下一页
System.out.println(page.hasPrevious());//是和否有上一页
}
打印示例:
8、逻辑删除
逻辑删除:假删除,将对应数据中代表是否被i删除字段状态修改为“被删除状态”,之后再数据库中仍旧能看到此条记录。
物理删除:真删除,将对应数据从数据库中删除,之后查询不到此条被删除数据。
-
在表中添加一个字段用来表示数据已删除,不进行页面显示
物理删除
- 通过id删除单个记录
public void delete(){ int i = userMapper.deleteById(1320984165531795458L); System.out.println(i); }
- 通过id列表批量删除
public void deleteIds(){ int i = userMapper.deleteBatchIds(Arrays.asList(1320979355583754242L, 1320986922254987266L)); System.out.println(i); }
- 简单的条件删除
public void deleteMap(){ HashMap<String,Object> map = new HashMap(); map.put("id",1320996203066904578L); map.put("name","测试2"); int deleteByMap = userMapper.deleteByMap(map); System.out.println(deleteByMap); }
逻辑删除
在表中加入一个用于判断是否删除的字段
在实体类是中封装这个字段
-
在这个字段上面加入@TableLgoic注解
@TableLogic @TableField(fill = FieldFill.INSERT) private Integer delete;
-
在application.properties加入配置(此为默认配置,可以不写)
#逻辑删除了的字段值为0 mybatis-plus.global-config.db-config.logic-delete-field=0 #没有逻辑删除的字段为1 mybatis-plus.global-config.db-config.logic-not-delete-value=1
-
配置插件(3.1.1版本以下需要,以上不需要)
@Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); }
9、性能分析插件
- 加上插件
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//ms,超过此处设置的ms则sql不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
10、条件查询
最常用的是QueryWrapper:Entity独享封装操作类,不是lambda语法
public void QueryWapper(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); //两个参数,字段名称和对应的值 wrapper.eq("id", 3); List<User> userList = userMapper.selectList(wrapper); System.out.println(userList); }
底层sql语句
参数 | 说明 | 语法 |
---|---|---|
eq | 等于 | wrapper.eq("id", 3) |
ne | 不等于 | wrapper.ne("id", 3) |
gl | 大于 | wrapper.gl("id", 3) |
gt | 大于等于 | wrapper.gt("id", 3) |
lt | 小于< | wrapper.lt("id", 3) |
le | 小于等于 | wrapper.le("id", 3) |
between | 在。。。之间 | wrapper.between("id",12,18) |
like | 模糊查询 | wrapper.like("name","吴") |
orderByDesc | 根据参数排序 | wrapper.orderByDesc("id") |
last | 在失去了语句最后拼接 | wrapper.last("lamit 1") |
select | 查询指定的列 | wrapper.select("id","name") |
代码生成器
-
带入依赖
<!-- TODO velocity 模板引擎, Mybatis Plus 代码生成器需要 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>${velocity.version}</version> </dependency>
2、代码生成器
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("Auther");//作者
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.AUTO); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/db1?serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("edu"); //模块名
pc.setParent("net.wds");
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("edu_teacher");
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}