MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。有意愿的可以去官方文档学习。
目录
MyBatis-Plus AutoGenerator自动生成代码
MyBatis-Plus CRUD接口
MyBatis-Plus AbstractWrapper条件构造器
MyBatis-Plus 分页插件
MyBatis-Plus Sequence主键
MyBatis-Plus 自定义ID生成器
MyBatis-Plus 逻辑删除
MyBatis-Plus 通用枚举
一、AutoGenerator
AutoGenerator代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
1.准备数据
CREATE TABLE `user` (
`id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'id\r\n身份标识号',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`gender` varchar(6) DEFAULT NULL COMMENT '性别',
`age` varchar(3) DEFAULT NULL COMMENT '年龄',
`email` varchar(25) DEFAULT NULL COMMENT '邮箱',
`address` varchar(255) DEFAULT NULL COMMENT '住址',
`nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`account` varchar(50) DEFAULT NULL COMMENT '账号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2.依赖
MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖
<!-- mybatisplus自动生成orm代码三件套 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<!--Freemarker模板引擎-->
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!--MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl三种模板,但springboot1.4版本以上不再支持velocity-->
<!-- <dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.1</version>
</dependency>-->
<!-- <dependency>
<groupId>com.ibeetl</groupId>
<artifactId>beetl-framework-starter</artifactId>
<version>1.2.10.RELEASE</version>
</dependency>-->
3.配置和执行AutoGenerator 代码生成器
@Slf4j
public class MysqlGenerator {
public static void main(String[] args) {
//全局策略配置
GlobalConfig config = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
config.setActiveRecord(true)
//作者注释
.setAuthor("LeeJack")
//输出路径
.setOutputDir(projectPath + "/mybatis-plus-autogenerator/src/main/java")
//覆盖已有文件,默认false
.setFileOverride(true)
//是否打开输出目录窗口。默认true
.setOpen(false)
//是否在xml中添加二级缓存配置。默认false
//.setEnableCache(true)
//开启kotlin模式,默认false
//.setKotlin(false)
//开启swagger2模式
.setSwagger2(true)
//开启ActiveRecord模式
.setActiveRecord(true)
//mapper添加restMap
.setBaseResultMap(true)
//mapper添加Base_Column_List
.setBaseColumnList(true)
//时间类型对应策略,默认time_pack
//.setDateType(DateType.TIME_PACK)
.setMapperName("%sDao")
.setServiceName("%sService")
.setServiceImplName("%sServiceImpl");
//.setIdType(IdType.ASSIGN_ID)
//数据源配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL)
.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai")
.setUsername("root")
.setPassword("root");
//数据库信息查询类,默认由dbType类型决定,实现IDbQuery接口可自定义数据库查询sql
//.setDbQuery()
//不知道干嘛的,官网写的是public,我改成其他都没有发现变化
//.setSchemaName("private")
//内置转换类型,默认由dbType类型决定。可实现或重写实现了 IColumnType 接口的类,自定义转换为自己需要的 java 类型
//.setTypeConvert(new MySqlTypeConvert())
//数据库表配置,通过该配置,可指定需要生成哪些表或者排除哪些表
StrategyConfig strategyConfig = new StrategyConfig();
//是否大写命名
strategyConfig.setCapitalMode(true)
//是否跳过视图
.setSkipView(true)
//数据库表映射到实体的命名策略
.setNaming(NamingStrategy.underline_to_camel)
//数据库表字段映射到实体的命名策略,未指定按照naming执行
//.setColumnNaming(NamingStrategy.no_change)
//生成表
.setInclude("operate_log", "user")
.setEntityBuilderModel(true)
.setEntityLombokModel(true)
.setRestControllerStyle(true)
.setEntityTableFieldAnnotationEnable(true);
//包名配置
PackageConfig packageConfig = new PackageConfig();
//父包名
packageConfig.setParent("com.ljj")
.setMapper("dao")
.setService("service")
.setController("controller")
.setEntity("entity")
.setXml("mapper");
//自定义模板配置
//TemplateConfig templateConfig = new TemplateConfig();
//templateConfig.setEntity("/templates/entity.java");
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setGlobalConfig(config)
.setStrategy(strategyConfig)
.setDataSource(dataSourceConfig)
.setTemplateEngine(new FreemarkerTemplateEngine())
.setPackageInfo(packageConfig);
autoGenerator.execute();
log.info("=============代码生成成功================");
}
}
二、CRUD接口
引入mybatis-plus(MP)依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!-- mybatis-plus现在最新版 -->
<!-- <dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.3.0</version>
</dependency>-->
<!-- mybatisplus-mysql-druid 数据持久化三件套 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
配置
application.yml
spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.druid.username=root
spring.datasource.druid.password=root
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
logging.level.com.ljj.dao=debug
在springboot启动类添加@MapperScan
@MapperScan("com.ljj.dao")
entity
@Data
@ToString
@Builder
public class User {
private String id;
private String realName;
private String gender;
private String age;
private String email;
private String address;
private String nickName;
private String account;
private String password;
}
使用
MP提供了2种封装完成了的CRUD接口供我们直接调用
1.Mapper CRUD接口
@Component
public interface UserDao extends BaseMapper<User> {
}
这就是mybatis-plus的重点,User是泛型。BaseMapper里面封装里一些数据库操作的常用方法。
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
直接注入使用即可
@Autowired
private UserDao userDao;
测试
1.int insert(T entity);
int row = userDao.insert(User.builder().account("545430111").address("广东省xx市xx区" + count).age("21").email("[email protected]").nickName("空想").password("{OP:JHYGGTYUUKOK").realName("妲己").gender(UserSex.MAN.getCode()).build());
log.info("插入用户数据成功------------->返回row:{}", count);
当然为了测试需要有更多的数据
int count = 0;
for (int i = 0; i < 10; i++) {
count += userDao.insert(User.builder().account("545430111").address("广东省xx市xx区" + count).age("21").email(
"[email protected]").nickName("空想" + count).password("{OP:JHYGGTYUUKOK").realName("妲己" +count).gender(UserSex.MAN.getCode()).build());
}
log.info("插入用户数据成功------------->返回row:{}", count);
2.int deleteById(Serializable id);
int row = userDao.deleteById("1215901606834593794");
log.info("删除用户数据成功------------->返回row:{}", count);
3.int deleteByMap(@Param(“cm”) Map<String, Object> columnMap);
Map<String, Object> map = new HashMap<String, Object>();
map.put("nick_name", "空想2");
int row = userDao.deleteByMap(map);
log.info("删除用户数据成功------------->返回row:{}", count);
4.int delete(@Param(“ew”) Wrapper wrapper);
int row = userDao.delete(new QueryWrapper<User>().eq("real_name","甄姬"));
log.info("删除用户数据成功------------->返回row:{}", count);
5.int deleteBatchIds(@Param(“coll”) Collection<? extends Serializable> idList);
List<String> list = new ArrayList<>();
list.add("1215902267827527682");
list.add("1215902272369958914");
int row = userDao.deleteBatchIds(list);
6.int updateById(@Param(“et”) T entity);
int count = userDao.updateById(User.builder().realName("甄姬").id("1215900383502876673").build());
log.info("更新用户数据成功------------->返回row:{}", count);
7.int update(@Param(“et”) T entity, @Param(“ew”) Wrapper updateWrapper);
int row = userDao.update(User.builder().realName("王昭君").build(), new QueryWrapper<User>().gt("id","1215900383502876673"));
log.info("更新用户数据成功------------->返回row:{}", count);
8.T selectById(Serializable id);
User user = userDao.selectById("1215900383502876673");
log.info("获取id为1215900383502876673的账号信息:{}",user.toString());
9.List selectBatchIds(@Param(“coll”) Collection<? extends Serializable> idList);
List<String> idlist = new ArrayList<>();
idlist.add("1215900383502876673");
idlist.add("1215901606834593794");
idlist.add("1215902267827527682");
idlist.add("1215902272369958914");
idlist.add("1215902272395124737");
idlist.add("1215902272407707650");
idlist.add("1215902272424484866");
List<User> userList = userDao.selectBatchIds(idlist);
for (User user : userList) {
log.info("获取id为{}的账号信息:{}", user.getId(), user.toString());
}
10.List selectByMap(@Param(“cm”) Map<String, Object> columnMap);
Map<String, Object> colum = new HashMap<>();
colum.put("real_name","妲己");
colum.put("id","1215902272508370946");
List<User> userList = userDao.selectByMap(colum);
for (User user : userList) {
log.info("获取id为{}的账号信息:{}", user.getId(), user.toString());
}
11.T selectOne(@Param(“ew”) Wrapper queryWrapper);
User user = userDao.selectOne(new QueryWrapper<User>().eq("id", "1215900383502876673"));
log.info("获取id为{}的账号信息:{}", user.getId(), user.toString());
12.Integer selectCount(@Param(“ew”) Wrapper queryWrapper);
Integer count = userDao.selectCount(new QueryWrapper<User>().gt("id", "1215900383502876673"));
log.info("统计用户数据成功------------->返回row:{}", count);
13.List selectList(@Param(“ew”) Wrapper queryWrapper);
List<User> userList = userDao.selectList(new QueryWrapper<User>().gt("id", "1215900383502876673"));
for (User user : userList) {
log.info("获取id为{}的账号信息:{}", user.getId(), user.toString());
}
14.List<Map<String, Object>> selectMaps(@Param(“ew”) Wrapper queryWrapper);
List<Map<String, Object>> maps = userDao.selectMaps(new QueryWrapper<User>().gt("id", "1215900383502876673"));
for (Map<String, Object> map : maps) {
log.info("获取id为{}的账号信息:{}", map.get("id"), map.toString());
}
15.List selectObjs(@Param(“ew”) Wrapper queryWrapper);
//只会返回第一个字段的值,无法转User类
List<Object> selectObjs = userDao.selectObjs(new QueryWrapper<User>().gt("id", "1215900383502876673"));
for (Object obj : selectObjs) {
log.info("获取的账号的id信息:{}", obj.toString());
}
16.<E extends IPage> E selectPage(E page, @Param(“ew”) Wrapper queryWrapper);
IPage<User> userIPage = new Page<>(1, 3);
IPage<User> pageList = userDao.selectPage(userIPage, new QueryWrapper<User>().gt("id","1215900383502876673"));
for (User record : pageList.getRecords()) {
log.info("获取id为{}的账号信息:{}",record.getId(),record.toString());
}
17.<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(“ew”) Wrapper queryWrapper);
IPage<Map<String, Object>> userIPage = new Page<>(1, 3);
IPage<Map<String, Object>> pageList = userDao.selectMapsPage(userIPage, new QueryWrapper<User>().gt("id","1215900383502876673"));
for (Map<String, Object> map : pageList.getRecords()) {
log.info("获取id为{}的账号信息:{}", map.get("id"), map.toString());
}
2.Service CRUD 接口
public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
}
使用方法同basemapper
Save
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
SaveOrUpdate
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
Remove
// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
Update
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereEntity 条件,更新记录
boolean update(T entity, Wrapper<T> updateWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
Get
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
List
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
Page
// 无条件翻页查询
IPage<T> page(IPage<T> page);
// 翻页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件翻页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 翻页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
Count
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
Chain
#query
// 链式查询 普通
QueryChainWrapper<T> query();
// 链式查询 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery();
// 示例:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
#update
// 链式更改 普通
UpdateChainWrapper<T> update();
// 链式更改 lambda 式。注意:不支持 Kotlin
LambdaUpdateChainWrapper<T> lambdaUpdate();
// 示例:
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
三、AbstractWrapper
条件构造器AbstractWrapper是QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
List<User> users = userDao.selectList(new QueryWrapper<User>().eq("real_name","王昭君"));
log.info("----------user:{}", users);
AbstractWrapper下的方法及使用
方法名 | 说明 | 使用 |
---|---|---|
allEq(Map<R, V> params) | 全部=(或个别isNull) | allEq(params,true) |
eq | = | eq(“real_name”,“王昭君”) |
ne | <> | ne(“nick_name”,“空想4”) |
gt | > | gt(“age”,21) |
ge | >= | ge(“age”,22) |
lt | < | lt(“age”,22) |
le | <= | le(“age”,21") |
between | cloum between ? and ? | between(“age”,0,21) |
notBetween | cloum between ? and ? | notBetween(“age”,0,21) |
like | cloum like ‘%王%’ | like(“real_name”,“王”) |
notLike | not like ‘%王%’ | notLike(“real_name”,“王”) |
likeLeft | like ‘%王’ | likeLeft(“real_name”,“昭”) |
likeRight | like ‘王%’ | likeRight(“real_name”,“昭”) |
isNull | is null | isNull(“gender”) |
isNotNull | is not null | isNotNull(“gender”) |
in | in (1,2,3) | in(“nick_name”,lists) |
notIn | age not in (1,2,3) | notIn(“nick_name”,lists) |
inSql | age in (1,2,3,4,5,6) | inSql(“nick_name”,"‘空想4’,‘空想5’,‘空想6’") |
notInSql | age not in (1,2,3,4,5,6) | notInSql(“nick_name”,"‘空想4’,‘空想5’,‘空想6’") |
groupBy | group by id,name | groupBy(“nick_name”,“age”) |
orderByAsc | order by id ASC,name ASC | orderByAsc(“nick_name”,“age”) |
orderByDesc | order by id DESC,name DESC | orderByDesc(“age”) |
orderBy | order by id ASC,name ASC | orderBy(true,true,“age”) |
having | having sum(age) > 10 | having(“sum(age) > 10”) |
or | id = 1 or name = ‘老王’ | eq(“nick_name”,“空想4”).or(i->i.eq(“age”,21) eq(“nick_name”,“空想4”).or().eq(“nick_name”,“空想5”) |
and | and (name = ‘李白’ and status <> ‘活着’) | and(i->i.eq(“age”,21)) |
nested | (name = ‘李白’ and status <> ‘活着’) | nested(i->i.eq(“age”,21).eq(“nick_name”,“空想4”)) |
apply | id = 1 | apply(“nick_name = ‘空想4’”) |
last | 最后添加多个以最后的为准,有sql注入风险 | last(“limit 1”) |
exists | 拼接 EXISTS ( sql语句 ) | exists(“select id from table where age = 1”) |
notExists | 拼接 NOT EXISTS ( sql语句 ) | notExists(“select id from table where age = 1”) |
QueryWrapper
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
及 LambdaQueryWrapper, 可以通过 new QueryWrapper().lambda() 方法获取
方法名 | 说明 | 使用 |
---|---|---|
select | select(i -> i.getProperty().startsWith(“test”)) | select(“id”, “name”, “age”) |
UpdateWrapper
继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件
及 LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!
方法名 | 说明 | 使用 |
---|---|---|
set | set(“name”, “老李头”) | set(“name”, “”) |
setSql | setSql(“name = ‘老李头’”) | setSql(String sql) |
自定义SQL使用Wrapper
方案一 注解方式 Mapper.java
@Select("select * from mysql_data ${ew.customSqlSegment}")
List<MysqlData> getAll(@Param(Constants.WRAPPER) Wrapper wrapper);
方案二 XML形式 Mapper.xml
<select id="getAll" resultType="MysqlData">
SELECT * FROM mysql_data ${ew.customSqlSegment}
</select>
四、分页插件
分页配置
1.spring xml方式
<!-- spring xml 方式 -->
<property name="plugins">
<array>
<bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor">
<property name="sqlParser" ref="自定义解析类、可以没有"/>
<property name="dialectClazz" value="自定义方言类、可以没有"/>
<!-- COUNT SQL 解析.可以没有 -->
<property name="countSqlParser" ref="countSqlParser"/>
</bean>
</array>
</property>
<bean id="countSqlParser" class="com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize">
<!-- 设置为 true 可以优化部分 left join 的sql -->
<property name="optimizeJoin" value="true"/>
</bean>
2.spring boot方式
@EnableTransactionManagement
@Configuration
@MapperScan("com.ljj.dao")
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor interceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
interceptor.setLimit(5);
// 开启 count 的 join 优化,只针对部分 left join
interceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return interceptor;
}
}
xml自定义分页
UserDao .java
@Component
public interface UserDao {
IPage<User> selectPageVo(Page<?> page,String realName);
}
UserMapper.xml
<select id="selectPageVo" resultType="User">
SELECT * FROM user where real_name = #{realName}
</select>
使用
Page<User> page = new Page<>(1, 10);
IPage<User> iPage = userDao.selectPageVo(page,"王昭君");
五、Sequence主键
MP内置支持的数据库主键策略:
- DB2KeyGenerator
- H2KeyGenerator
- KingbaseKeyGenerator
- OracleKeyGenerator
- PostgreKeyGenerator
mybatis plus 实体类主键策略有3种( 注解 > 全局 > 默认 )
注解使用
public class User extends Model<User> {
@TableId(value = "id", type = IdType.AUTO)
private String id;
@TableField("real_name")
private String realName;
}
IdType
AUTO:数据库ID自增
INPUT:用户输入ID
NONE:该类型为未设置主键类型,注解里等于跟随全局,全局里约等于 INPUT
ASSIGN_ID:使用雪花算法分配ID,主键类型为Number(Long和Integer)或String
ASSIGN_UUID:分配UUID,主键类型为String
ID_WORKER:分布式全局唯一ID 长整型类型,已弃用
UUID:UUID:32位UUID字符串,已弃用
ID_WORKER_STR:分布式全局唯一ID 字符串类型,已弃用
spring boot
支持主键类型指定(3.3.0开始自动识别主键类型)
方式一:使用配置类
@Bean
public IKeyGenerator keyGenerator() {
return new H2KeyGenerator();
}
方式二:通过MybatisPlusPropertiesCustomizer自定义
@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
return plusProperties -> plusProperties.getGlobalConfig().getDbConfig().setKeyGenerator(new H2KeyGenerator());
}
Spring
方式一: XML配置
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="dbConfig" ref="dbConfig"/>
</bean>
<bean id="dbConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig.DbConfig">
<property name="keyGenerator" ref="keyGenerator"/>
</bean>
<bean id="keyGenerator" class="com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator"/>
方式二:注解配置
@Bean
public GlobalConfig globalConfig() {
GlobalConfig conf = new GlobalConfig();
conf.setDbConfig(new GlobalConfig.DbConfig().setKeyGenerator(new H2KeyGenerator()));
return conf;
}
六、自定义ID生成器
MP自3.3.0开始,默认使用雪花算法+UUID(不含中划线)
Spring-Boot
方式一:声明为Bean供Spring扫描注入
@Component
public class CustomIdGenerator implements IdentifierGenerator {
@Override
public Long nextId(Object entity) {
//可以将当前传入的class全类名来作为bizKey,或者提取参数来生成bizKey进行分布式Id调用生成.
String bizKey = entity.getClass().getName();
//根据bizKey调用分布式ID生成
long id = ....;
//返回生成的id值即可.
return id;
}
}
方式二:使用配置类
@Bean
public IdentifierGenerator idGenerator() {
return new CustomIdGenerator();
}
#方式三:通过MybatisPlusPropertiesCustomizer自定义
@Bean
public MybatisPlusPropertiesCustomizer plusPropertiesCustomizer() {
return plusProperties -> plusProperties.getGlobalConfig().setIdentifierGenerator(new CustomIdGenerator());
}
#
Spring
方式一: XML配置
<bean name="customIdGenerator" class="com.baomidou.samples.incrementer.CustomIdGenerator"/>
<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
<property name="identifierGenerator" ref="customIdGenerator"/>
</bean>
方式二:注解配置
@Bean
public GlobalConfig globalConfig() {
GlobalConfig conf = new GlobalConfig();
conf.setIdentifierGenerator(new CustomIdGenerator());
return conf;
}
七、逻辑删除
逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案。使用一个状态来表示数据是否已被删除。
SpringBoot 配置方式:
application.yml 加入配置(如果你的默认值和mp默认的一样,该配置可无):
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
注册 Bean(3.1.1开始不再需要这一步):
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfiguration {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
实体类字段上加上@TableLogic注解
@TableLogic
private Integer deleted;
效果: 使用mp自带方法删除和查找都会附带逻辑删除功能 (自己写的xml不会)
example
删除时 update user set deleted=1 where id =1 and deleted=0
查找时 select * from user where deleted=0
全局逻辑删除: 3.3.0开始支持
如果公司代码比较规范,比如统一了全局都是flag为逻辑删除字段。
使用此配置则不需要在实体类上添加 @TableLogic。
但如果实体类上有 @TableLogic 则以实体上的为准,忽略全局。 即先查找注解再查找全局,都没有则此表没有逻辑删除。
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag #全局逻辑删除字段值
八、通用枚举
1.枚举类
有2种使用方法
(1)注解@EnumValue
public enum GenderEnum {
MEN(0, "男"),
WOMEN(1, "女");
GenderEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@EnumValue
private final int code;
private String desc;
}
(2)实现 IEnum
public enum GenderIEnum implements IEnum<Integer> {
MEN(0, "男"),
WOMEN(1, "女");
private int code;
private String desc;
GenderIEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
@Override
public Integer getValue() {
return this.code;
}
}
2.修改实体类
public class User extends Model<User> {
。。。
@TableField("gender")
private GenderEnum gender;
。。。
}
3.配置扫描通用枚举
mybatis-plus.type-enums-package=com.ljj.entity.enums