MybatisPlus一个自动完成基本CRUD对Mybatis的增强框架。主流同类有JPA、tk-mapper。
开始使用
步骤:
1.导入依赖
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--Lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
注意:不要同时导入mybatis和mybatisplus,或版本冲突。
2.编写配置
3.编码
(没有使用mybatisPlus:连接数据库、编写dao-service-controller)
(使用mybatisPlus:编写pojo、mapper接口、使用)
注意:需要在主启动类中扫描mapper下的所有接口。@MapperScan(“com.hx.mybatis_plus.dao”)
4.编写测试类
–问题:mybatisPlus帮我们写好了sql,和方–
配置日志
#mybatis-plus配置
mybatis-plus:
configuration:
log-impl:org.apache.ibatis.logging.stdout.StdOutImpl#使用默认的控制台输出
CRUD扩展
主键生成策略
UUID,自增id,雪花算法,redis生成,zookeeper生成
数据库主键的值,必须为唯一的id
雪花算法
分布式系统唯一id生成方案汇总
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。
几乎可以保证全球唯一!
@TableId(type=?)IdType
默认ID_WORKER是全局唯一id
主键自增
1.我们需要配置自增主键(数据库字段一定是要自增的)
2.实体类字段上@TableId(type=IdType.AUTO)
publicenumIdType{
AUTO(0),//自增
NONE(1),//无
INPUT(2),//手动输入
ID_WORKER(3),//默认全局id
UUID(4),//全局iduuid
ID_WORKER_STR(5);//id_worker的字符串表示法
}
#更新操作
==>Preparing:UPDATEuserSETname=?,age=?,email=?WHEREid=?
==>Parameters:嘻嘻(String),19(Integer),[email protected](String),1(Long)
<==Updates:1b
这里mybatisPlus会自动的拼接动态sql
自动填充
一般的创建时间,修改时间希望数据库自动填充,而不是手动的填充。
阿里开发手册:所有的数据库表都需要具备gmt_create,gmt_modified。几乎所有的表都需要配置
1.数据库级别的
不建议在工作中使用这种方式。
1.在表中新增字段create_time,update_time
##2.代码级别的
1.为实体类加上属性,并添加注解
@TableField(fill=FieldFill.INSERT)
privateStringcreateTime;
@TableField(fill=FieldFill.INSERT_UPDATE)
privateStringupdateTime;
2.编写处理器来处理这个注解。
乐观锁&悲观锁
原子引用。
乐观锁:总是认为不会出现问题,不加锁。若出现问题则再次更新值测试。
悲观锁:悲观的认为总会出现问题,无论什么都加锁。
乐观锁实现机制:
1.取记录时,获取当前version
2.更新时带上version
3.执行更新时,setversion=newVersionwhereversion=oldVersion
4.ifversion不对,则更新失败
步骤
1.给数据库加上字段version(int)
2.实体加属性与注解
@Version
privateintversion;
3.扫描注册组件
@EnableTransactionManagement//默认也是开启的
@Configuration//配置类
//扫描mapper所在的文件夹
@MapperScan("com.hx.mybatis_plus.dao")
publicclassMybatisPlusConfig{
//注册一个乐观锁插件
@Bean
publicOptimisticLockerInterceptoroptimisticLockerInterceptor(){
returnnewOptimisticLockerInterceptor();
}
}
测试
//测试乐观锁成功
@Test//在单线程情况下是可以成功的
voidtestOptimisticLockerSuccess(){
Useruser=userMapper.selectById(1L);
user.setName("Huathy-"+newDate().getTime());
userMapper.updateById(user);
}
控制台输出结果
==>Preparing:UPDATEuserSETname=?,age=?,email=?,version=?,update_time=?WHEREid=?ANDversion=?
==>Parameters:Huathy1608825571198(String),19(Integer),[email protected](String),2(Integer),2020-12-2423:59:31.227(Timestamp),1(Long),1(Integer)
<==Updates:1
//测试乐观锁失败
@Test
voidtestOptimisticLockerFailed(){
//线程1操作
Useruser=userMapper.selectById(1L);
user.setName("Huathy-"+newDate().getTime());
//模拟线程2执行插队操作
Useruser2=userMapper.selectById(1L);
user2.setName("Huathy-"+newDate().getTime());
userMapper.updateById(user2);
//可以利用自旋锁来多次尝试提交
userMapper.updateById(user);
}
查询操作
@Test//多id查询
voidtestSelectByBatchIds(){
List<User>users=userMapper.selectBatchIds(Arrays.asList(1,2,3));
users.forEach(System.out::println);
}
@Test//多条件查询
voidtestSelectByMap(){
Map<String,Object>map=newHashMap<>();
map.put("name","嘻嘻");
map.put("age",18);
List<User>users=userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页插件
1.原始的limit分页
2.pageHelper分页
3.MP内置分页插件分页
使用步骤
1.导入拦截器组件
//分页插件
@Bean
publicPaginationInterceptorpaginationInterceptor(){
returnnewPaginationInterceptor();
}
2.测试分页查询
@Test
voidtestPageSelect(){
//当前页,页面大小
Page<User>page=newPage<>(1,5);
IPage<User>userIPage=userMapper.selectPage(page,null);
userIPage.getRecords().forEach(System.out::println);
}
删除操作
@Test
voidtestDeleteById(){
intres=userMapper.deleteById(3L);
System.out.println(res);
}
@Test
voidtestDeleteBatchIds(){
intres=userMapper.deleteBatchIds(Arrays.asList(4L,5L));
System.out.println(res);
}
@Test
voidtestDeleteByMap(){
Map<String,Object>map=newHashMap<>();
map.put("name","嘻嘻1");
intres=userMapper.deleteByMap(map);
System.out.println(res);
}
逻辑删除
物理删除:直接的从数据库中删除。
逻辑删除:通过标识字段标识此记录失效。
步骤:
1.创建数据库字段deleted,并在实体类中加上字段
@TableLogic//逻辑删除标识
privateIntegerdeleted;
2.配置逻辑删除组件
@Bean//逻辑删除组件
publicISqlInjectorsqlInjector(){
returnnewLogicSqlInjector();
}
3.配置逻辑删除值
global-config:
db-config:
logic-delete-value:1
logic-not-delete-value:0
4.测试删除
@Test
voidtestDeleteById(){
intres=userMapper.deleteById(3L);
System.out.println(res);
}
//输出日志:
==>Preparing:UPDATEuserSETdeleted=1WHEREid=?ANDdeleted=0
==>Parameters:3(Long)
<==Updates:1
5.再次测试查询,检查是否能够查到数据
@Test
voidtestSelectById(){
Useru=userMapper.selectById(3L);
System.out.println(u);
}
//输出日志
==>Preparing:SELECTid,name,age,email,version,create_time,update_time,deletedFROMuserWHEREid=?ANDdeleted=0
==>Parameters:3(Long)
<==Total:0
性能分析插件
开发中可能存在一些慢查询。可以通过测试(压力测试),druid分析。MP也提供了性能分析插件。
若超过一定的时间就停止运行。
##使用步骤
导入插件->测试使用
作用:性能分析拦截器,用于输出每条sql语句及其执行时间
1.配置yml为开发环境
#设置springboot当前为开发环境
spring:
profiles:
active:dev
@Bean
@Profile({"dev","test"})
publicPerformanceInterceptorperformanceInterceptor(){
PerformanceInterceptorperformanceInterceptor=newPerformanceInterceptor();
//设置sql执行的最大时间ms
performanceInterceptor.setMaxTime(100);
//开启格式化支持
performanceInterceptor.setFormat(true);
returnperformanceInterceptor;
}
wapper条件构造器。条件查询
wapper用法:
wapper.isNotNull("coloum")//非空
wapper.ge("coloum",valObj)//大于等于
示例:
@Test
voidselectTest(){
//查询name和email不为空的参数且年龄>18
QueryWrapper<User>queryWrapper=newQueryWrapper<>();
queryWrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",18);
userMapper.selectList(queryWrapper).forEach(System.out::println);
}