乐趣区

关于后端开发:提高生产力最全-MyBatisPlus-讲解

大家好,我是小菜,一个渴望在互联网行业做到蔡不菜的小菜。可柔可刚,点赞则柔,白嫖则刚!死鬼~ 看完记得给我来个三连哦!

本文次要介绍 MybatisPlus 的应用

如有须要,能够参考

如有帮忙,不忘 点赞

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

如果你每天还在反复写 CRUDSQL,如果你对这些 SQL 曾经不耐烦了,那么你何不破费一些工夫来浏览这篇文章,而后对已有的老我的项目进行革新,必有播种!

一、MP 是什么

MP 全称 Mybatis-Plus,套用官网的解释便是成为 MyBatis 最好的搭档, 简称 基友。它是在 MyBatis 的根底上只做加强不做扭转,为简化开发、提高效率而生。

1. 三大个性

1)润物无声

只做加强不做扭转,引入它不会对现有工程产生影响,如丝般顺滑。

2)效率至上

只需简略配置,即可疾速进行单表 CRUD 操作,从而节俭大量工夫。

3)丰盛性能

代码生成、物理分页、性能剖析等性能一应俱全。

2. 反对数据库

  • mysqlmariadboracledb2h2hsqlsqlitepostgresqlsqlserverprestoGaussFirebird
  • PhoenixclickhouseSybase ASEOceanBase、达梦数据库、虚谷数据库、人大金仓数据库、南大通用数据库

3. 框架结构

瞎话说,以上这些内容只有你关上官网也能看到,那么咱们接下来就先来实际操作一番!

二、MP 实战

1. 手摸手式我的项目练习

1)数据库及表筹备

sql 语句:

 use test;
 CREATE TABLE `student`  (`id` int(0) NOT NULL AUTO_INCREMENT,
  `dept_id` int(0) NULL DEFAULT NULL,
  `name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  `remark` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;
 -- ----------------------------
 -- Records of student
 -- ----------------------------
 INSERT INTO `student` VALUES (1, 1, '小菜', '关注小菜不迷路!');
 INSERT INTO `student` VALUES (2, 2, '小明', '好好学习,天天向上!');

2)pom 依赖

 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
 </dependency>
 <!--lombok-->
 <dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.16.16</version>
 </dependency>
 <!--MP 插件 -->
 <dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.2.0</version>
 </dependency>
 <!--Mysql-->
 <dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.21</version>
 </dependency>
 <!-- 连接池 -->
 <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.1</version>
 </dependency>
 <!--JUNIT-->
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.1</version>
 </dependency>

3)配置文件

 spring:
  datasource:
  url: jdbc:mysql://localhost:3306/test
  username: root
  password: 123456
  driver-class-name: com.mysql.cj.jdbc.Driver

4)实体类

 @Data
 @Builder
 @TableName("student")
 public class User {
 ​
  @TableId(type = IdType.AUTO)
  private Integer id;
 ​
  private Integer deptId;
 ​
  private String name;
 ​
  private String remark;
 }

5)Mapper

 public interface UserMapper extends BaseMapper<User> {}

6)测试类

 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class MapperTest {
 ​
  @Autowired
  private UserMapper userMapper;
 ​
  @Test
  public void getAll() {List<User> users = userMapper.selectList(null);
  users.forEach(System.out::println);
  }
 }
 /** OUTPUT:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
 User(id=2, deptId=1, name= 小明, remark= 好好学习,天天向上!)
 **/

小菜结:

在以上的后果,咱们能够看到曾经打印出了数据库中的全副数据(两条)。而并没有看到平时咱们须要写的 mapper.xml 文件,只是用到了 usermapper 中的 selectList() 办法,而 UserMapper 继承了 BaseMapper 这个接口,这个接口便是 MybatisPlus 提供给咱们的,咱们再来看下这个接口给咱们提供了哪些办法。

2. CRUD 基操

1)insert

 @Test
 public void insert() {
  // 这里应用了 lombok 中的建造者模式构建对象
  User user = User.builder().deptId(1).name("小华").remark("小华爱学习").build();
  int insertFlag = userMapper.insert(user);
  log.info("插入影响行数,{} | 小华的 ID: {}", insertFlag, user.getId());
 }
 /** OUTPUT:
 插入影响行数,1 | 小华的 ID: 8
 **/

能够看到咱们不仅插入了数据,而且还获取到了插入数据的ID,然而值得注意的是这里的 ID 尽管是自增的,但并非是 MP 默认的 ID 生成策略,而是咱们在实体类中指定的:

MP 中反对的主键生成策略有以下几种:

咱们既然曾经看到了 @TableId 这个注解,那咱们再来关注一个罕用注解 @TableField

从注解名上咱们就能够看出,@TableId 是用来标记主键 ID 的,而 @TableField 是用来标记其余字段的。

能够看得出来这个注解中存在的值还是比拟多的,上面介绍几个罕用的值:

  • value

用于解决字段名不统一问题和驼峰命名,比方实体类中属性名为 remark,然而表中的字段名为 describe,这个时候就能够应用 @TableField(value="describe") 来进行转换。驼峰转换如果在全局中有配置驼峰命名,这个中央可不写。

  • exist

用于在数据表中不存在的字段,咱们能够应用 @TableField(exist = false) 来进行标记

  • condition

用在预处理 WHERE 实体条件自定义运算规定,比方我配置了 @TableField(condition = SqlCondition.LIKE),输入 SQL 为:select 表 where name LIKE CONCAT('%', 值,'%'),其中 SqlCondition 值如下:

  • update

用在预处理 set 字段自定义注入,比方我配置了 @TableField(update = "%s+1"),其中 %s 会填充字段,输入 SQL 为:update 表名 set 字段 = 字段 +1 where 条件

  • select

用于是否查问时束缚,如果咱们有个字段 remarktext 类型的,查问的时候不想查问该字段,那么就能够应用 @TableField(select = false) 来束缚查问的时候不查问该字段

2)update

MybatisPlus 的更新操作存在两种:

 int updateById(Param("et") T entity);
 ​
 int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
依据 ID 更新
 @Test
 public void update() {User user = User.builder().id(3).name("小华").remark("小华爱玩游戏").build();
  userMapper.updateById(user);
 }
 /** 更新后果:
 User(id=3, deptId=1, name= 小华, remark= 小华爱玩游戏)
 **/
依据条件更新
 @Test
 public void update() {UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
  updateWrapper.eq("name","小华").set("remark","小华爱下棋");
  userMapper.update(null, updateWrapper);
 }
 /** 更新后果:
 User(id=3, deptId=1, name= 小华, remark= 小华爱下棋)
 **/

咱们也能够将要更新的条件放进 user 对象 外面:

 @Test
 public void update() {UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
  updateWrapper.eq("name","小华");
  User user = User.builder().remark("小华爱游泳").build();
  userMapper.update(user, updateWrapper);
 }
 /** 更新后果:
 User(id=3, deptId=1, name= 小华, remark= 小华爱游泳)
 **/

3)delete

MybatisPlus 中删除的形式绝对于更新多,总共有四种:

 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);
依据 ID 删除
 @Test
 public void deleteById() {userMapper.deleteById(3);
 }
 /** SQL 语句:DELETE FROM student WHERE id = 3;
 **/
依据 Map 删除
 @Test
 public void deleteByMap() {HashMap<String, Object> columnMap = new HashMap<>();
  columnMap.put("name","小华");
  columnMap.put("remark","小华爱游泳");
  userMapper.deleteByMap(columnMap);
 }
 /** SQL 语句:DELETE FROM student WHRE name = '小华' AND remark = '小华爱游泳';
 **/
依据 Wrapper 删除
 @Test
 public void delete() {UpdateWrapper<User> wrapper = new UpdateWrapper<>();
  wrapper.eq("remark","小华爱下棋");
  userMapper.delete(wrapper);
 }
 /** SQL 语句:DELETE FROM student WHRE remark = '小华爱下棋';
 **/

依据 Wrapper 删除还有另外一种形式,间接将实体类放入 Wrapper 中包装:

 @Test
 public void delete() {User user = User.builder().remark("小华爱下棋").build();
  UpdateWrapper<User> wrapper = new UpdateWrapper<>(user);
  userMapper.delete(wrapper);
 }
 /** SQL 语句:DELETE FROM student WHRE remark = '小华爱下棋';
 **/
依据 ID 批量删除
 @Test
 public void deleteBatchIds() {List<Integer> idList = new ArrayList<>();
  idList.add(4);
  idList.add(7);
  userMapper.deleteBatchIds(idList);
 }
 /** SQL 语句:DELETE FROM student WHERE id In (4,7)
 **/

4)select

查问操作在咱们开发中是最常常用到的,也是重中之重。MybatisPlus 中反对查问的办法也比拟多,如下:

 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(@aram("ew") Wrapper<T> queryWrapper);
 ​
 IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
 ​
 IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);

能够看到总共有 10 个办法,咱们接下来一个一个测试

查问所有
 @Test
 public void selectList() {List<User> users = userMapper.selectList(null);
  users.forEach(System.out::println);
 }
 /** 
  OUTPUT:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
 User(id=2, deptId=1, name= 小明, remark= 好好学习,天天向上!)
  SQL 语句:
 SELECT id, dept_id, name, remark FROM student;
 **/
查问数量
 @Test
 public void selectCount() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.like("name","小");
  System.out.println(userMapper.selectCount(queryWrapper));
 }
 /** 
  OUTPUT:
 2
  SQL 语句:
 SELECT COUNT(1) FROM student WHERE (name LIKE '% 小 %');
 **/
依据 ID 查问
 @Test
 public void selectById() {User user = userMapper.selectById(1);
  System.out.println(user);
 }
 /** 
  OUTPUT:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
  SQL 语句:
 SELECT id, dept_id, name, remark FROM student WHERE ID = 1;
 **/
依据 ID 批量查问
 @Test
 public void selectBatchIds() {List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2));
  users.forEach(System.out::println);
 }
 /** 
  OUTPUT:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
 User(id=2, deptId=1, name= 小明, remark= 好好学习,天天向上!)
  SQL 语句:
 SELECT id, dept_id, name, remark FROM student WHERE ID IN (1, 2);
 **/
依据条件查问单条
 @Test
 public void selectOne() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.eq("name","小菜");
  User user = userMapper.selectOne(queryWrapper);
  System.out.println(user);
 }
 /**
  OUTPUT:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
  SQL 语句:
  SELECT id, name, dept_id, remark FROM student WHERE (name = '小菜');
 **/
依据条件查问多条

通过 map 传递参数,不是通过 LIKE 查问,而是通过 = 查问

 @Test
 public void selectByMap() {HashMap<String, Object> columnMap = new HashMap<>();
  columnMap.put("name","小");
  List<User> users = userMapper.selectByMap(columnMap);
  users.forEach(System.out::println);
 }
 /**
  OUTPUT:
 null
  SQL 语句:
 SELECT id, name, dept_id, remark FROM student WHERE name = '小';
 **/

如果咱们没有新建实体类进行后果封装,咱们还能够用 Map 来接管后果集:

 @Test
 public void selectMaps() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.like("name","小");
  List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
  maps.forEach(System.out::println);
 }
 /**
  OUTPUT:
 {name= 小菜, remark= 关注小菜不迷路!, id=1, dept_id=1}
 {name= 小明, remark= 好好学习,天天向上!, id=2, dept_id=1}
  SQL 语句:SELECT id, name, dept_id, remark FROM student WHERE (name LIKE '% 小 %');
 **/

也能够用 Object 对象来接管后果集:

 @Test
 public void selectObjs() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.like("name", "小");
  List<Object> objects = userMapper.selectObjs(queryWrapper);
 }
 /**
  OUTPUT:
 {name= 小菜, remark= 关注小菜不迷路!, id=1, dept_id=1}
 {name= 小明, remark= 好好学习,天天向上!, id=2, dept_id=1}
  SQL 语句:SELECT id, name, dept_id, remark FROM student WHERE (name LIKE '% 小 %');
 **/
分页查问
 @Test
 public void selectPage() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.like("name", "小");
  Page<User> page = new Page<>(1, 1);
  IPage<User> userIPage = userMapper.selectPage(page, queryWrapper);
  System.out.println("数据总数:" + userIPage.getTotal());
  System.out.println("总页数:" + userIPage.getPages());
  System.out.println("当前页:" + userIPage.getCurrent());
  System.out.println("页大小:" + userIPage.getSize());
  userIPage.getRecords().forEach(System.out::println);
 }
 /**
  OUTPUT:
 数据总数:2
 总页数:2
 当前页:1
 页大小:1
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
  SQL 语句:SELECT id, name, dept_id, remark
  FROM student
  WHERE (name LIKE '% 小 %')
  LIMIT 0,1;
 **/

3. 条件结构器

CRUD 的基本操作中,咱们想要通过条件查问都是通过 Wrapper 类进行封装的,下面只是简略的用到 eqlike 操作。事实上这个类非常弱小,咱们在上面会具体进行介绍。

1)allEq

全副 eq 或个别 isNull

 allEq(Map<R, V> params)
 allEq(Map<R, V> params, boolean null2IsNull)
 allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  
 allEq(BiPredicate<R, V> filter, Map<R, V> params)
 allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
 allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 

参数阐明:

param: key 为数据库字段名,value 为字段值

nullsIsNull:为 true 则在 map 的 value 为 null 时调用 isNull 办法,为 false 是则疏忽 value 为 null 时不调用 isNull 办法

filter: 过滤函数,判断是否容许字段传入比对条件中

应用示例:

  • allEq(Map<R, V> params)
 @Test
 public void testAllEq() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  Map<String,Object> params = new HashMap<>();
  params.put("name","小菜");
  params.put("dept_id",1);
  params.put("remark",null);
  queryWrapper.allEq(params); // 会调用 isNull 办法
  userMapper.selectList(queryWrapper);
 }
 /** 
  后果:
 {}
  SQL 语句:
  SELECT id,name,dept_id,remark
  FROM student
  WHERE (name = '小菜' AND dept_id = 1 AND remark IS NULL);
  **/
  • allEq(Map<R, V> params, boolean null2IsNull)
 @Test
 public void testAllEq() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  Map<String,Object> params = new HashMap<>();
  params.put("name","小菜");
  params.put("dept_id",1);
  params.put("remark",null);
  queryWrapper.allEq(params, false); // 不会调用 isNull 办法
  userMapper.selectList(queryWrapper);
 }
 /** 
  后果:
 User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!)
  SQL 语句:
  SELECT id,name,dept_id,remark
  FROM student
  WHERE (name = '小菜' AND dept_id = 1);
  **/
  • allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
 @Test
 public void testAllEq() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  Map<String,Object> params = new HashMap<>();
  params.put("name","小菜");
  params.put("dept_id",1);
  params.put("remark",null);
  queryWrapper.allEq(false,params,false); // 不会带入条件进行查问
  userMapper.selectList(queryWrapper);
 }
 /** 
  后果:
 {name= 小菜, remark= 关注小菜不迷路!, id=1, dept_id=1}
 {name= 小明, remark= 好好学习,天天向上!, id=2, dept_id=1}
  SQL 语句:
  SELECT id,name,dept_id,remark
  FROM student;
  **/
  • allEq(BiPredicate<R, V> filter, Map<R, V> params)
 @Test
 public void testAllEq() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  Map<String, Object> params = new HashMap<>();
  params.put("name", "小菜");
  params.put("dept_id", 1);
  params.put("remark", null);
  // 只有 key 中含有“m”才会用作条件判断
  queryWrapper.allEq((k, v) -> (k.contains("m")), params);
  userMapper.selectList(queryWrapper);
 }
 /** 
  后果:
 0
  SQL 语句:
  SELECT id,name,dept_id,remark
  FROM student
  WHERE (name = '小菜' AND remark IS NULL);
  **/

2)比拟操作

  • eq: 相当于 =
  • ne: 相当于 !=
  • gt: 相当于 >
  • ge: 相当于>=
  • lt: 相当于 <
  • le: 相当于<=
  • between: 相当于between ... and ...
  • notBetween: 相当于not between ... and ...
  • in: 相当于in(.., .., ..)
  • notIn: 相当于not in(.., .., ..)

3)含糊查问

  • like: like("name","小菜") --> name like "% 小菜 %"
  • notLike: notLike("name","小菜") --> name not like "% 小菜 %"
  • likeLeft: like("name","小菜") --> name like "% 小菜"
  • likeRight: like("name","小菜") --> name like "小菜 %"

4)排序

  • orderBy:
 orderBy(boolean condition, boolean isAsc, R... columns)

orderBy(true, true, "id", "name") --> order by id ASC, name ASC

  • orderByAsc:
`orderByAsc("id","name") --> order by id ASC, name ASC`
  • orderByDesc:
orderByDesc("id","name) --> order by id Desc, name Desc`

5)逻辑查问

  • or:

拼接:被动调用 or 示意紧接着下一个办法不是用 and 连贯!(不调用 or 则默认为应用 and 连贯),eq("id",1).or().eq("name","老王")

嵌套:or(i -> i.eq("name", "李白").ne("status", "活着"))

  • and:

嵌套:and(i -> i.eq("name", "李白").ne("status", "活着"))

6)select

在 MP 查问中,默认查问所有的字段,如果有须要也能够通过 select 办法进行指定字段,如select("id", "name")

4. 配置解说

1)根本配置

  • configLocation

用于指明 MyBatis 配置文件的地位,如果咱们有 MyBatis 的配置文件,需将配置文件的门路配置到 configLocation

SpringBoot:

 mybatis-plus.config-location = classpath:mybatis-config.xml

SpringMvc:

 <bean id="sqlSessionFactory"
 class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
 <property name="configLocation" value="classpath:mybatis-config.xml"/>
 </bean
  • mapperLocations

用于指明 Mapper 所对应的 XML 的文件地位,咱们在 通用 CRUD 中用到的 Mapper 是间接继承 MP 提供的 BaseMapper,咱们也能够自定义办法,而后在 XML 文件中自定义 SQL,而这时咱们须要通知 Mapper 所对应 XML 文件的地位

SpringBoot:

 mybatis-plus.mapper-locations = classpath*:mybatis/*.xml

SpringMVC:

 <bean id="sqlSessionFactory"
 class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
 <property name="mapperLocations" value="classpath*:mybatis/*.xml"/>
 </bean>
  • typeAliasesPackage

用于 MyBatis 别名包扫描门路,通过该属性能够给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中能够间接应用类名,而不必应用全限定的类名

SpringBoot:

 mybatis-plus.type-aliases-package = cbuc.life.bean

SpringMVC:

 <bean id="sqlSessionFactory"
 class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
 <property name="typeAliasesPackage"
 value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
 </bean>

2)进阶配置

  • mapUnderScoreToCamelCase

是否开启主动驼峰命名规定映射,这个配置的默认值是 true,然而这个属性在 MyBatis 中的默认值是 false,所以在咱们平时的开发中都会将这个配置开启。

 #敞开主动驼峰映射,该参数不能和 mybatis-plus.config-location 同时存在
 mybatis-plus.configuration.map-underscore-to-camel-case = false

  • cacheEnabled

全局地开启或敞开配置文件中的所有映射器曾经配置的任何缓存,默认为 true

 mybatis-plus.configuration.cache-enabled = false

3)DB 策略配置

  • idType

全局默认主键类型,设置后,即可省略实体对象中的 @TableId(type = IdType.AUTO) 配置。该配置的默认值为 ID_WORKER

SpringBoot:

 mybatis-plus.global-config.db-config.id-type = auto

SpringMVC:

 <bean id="sqlSessionFactory"
 class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="globalConfig">
          <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
              <property name="dbConfig">
                  <bean         class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
                  <property name="idType" value="AUTO"/>
                  </bean>
              </property>
          </bean>
      </property>
 </bean>
  • tablePrefix

表名前缀,全局配置后可省略 @TableName() 配置。该配置的默认值为 null

SpringBoot:

 mybatis-plus.global-config.db-config.table-prefix = yq_

SpringMVC:

 <bean id="sqlSessionFactory"
 class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="globalConfig">
          <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
              <property name="dbConfig">
                  <bean            class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
                      <property name="idType" value="AUTO"/>
                      <property name="tablePrefix" value="yq_"/>
                  </bean>
              </property>
          </bean>
      </property>
 </bean>

5. 其余扩大

1)主动填充

有时候咱们在插入或更新数据的时候,心愿有些字段能够主动填充。比方咱们平时数据表外面会有个 插入工夫 或者 更新工夫 这种字段,咱们会默认以以后工夫填充,在 MP 中咱们也能够进行配置。

首先咱们须要借助 @TableField(fill = FieldFill.INSERT) 这个注解,在插入时进行填充。

 @TableField(fill = FieldFill.INSERT)
 private String remark;

其中主动填充的模式如下:

 public enum FieldFill {
  /**
  * 默认不解决
  */
  DEFAULT,
  /**
  * 插入时填充字段
  */
  INSERT,
  /**
  * 更新时填充字段
  */
  UPDATE,
  /**
  * 插入和更新时填充字段
  */
  INSERT_UPDATE
 }

而后咱们再编写自定义的填充解决模式:

 @Component
 public class MyMetaObjectHandler implements MetaObjectHandler {
  @Override
  public void insertFill(MetaObject metaObject) {Object remark = getFieldValByName("remark", metaObject);
  if (null == remark) {setFieldValByName("remark", "好好学习", metaObject);
  }
  }
 ​
  @Override
  public void updateFill(MetaObject metaObject) {// 自定义更新时填充}
 }

测试:

 @Test
 public void testObjectHandler() {User user = User.builder().deptId(1).name("小明").build();
  userMapper.insert(user);
 }
 /**
  SQL 语句:INSERT INTO student (name, dept_id, remark)
 VALUES ('小明', 1, '好好学习');
 **/

能够看到插入时,曾经主动将咱们填充的字段合并进去。

2)逻辑删除

在开发中,很多时候咱们删除数据并不需要真正意义上的物理删除,而是应用逻辑删除,这样子查问的时候须要状态条件,确保被标记的数据不被查问到。MP 当然也反对这样的性能。

咱们须要先为 student 表增加一个字段 status 来申明数据是否被删除,0 示意被删除,1 示意未删除,而后也须要在实体类上减少这个属性:

 @TableLogic
 private Integer status;

application.yaml 中配置:

 mybatis-plus:
  global-config:
  db-config:
  logic-delete-value: 0
  logic-not-delete-value: 1

测试:

 @Test
 public void testLogicDelete() {userMapper.deleteById(1);
 }
 /**
  SQL 语句:UPDATE student SET status=0
 WHERE id=1 AND status=1;
 **/

能够看出这段 SQL 并没有真正删除,而是进行了逻辑删除,只是更新了删除标识

3)通用枚举

如果有性别之类的字段,咱们通常会用 01 来示意,然而查出来咱们得进行值转换,这个时候咱们就能够应用枚举来解决这个问题:

首先为 student 表增加一个 sex 字段来示意性别,0 示意女性,1 示意男性,而后定义一个枚举类:

 public enum SexEnum implements IEnum<Integer> {MAN(1, "男"),
  WOMEN(0, "女");
 ​
  private int code;
 ​
  private String value;
 ​
  SexEnum(int code, String value) {
  this.code = code;
  this.value = value;
  }
 ​
  @Override
  public Integer getValue() {return this.code;}
  
  // 留神要重写此办法,不然会将值转换成‘MAN’,而不是‘男’@Override
  public String toString() {return this.value;}
 }

而后在实体类中增加对应属性:

 private SexEnum sex;

application.yaml 中配置:

 mybatis-plus:
  type-enums-package: cbuc.life.enums

测试:

 @Test
 public void selectOne() {QueryWrapper<User> queryWrapper = new QueryWrapper<>();
  queryWrapper.eq("name", "小菜");
  User user = userMapper.selectOne(queryWrapper);
  System.out.println(user);
 }
 /**
  输入后果:User(id=1, deptId=1, name= 小菜, remark= 关注小菜不迷路!, status=1, sex= 男)
  SQL 语句:SELECT id,sex,name,dept_id,remark,status
  FROM student
  WHERE status=1 AND (name = '小菜');
 **/

END

这篇文章写到这里就告一段落了哦,内容有点长,不过如果能残缺看下来,我置信你必定可能很好的应用 MybatisPlus 啦!路漫漫,小菜与你一起求索!

明天的你多致力一点,今天的你就能少说一句求人的话!

我是小菜,一个和你一起学习的男人。 ????

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

退出移动版