mybatis-plus的基本使用
官网地址
https://baomidou.com/guide/quick-start.html
特性了解
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
mybatis入门案例
依赖添加
<!--mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String stuId;
private String stuName;
private Integer stuSex;
private String stuAddress;
private Integer stuAge;
}
定义Mapper接口
//继承BaseMapper即可获取基础的crud方法,<Student>为传入的对象,查询的结果直接封装为对象
public interface StudentMapper extends BaseMapper<Student> {
}
配置扫描Mapper包
//方式1-->创建MybatisPlusConfig的配置类使用@MapperScan注解扫描包路径
@Configuration
@MapperScan("com.lwp.study.dao")
public class MybatisPlusConfig {
}
//方式2-->启动类添加@MapperScan注解扫描包路径
@SpringBootApplication(exclude = {
//禁用Spring Security
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
@MapperScan("com.lwp.study.dao")
public class StudyApplication {
public static void main(String[] args) {
SpringApplication.run(StudyApplication.class, args);
}
}
测试使用
@SpringBootTest
class StudyApplicationTests {
@Autowired
private StudentMapper studentMapper;
@Test
void contextLoads() throws SQLException {
//Params:queryWrapper – 实体对象封装操作类(可以为 null
List<Student> students = studentMapper.selectList(null);
students.forEach(System.out::println);
}
}
解决驼峰标识解析失败问题
#问题描述:当我们数据库是stuid字段时,实体类定义为stuId驼峰式时,mybatis-plus会从实体解析为stu_id
# 然后去数据库匹配叫stu_id的字段,随后报错,解决方案为关闭驼峰式编码
mybatis-plus:
configuration:
# 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名)
#到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
map-underscore-to-camel-case: false
日志打印
mybatis-plus:
configuration:
#mybatis自带的控制台日志,可使用log4j,需要添加对应依赖
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
实体类注解
主键生成策略
//配置主键生成紫略
@TableId(type= IdType.ASSIGN_ID)
private String stuId;
/**
* IdType取值说明:
AUTO(0), //自增
NONE(1), //不启用
INPUT(2), //自定义输入
ASSIGN_ID(3), //雪花算法
ASSIGN_UUID(4); //UUID算法
*/
自动填充
实体类定义注解
//value="create_time" 因为关闭了驼峰,所以需要指定数据库字段
//fill= FieldFill.INSERT 插入时触发处理
@TableField(value="create_time",fill= FieldFill.INSERT)
private Date createTime;
//fill= FieldFill.INSERT_UPDATE 插入及更新时处理
@TableField(value="update_time",fill= FieldFill.INSERT_UPDATE)
private Date updateTime;
编写handle处理器
@Component
public class MybatisHandle implements MetaObjectHandler {
/**
* 插入元对象字段填充(用于插入时对公共字段的填充)
* @param metaObject – 元对象
*/
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
/**
* 更新元对象字段填充(用于更新时对公共字段的填充)
* @param metaObject – 元对象
*/
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
测试新增和修改
@Test
public void testInsert(){
Student stu=new Student();
stu.setStuName("溪风");
stu.setStuAge(18);
//返回受影响的行数
int resultValue = studentMapper.insert(stu);
//输出填充Id后的对象
System.out.println(stu);
}
@Test
public void testUpdate(){
Student stu=new Student();
stu.setStuId("1414133065828499457");
stu.setStuAge(20);
//返回受影响的行数
int resultValue = studentMapper.updateById(stu);
//输出填充Id后的对象
System.out.println(stu);
}
自动填充时间慢8个小时问题
#修改连接串的serverTimezone指定为Asia/Shanghai解决
url: jdbc:mysql://localhost:3306/lwpstudy?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
乐观锁
简单理解
乐观锁:在做什么事情的时候都十分乐观,总认为不会出问题,无论做什么都不会去上锁,如果出了问题,再次更新值测试
悲观锁:在做什么事情的时候都十分悲观,总认为会出问题,无论干什么都会先上锁,再去操作
添加字段version
@Version //乐观锁注解
private Integer version;
配置插件
@Configuration
@MapperScan("com.lwp.study.dao")
@EnableTransactionManagement //开启事务
public class MybatisPlusConfig {
/**
* 乐观锁处理
* @return
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
更新测试
单线程成功测试
@Test
public void testUpdate(){
Student student = studentMapper.selectById("1414125536583036929");
student.setStuName("魔尊");
studentMapper.updateById(student);
//更新的时候会加上乐观锁字段作为where条件判定,然后没问题再进行修改,自动更新version+1
//UPDATE student SET stuName=?, stuAge=?, version=?, update_time=? WHERE stuId=? AND version=?
}
多线程失败测试
@Test
public void testUpdate(){
//假设A线程拿到数据时还未更新
Student student = studentMapper.selectById("1414125536583036929");
student.setStuName("魔尊");
//B线程拿到数据并且已更新
Student student1 = studentMapper.selectById("1414125536583036929");
student1.setStuName("魔尊1");
studentMapper.updateById(student1);
//A线程更新失败,这个时候需要用到自旋锁
studentMapper.updateById(student);
}