史上最简单的mybatis-plus快速入门
mybatis-plus快速入门
介绍:
Mybatis-Plus(简称MP)是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发,提高效率而生。
数据库表:
-- 创建表CREATE TABLE tbl_employee( id INT(11) PRIMARY KEY AUTO_INCREMENT, last_name VARCHAR(50), email VARCHAR(50), gender CHAR(1), age INT);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@atguigu.com',1,22);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@atguigu.com',0,25);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@atguigu.com',1,30);INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@atguigu.com',0,35);
一:实体类的配置
mybatis-plus常用的实体类注解
@TableName:对数据表名注解@TableId:表主键标识@TableId(value = "id", type = IdType.AUTO):自增@TableId(value = "id", type = IdType.ID_WORKER_STR):分布式全局唯一ID字符串类型@TableId(value = "id", type = IdType.UUID):32位UUID字符串@TableField:表字段标识@TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。@Version:乐观锁注解、标记@EnumValue:通枚举类注解@TableLogic:表字段逻辑处理注解(逻辑删除)
@Data@AllArgsConstructor@NoArgsConstructor@TableName("tbl_employee")public class Employee { @TableId(value = "id",type= IdType.AUTO) private Integer id; @TableField("last_name") private String lastName; private String email; private Integer gender; private Integer age;}
二:增删查改的实现
让编写的mapper接口继承BaseMapper接口
/** * 基于Mybatis‐plus实现: 让XxxMapper接口继承 BaseMapper接口即可. * BaseMapper : 泛型指定的就是当前Mapper接口所操作的实体类类型 */@Repositorypublic interface EmployeeMapper extends BaseMapper<Employee> { }
测试:
@SpringBootTest@RunWith(SpringRunner.class)public class EmployeeMapperTest { @Autowired private EmployeeMapper employeeMapper; @Test public void select(){ Object o = employeeMapper.selectById(1); System.out.println(o); } @Test public void insert(){ Employee employee = new Employee(null, "xushu", "dasda", 1, 211); employeeMapper.insert(employee); } @Test public void update(){ Employee employee = new Employee(4, "xushu", "dasda", 1, 211); employeeMapper.updateById(employee); } @Test public void delete(){ Employee employee = new Employee(4, "xushu", "dasda", 1, 211); int i = employeeMapper.deleteById(4); } @Test public void selectList(){ HashMap<String, Object> objectObjectHashMap = new HashMap<>(); objectObjectHashMap.put("gender",1); List<Employee> employees = employeeMapper.selectByMap(objectObjectHashMap); System.out.println(employees); }}
三:条件构造器Wrapper
(1)Wrapper :条件构造抽象类,最顶端父类,抽象类中提供3个方法以及其他方法.
(2)AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件,QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
(3)AbstractLambdaWrapper : Lambda 语法使用 Wrapper统一处理解析 lambda 获取 column。 (4)LambdaQueryWrapper :看名称也能明白就是用于Lambda语法使用的查询Wrapper (5)LambdaUpdateWrapper : Lambda 更新封装Wrapper
(6)QueryWrapper : Entity 对象封装操作类,不是用lambda语法,自身的内部属性 entity 也用于生成 where 条件 该类的重要方法:
具体用法请查该地址:mybatis-plus条件构造器
样例:
@Test public void selectWrapper(){ QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper. between("age",18,30); List<Employee> list = employeeService.list(wrapper); System.out.println(employeeService.list(wrapper)); } @Test public void updateWrapper(){ UpdateWrapper<Employee> wrapper = new UpdateWrapper<>(); wrapper.set("last_name","wang").eq("id",1); boolean update = employeeService.update(wrapper); System.out.println(update); selectWrapper(); } // 使用lambda表达式查询 @Test public void lambdaSelect(){ QueryWrapper<Employee> wrapper = new QueryWrapper<>(); wrapper.lambda() .select(Employee::getLastName,Employee::getAge) .eq(Employee::getLastName,"wang"); System.out.println(employeeService.list(wrapper)); }
四:全局id生成策略
在yaml文件中使用配置
mybatis-plus: configuration: // 开启驼峰命名法 map-underscore-to-camel-case: true global-config: db-config: // 设置全局的主键自增,不需要给每一个都配置 id-type: auto
测试样例
@Test public void insertWrapper(){ Employee employee = new Employee(null,"hei","dasd",1,32); employeeService.save(employee); System.out.println(employee); }
五:MyBatis-Plus逻辑删除
物理删除: 在删除的时候直接将数据从数据库干掉DELTE
逻辑删除: 从逻辑层面控制删除,通常会在表里添加一个逻辑删除的字段比如 enabled 、is_delete ,数据默认是有效的(值为1), 当用户删除时将数据修改UPDATE 0, 在查询的时候就只查where enabled=1.
方法一:在数据库中增加一个判断是否删除的字段
@TableLogic() private Integer enabled;
mybatis-plus对于是否删除的默认判断:0是未删除,1是已删除
由于不太符合常用的规则,可以自定义是否删除的标志
/** * 未删除的数据为1,已删除的数据为0 */ @TableLogic(value = "1",delval = "0") private Integer enabled;
方法二:在yaml文件中配置是否删除
mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto logic-delete-field: enabled #判断是否删除的字段,逻辑删除的字段 logic-not-delete-value: 1 #没有删除1 logic-delete-value: 0 #已删除是0
六:MyBatis-Plus自动填充
在表中添加 create_date和modify_date两个字段,如何做到自动填充数据
方法一:不建议使用
设置create_date、modify_date的默认值为CURRENT_TIMESTA-MP
方法二:使用mybatis-plus带的注解@TableField
// 创建时间,希望在添加数据的时候填充:当前时间 @TableField(value = "create_date",fill = FieldFill.INSERT) private Date createDate; // 修改时间:希望在修改数据和添加数据的时候填充 @TableField(value = "modify_date",fill = FieldFill.INSERT_UPDATE) private Date modifyDate;
添加一个配置类MyMetaObjectHandler
用于设置填充的时间
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 插入时:创建时间和修改时间 this.setFieldValByName("createDate",new Date(),metaObject); this.setFieldValByName("modifyDate",new Date(),metaObject); } @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("modifyDate",new Date(),metaObject); }}
七:MyBatis-Plus执行SQL分析打印
SQL分析打印:可以查看SQL的执行时间,最大的好处时显示除mybatis执行的sql的具体语句
样例:
2022-04-16 18:31:17.425 DEBUG 22096 --- [ main] c.e.q.mapper.EmployeeMapper.update: ==> Parameters: black(String), 2055(String), 1(Integer), 98(Integer), 2022-04-16 18:31:16.959(Timestamp), 10(Integer) Consume Time:351 ms 2022-04-16 18:31:17 Execute SQL:UPDATE tbl_employee SET last_name='black', email='2055', gender=1, age=98, modify_date='2022-04-16T18:31:16.959+0800' WHERE enabled=1 AND (id = 10)
第一步:添加依赖
<dependency> <groupId>p6spy</groupId> <artifactId>p6spy</artifactId> <version>3.9.1</version> </dependency>
第二步:更改yaml中的配置
将url和driver-class-name更改
spring: datasource: url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC username: root password: root driver-class-name: com.p6spy.engine.spy.P6SpyDriver type: com.alibaba.druid.pool.DruidDataSource
第三步:添加一个spy.properties文件
#3.2.1以上使用modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory#3.2.1以下使用或者不配置#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory# 自定义日志打印logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger#日志输出到控制台appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger# 使用日志系统记录 sql#appender=com.p6spy.engine.spy.appender.Slf4JLogger# 设置 p6spy driver 代理deregisterdrivers=true# 取消JDBC URL前缀useprefix=true# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.excludecategories=info,debug,result,commit,resultset# 日期格式dateformat=yyyy-MM-dd HH:mm:ss# 实际驱动可多个#driverlist=org.h2.Driver# 是否开启慢SQL记录outagedetection=true# 慢SQL记录标准 2 秒outagedetectioninterval=2
注意!driver-class-name 为 p6spy 提供的驱动类url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址打印出 sql 为 null,在 excludecategories 增加 commit批量操作不打印 sql,去除 excludecategories 中的 batch批量操作打印重复的问题请使用 MybatisPlusLogFactory (3.2.1 新增)该插件有性能损耗,不建议生产环境使用。
八:MyBatis-Plus乐观锁
第一:什么是乐观锁 悲观锁:
悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事 务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。 假设功能并发量非常大,就需要使用synchronized
来处理高并发下产生线程不安全问题, 会使其他线程进行挂起等待从 而影响系统吞吐量 。
乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突
,所以在数据进行提交更新的时候,才会正 式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场 景,这样可以提高程序的吞吐量。 假设功能产生并发几率极少,采用乐观锁版本机制对比, 如果有冲突 返回给用户错 误的信息
1.mybatis的配置
@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor;}
2在实体类的字段上加上@Version注解
@Versionprivate Integer version;
样例:
@Test public void testCAS(){ // 线程1 age50 version1 Employee employee1 = employeeService.getById(1); // 线程2 age50 version 1 Employee employee2 = employeeService.getById(1); employee1.setAge(100); employee2.setAge(50); System.out.println(employeeService.updateById(employee1)); System.out.println(employeeService.updateById(employee2)); }
九:MyBatis-Plus分页
直接在启动类中增加就可
@Configuration@MapperScan("scan.your.mapper.package")public class MybatisPlusConfig { /** * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); }}
xml文件配置
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.quickstart.mapper.EmployeeMapper"> <select id="getByGender" resultType="com.example.quickstart.pojo.Employee"> SELECT * FROM tbl_employee </select> <select id="selectAll" resultType="com.example.quickstart.pojo.Employee"> SELECT * FROM tbl_employee </select></mapper>
mapper层(持久层)
/** * 基于Mybatis‐plus实现: 让XxxMapper接口继承 BaseMapper接口即可. * BaseMapper : 泛型指定的就是当前Mapper接口所操作的实体类类型 */@Repositorypublic interface EmployeeMapper extends BaseMapper<Employee> { IPage<Employee> getByGender(IPage page); List<Employee> selectAll();}
样例测试
@Test public void xmlPage(){ IPage<Employee> iPage = new Page<>(5,1); IPage<Employee> page = employeeMapper.getByGender(iPage); System.out.println(page.getSize()); List<Employee> records = page.getRecords(); System.out.println(page.getPages()); System.out.println(records); }
测试:
@Test public void page(){ IPage<Employee> iPage = new Page<>(1,3); IPage<Employee> page = employeeImplService.page(iPage); List<Employee> records = page.getRecords(); for (Employee record: records){ System.out.println(record); } System.out.println(page.getPages()); }