今天完成了MyBatis-Plus(以下简称MP)的学习,深入了解了MP的特性和使用方式
1、主键生成策略
自动增长 AUTO INCREMENT
缺陷:分表操作需要考虑到上张表的最后一个id值是多少
UUID 每次生成随机唯一的值
缺陷:排序不方便
Redis原子操作
MP自带策略 snowflake算法
使用41bitz作为毫秒数,10bit作为机器的id(5个bit是数据中心,5个bit的机器id),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个id),最后还有一个符号位,永远是0
MP可以自定义id生成规则,在主键字段上面添加@TableId
注解即可,方式如下:
AUTO:自动增长
ID_WORKER:MP自带的策略,生成19位数值,数字类型使用这种策略,比如long
ID_WORKER_STR:MP自带的策略,生成19位数值,字符串类型使用这种策略
INPUT:设置id值,需要自己输入
NONE:没有策略,也是需要自己输入
UUID:随机策略
注:不写注解的话会自动识别字段类型,分配合适的自带策略
2、自动填充
1、表添加字段
create_time
update_time
2、添加实体类属性
传统添加时间的方式:
@Test
public void addUser() {
User user = new User();
user.setName("Lucy");
user.setAge(21);
user.setEmail("[email protected]");
user.setCreateTime(new Date());
user.setUpdateTime(new Date());
int result = userMapper.insert(user);
System.out.println("成功入库条数:" + result);
}
具体实现过程:
(1)在实体类里面进行自动填充属性添加注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
(2)创建类,实现接口MetaObjectHandler里面的方法
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 使用mp实现添加操作,这个方法执行
*/
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(), metaObject);
this.setFieldValByName("updateTime",new Date(), metaObject);
}
/**
* 使用mp实现修改操作,这个方法执行
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(), metaObject);
}
}
此时即可不设置updateTime和createTime的值完成数据自动填充
@Test
public void addUser() {
User user = new User();
user.setName("Lucy");
user.setAge(21);
user.setEmail("[email protected]");
int result = userMapper.insert(user);
System.out.println("成功入库条数:" + result);
}
3、乐观锁
主要解决 丢失更新问题
如果不考虑事务隔离性,产生读的问题:
脏读
不可重复读
幻读
如果不考虑事务隔离性,产生写的问题:
丢失更新问题:多个人同时操作同一条记录,最后提交的把之前提交的覆盖
解决方案:
1.悲观锁:串行,只能一个人进行操作,操作完后面的人才能进行操作,缺点是效率低下
2.乐观锁:提交事务的同时通过比较版本号,来实现数据操作,第一个人拿着1的版本号进行更新操作,操作完版本号变为2,第二个人此时也拿着1的版本号进行操作,提交事务的时候版本号对不上,操作失败;
实现MP乐观锁:
1、添加version字段
2、User实体类添加version属性
@Version
@TableField(fill = FieldFill.INSERT_UPDATE)
private Integer version;
3、配置乐观锁插件
@Configuration
@MapperScan("com.project.mpdemo.mapper")
public class MpConfig {
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
配置完执行新增和更新操作就会自动生成和更新版本号
/**
* 测试乐观锁
*/
@Test
public void OptimisticLocker() {
User user = userMapper.selectById(1283695307099598850L);
user.setAge(22);
int result = userMapper.updateById(user);
System.out.println("成功更新条数:" + result);
}
4、MP分页操作
1、添加分页插件配置
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2、编写分页代码
/**
* 测试分页查询
*/
@Test
public void pageSelect() {
Page page = new Page(1,4);
userMapper.selectPage(page, null);
List userList = page.getRecords();
for(User user : userList) {
System.out.println(user);
}
System.out.println(page.getCurrent()); //当前页
System.out.println(page.getSize()); //每页显示记录数
System.out.println(page.getTotal()); //总记录数
System.out.println(page.getPages()); //总页数
System.out.println(page.hasNext());
System.out.println(page.hasPrevious());
}
5、MP逻辑删除实现
逻辑删除用于删除操作后,页面查询不到,但数据依然存在于数据库里,通过删除标记位实现
1、数据库添加标记位字段
2、实体类添加标记位属性,并添加逻辑删除注解
@TableLogic
private Integer deleted;
3、配置逻辑删除插件(如果默认配置跟MP一样的话则不需要)
#逻辑删除枚举值
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4、添加删除标记位枚举值配置
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
5、测试
@Test
public void delUser() {
int result = userMapper.deleteById(1283681589426958338L);
System.out.println("成功删除数据条数:" + result);
}
6、MP性能分析插件
性能分析拦截器,用于输出每条SQL语句及其执行时间
SQL性能执行分析,开发环境使用,超过执行时间,停止运行。有助于发现问题
1、配置性能分析插件
/**
* 性能分析插件
*
* 三种环境
* dev 开发环境
* test 测试环境
* prod 生产环境
*/
@Bean
@Profile({"dev","test"})
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//ms,超过此处设置的SQL不执行
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
2、SpringBoot中设置dev环境
spring.profiles.active=dev
3、执行测试
4、打印结果
7、MP实现复杂条件查询
推荐使用QueryWrapper构建查询条件
为什么:QueryWarpper比其父类Wrapper功能更强大(继承关系,字类可以使用父类的方法,父类不能使用子类的)
使用步骤
1、创建QueryWrapper对象
2、调用方法实现各种条件查询
@Test
public void selectQuery() {
QueryWrapper queryWrapper = new QueryWrapper<>();
//通过QueryWrapper设置条件
// ge 大于、gt 大于等于、le 小于、lt 小于等于
queryWrapper.ge("age",20);
List userList = userMapper.selectList(queryWrapper);
//eq 等于、ne 不等于
queryWrapper.eq("name","Kitor");
userList = userMapper.selectList(queryWrapper);
//between
queryWrapper.between("age",10,20);
userList = userMapper.selectList(queryWrapper);
//like
queryWrapper.like("name","Ki");
userList = userMapper.selectList(queryWrapper);
//orderByDesc
queryWrapper.orderByDesc("age","id");
userList = userMapper.selectList(queryWrapper);
//last
queryWrapper.ge("age",30).eq("name","Kitor")
.between("age",10,30).like("name","Ki")
.orderByDesc("age","id");
userList = userMapper.selectList(queryWrapper);
//只查询这些字段
queryWrapper.select("age","name","email");
userList = userMapper.selectList(queryWrapper);
}
总结
通过今天的学习,发现所有的特性依然局限于单表操作(本人一直期待复杂查询的实现),但MP对于单表的特性可以说是史无前例了,几乎涵盖了全部实现方式,不需要再写SQL去进行其他操作,令我比较惊奇的是MP实现复杂条件查询这块,把几乎所有的SQL语法都覆盖进去了,极大地提升了开发效率(这边强吹一波,因为我感觉在Java里写SQL非常非常非常影响代码整体的美观性和整洁性),对比我现在使用的Hibernate,能够有效减少Java穿插SQL的这类情况,各位视而用之,也许MP不能完全满足你的需求,但加上MP你绝对不亏啊