mybatis plus 是基于mybatis 的一个增强包,比 mybatis 更加容易使用。
特点:
1.分页支持
2.支持自定义查询。
3.简单的情况下,不需要写map.xml 文件
4.支持租户过滤
下面介绍一下 它的使用方法
1.引入jar包。
在 pom.xml 增加
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
2.配置使用数据源
spring: datasource: url: jdbc:mysql://localhost:3306/wuxianji?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8 username: root password: root type: com.alibaba.druid.pool.DruidDataSource druid: # 下面为连接池的补充设置,应用到上面所有数据源中 # 初始化大小,最小,最大 initial-size: 5 min-idle: 5 max-active: 20 # 配置获取连接等待超时的时间 max-wait: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 time-between-eviction-runs-millis: 60000 # 配置一个连接在池中最小生存的时间,单位是毫秒 min-evictable-idle-time-millis: 300000 validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false # 打开PSCache,并且指定每个连接上PSCache的大小 pool-prepared-statements: true # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 max-pool-prepared-statement-per-connection-size: 20 filters: stat,wall use-global-data-source-stat: true # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 配置监控服务器 stat-view-servlet: login-username: admin login-password: 123456 reset-enable: false url-pattern: /druid/* # 添加IP白名单 #allow: # 添加IP黑名单,当白名单和黑名单重复时,黑名单优先级更高 #deny: web-stat-filter: # 添加过滤规则 url-pattern: /* # 忽略过滤格式 exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
这里我们使用 druid 作为数据源
3.配置 mybatis plus
mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml global-config: refresh: true # 刷新xml文件 db-config: logic-delete-value: 1 #默认值1 logic-not-delete-value: 0 #默认值0
这里指定了mapper xml 文件的位置。
4. 创建mybatis plus 配置java 文件
package com.example.config; import com.baomidou.mybatisplus.core.injector.ISqlInjector; import com.baomidou.mybatisplus.core.parser.ISqlParser; import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator; import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor; import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler; import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; import net.sf.jsqlparser.expression.LongValue; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; import java.util.ArrayList; import java.util.List; @Configuration @MapperScan("com.example.demo.dao") public class MybatisPlusConfig { @Bean public PerformanceInterceptor performanceInterceptor(){ return new PerformanceInterceptor(); } @Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); } /** * 分页插件 */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor= new PaginationInterceptor(); List<ISqlParser> sqlParserList = new ArrayList<>(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId() { return new LongValue(1L); } @Override public String getTenantIdColumn() { return "tenant_id"; } @Override public boolean doTableFilter(String tableName) { // 这里可以判断是否过滤表 if ("User_".equals(tableName)) { return true; } return false; } }); sqlParserList.add(tenantSqlParser); paginationInterceptor.setSqlParserList(sqlParserList); return paginationInterceptor; } }
这里支持性能分析,逻辑删除,租户过滤,物理分页。
5.下面以一个操作一个用户表为例,介绍一下 具体的用法。
5.1 创建一个用户表
CREATE TABLE `user_` ( `id_` bigint(11) NOT NULL DEFAULT '0', `name_` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, `address` varchar(100) DEFAULT NULL, `isDelete` int(11) DEFAULT NULL, PRIMARY KEY (`id_`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
5.2 创建对应的User.java类
package com.example.demo.model; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; @TableName(value = "User_") public class User { @TableId(value="id_") private Long id; @TableField(value="name_") private String name; private Integer age; private String address; @TableLogic @TableField(value="isDelete") private Integer isDelete; }
这里去掉了get 和 set 方法。
5.3 创建 DAO操作数据库
package com.example.demo.dao; import com.example.demo.model.*; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.Map; public interface UserMapper extends BaseMapper<User> { int updName(Map<String,Object> params); }
这个类继承了 BaseMapper 接口,自动有增查改删操作。
5.4 开始测试
1.列表查询
private UserMapper userMapper; //@Test public void testSelect() { System.out.println(("----- selectAll method test ------")); List<User> userList = userMapper.selectList(null); Assert.assertEquals(5, userList.size()); userList.forEach(System.out::println); }
2.增加用户
public void add() { User user=new User(); user.setId(14L); user.setName("关羽"); user.setAge(12); userMapper.insert(user); }
3.更新实体对象
public void upd() { User user=new User(); user.setId(13L); user.setName("zyg"); user.setAge(13); userMapper.updateById(user); }
4.自定义条件更新
public void updWrap() { User user=new User(); user.setAddress("广州"); user.setAge(23); userMapper.update(user,new UpdateWrapper<User>().eq("name_","a").or().eq("name_","b")); }
这个意思是他会根据姓名 为 a 或 b 的用户更新他的地址和年龄字段。
5.根据 MAP 传值更新
public void updName() { Map<String,Object> params=new HashMap<>(); params.put("id",14); params.put("name","趙雲"); int i= userMapper.updName(params); System.err.println(i); }
这里我们需要在 User.xml 中增加
<update id="updName" parameterType="java.util.HashMap"> update user_ set name_=#{name} where id_=#{id} </update>
也需要在UserMapper 内中增加方法
int updName(Map<String,Object> params);
6.分页获取数据
public void getPage(){ Page<User> page = new Page<>(1, 5); IPage<User> userIPage = userMapper.selectPage(page, null); System.err.println(userIPage.getRecords()); }
这个需要配合MybatisPlusConfig 的分页配置,才可以生效。
7.当分页返回的数据不是 User 对象时,我们可以返回 Map对象。
public void getPageMap(){ Page page = new Page<>(1, 5); Wrapper wrapper=new QueryWrapper(); ((QueryWrapper) wrapper).ge("id_",2); IPage<Map<String,Object>> userIPage = userMapper.selectMapsPage(page,wrapper); System.err.println(userIPage.getRecords()); }
这里我们查询Id_ 大于 2的用户分页列表。
8.逻辑删除用户
如果平台中数据不需要做实际删除,我们可以配置逻辑删除
配置方法如下:
MybatisPlusConfig 中指定了
@Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
配置这个就支持逻辑删除
application.yml配置如下:
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
refresh: true # 刷新xml文件
db-config:
logic-delete-value: 1 #默认值1
logic-not-delete-value: 0 #默认值0
这里指定逻辑删除 删除标记 为1 表示删除 为0 表示正常。
User 对象 需要指定
@TableLogic
@TableField(value="isDelete")
指定逻辑删除字段。
删除代码
public void delById(){ userMapper.deleteById(1L); }
这样我们执行这个删除时,后端并不执行删除操作。
Time:9 ms - ID:com.example.demo.dao.UserMapper.deleteById
Execute SQL:UPDATE User_ SET isDelete = 1 WHERE id_ = 1 AND isDelete = 0
后端执行的语句为 将 删除标记更新为1
9.分页配置根据租户查询。
需要配置
List<ISqlParser> sqlParserList = new ArrayList<>(); TenantSqlParser tenantSqlParser = new TenantSqlParser(); tenantSqlParser.setTenantHandler(new TenantHandler() { @Override public Expression getTenantId() { return new LongValue(1L); } @Override public String getTenantIdColumn() { return "tenant_id"; } @Override public boolean doTableFilter(String tableName) { // 这里可以判断是否过滤表 if ("User_".equals(tableName)) { return true; } return false; } }); sqlParserList.add(tenantSqlParser); paginationInterceptor.setSqlParserList(sqlParserList);
1.指定租户ID字段
2.返回租户ID值
@Override public Expression getTenantId() { return new LongValue(1L); }
3.允许表过滤
有些表是不需要通过租户过滤的,可以修改方法
@Override public boolean doTableFilter(String tableName) { // 这里可以判断是否过滤表 if ("User_".equals(tableName)) { return true; } return false; }
10.乐观锁支持
乐观锁的原理是,每一条数据都带有一个版本。
比如当前都版本为1.
在更新数据时,会将版本加一进行更新,如果A 进行更新,那么这个时候版本变为 2,如果B 同A一起发起更新,那么这个时候就更新不到,给出提示。
配置方法:
@Version private Integer version;
User 类中增加一个字段 为 version
配置增加乐观锁
@Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
编写更新代码
public void upd() { User user=new User(); user.setId(13L); user.setName("zyg"); user.setAge(13); user.setVersion(1); if( userMapper.updateById(user)>0){ System.err.println("更新成功"); } else { System.err.println("被其他人更新"); } }
执行上面的代码
Time:7 ms - ID:com.example.demo.dao.UserMapper.updateById Execute SQL:UPDATE User_ SET name_ = 'zyg', age = 13, version = 2 WHERE id_ = 13 AND version = 1
这里我们可以看到他会自动将版本字段加1,如果执行成功就变成了2,当第二个人执行更新的时候,还是用版本1 进行更新,数据就更新不到了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)