目录
初始配置
基本CRUD
常用注解
条件构造器和常用接口
QueryWrapper
UpdateWrapper
condition
LambdaQueryWrapper
LambdaUpdateWrapper
插件
分页插件
xml自定义分页
乐观锁
通用枚举
MyBatisX:
初始配置
1) 添加依赖:
<packaging>jar</packaging><properties><spring.version>5.3.1</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><!-- 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!-- junit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!-- lombok用来简化实体类 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--MyBatis-Plus的核心依赖--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.4.3.4</version></dependency></dependencies>
2) 创建MyBatis的核心配置文件
在resources下创建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>
3) 创建Spring的配置文件
创建Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"><!-- 引入jdbc.properties --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Druid数据源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!--开启扫描--><context:component-scan base-package="com.gr.mybatisplus"></context:component-scan><!--配置mapper接口的扫描配置由mybatis-spring提供,可以将指定包下所有的mapper接口创建动态代理并将这些动态代理作为IOC容器的bean管理--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.gr.mybatisplus.mapper"></property></bean><!-- 此处使用的是MybatisSqlSessionFactoryBean --><bean class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="configLocation" value="classpath:mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property><property name="typeAliasesPackage" value="com.gr.mybatisplus.pojo"></property><!-- 设置MyBatis-Plus的全局配置 --><property name="globalConfig" ref="globalConfig"></property></bean><bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!-- 设置实体类所对应的表的前缀 --><property name="tablePrefix" value="t_"></property></bean></property></bean>
</beans>
4) 添加日志功能
在resources下创建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--定义日志文件的存储地址 logs为当前项目的logs目录 还可以设置为../logs --><property name="LOG_HOME" value="logs" /><!--控制台日志, 控制台输出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n</pattern></encoder></appender><!--myibatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志输出级别 --><root level="DEBUG"><appender-ref ref="STDOUT" /></root>
</configuration>
基本CRUD
BaseMapper
MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用
插入
@Testpublic void testInsert(){//实现新增用户信息//INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )User user = new User();//user.setId(100L);user.setName("张三");user.setAge(23);user.setEmail("zhangsan@atguigu.com");int result = userMapper.insert(user);System.out.println("result:"+result);System.out.println("id:"+user.getId());}
删除
@Testpublic void testDelete(){//通过id删除用户信息//DELETE FROM user WHERE id=?int result = userMapper.deleteById(1492767055210991617L);System.out.println("result:"+result);//根据map集合中所设置的条件删除用户信息//DELETE FROM user WHERE name = ? AND age = ?Map<String, Object> map = new HashMap<>();map.put("name", "张三");map.put("age", 23);int result = userMapper.deleteByMap(map);System.out.println("result:"+result);//通过多个id实现批量删除//DELETE FROM user WHERE id IN ( ? , ? , ? )List<Long> list = Arrays.asList(1L, 2L, 3L);int result = userMapper.deleteBatchIds(list);System.out.println("result:"+result);}
修改
@Testpublic void testUpdate(){//修改用户信息//UPDATE user SET name=?, email=? WHERE id=?User user = new User();user.setId(4L);user.setName("李四");user.setEmail("lisi@atguigu.com");int result = userMapper.updateById(user);System.out.println("result:"+result);}
查询
@Testpublic void testSelect(){//通过id查询用户信息//SELECT id,name,age,email FROM user WHERE id=?User user = userMapper.selectById(1L);System.out.println(user);//根据多个id查询多个用户信息//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )List<Long> list = Arrays.asList(1L, 2L, 3L);List<User> users = userMapper.selectBatchIds(list);users.forEach(System.out::println);//根据map集合中的条件查询用户信息//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?Map<String, Object> map = new HashMap<>();map.put("name", "Jack");map.put("age", 20);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);//查询所有数据//SELECT id,name,age,email FROM userList<User> users = userMapper.selectList(null);users.forEach(System.out::println);/*Map<String, Object> map = userMapper.selectMapById(1L);System.out.println(map);*/}
通用Service
a>IService
MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑 详情查看源码IService和ServiceImpl
b>创建Service接口和实现类
//UserService继承IService模板提供的基础功能
public interface UserService extends IService<User> {}
/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
c>扫描组件
在applicationContext.xml中添加扫描组件的配置,扫描业务层组件,用于测试
d>测试查询记录数
e>测试批量插入
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyBatisPlusServiceTest {@Autowiredprivate UserService userService;@Testpublic void testGetCount(){long count = userService.count();System.out.println("啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊:"+count);}@Testpublic void testInsertMore(){List<User> list = new ArrayList<>();for (int i = 1; i < 10; i++) {User user = new User();user.setName("aaa"+i);user.setAge(22+i);list.add(user);}boolean b = userService.saveBatch(list);System.out.println("aaaa啊啊啊啊啊啊啊啊:"+b);}
}
常用注解
常用注解实例:
//设置实体类所对应的表名
//@TableName("t_user")
public class User {//将属性所对应的字段指定为主键//@TableId注解的value属性用于指定主键的字段//@TableId注解的type属性设置主键生成策略//@TableId(value = "uid", type = IdType.AUTO)@TableId("uid")private Long id;//指定属性所对应的字段名@TableField("user_name")private String name;private Integer age;private String email;private SexEnum sex;@TableLogicprivate Integer isDeleted;
}
1、@TableName
在实体类类型上添加@TableName("t_user"),标识实体类对应的表,即可成功执行SQL语句
通过GlobalConfig全局配置 修改spring核心配置文件:
<!-- 此处使用的是MybatisSqlSessionFactoryBean --><bean class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="configLocation" value="classpath:mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property><property name="typeAliasesPackage" value="com.gr.mybatisplus.pojo"></property><!-- 设置MyBatis-Plus的全局配置 --><property name="globalConfig" ref="globalConfig"></property></bean><bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!-- 设置实体类所对应的表的前缀 --><property name="tablePrefix" value="t_"></property></bean></property></bean>
2、@TableId
在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句
相当于配置@TableId的type属性的全局主键策略: bean标签globalConfig中的bean标签内添加如下信息
<!-- 设置全局主键策略 -->
<property name="idType" value="AUTO"></property>
3、@TableField
若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格,此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
例如实体类属性name,表中字段username 此时需要在实体类属性上使@TableField("username")设置属性所对应的字段名
4、@TableLogic
逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库 中仍旧能看到此条数据记录
使用场景:可以进行数据恢复
实现逻辑删除
step1:数据库中创建逻辑删除状态列,设置默认值为0
step2:实体类中添加逻辑删除属性
常用注解实例:
//设置实体类所对应的表名
//@TableName("t_user")
public class User {//将属性所对应的字段指定为主键//@TableId注解的value属性用于指定主键的字段//@TableId注解的type属性设置主键生成策略//@TableId(value = "uid", type = IdType.AUTO)@TableId("uid")private Long id;//指定属性所对应的字段名@TableField("user_name")private String name;private Integer age;private String email;private SexEnum sex;@TableLogicprivate Integer isDeleted;
}
条件构造器和常用接口
接口类:
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
QueryWrapper
//a>例1:组装查询条件@Testpublic void test01(){//查询用户名包含a,年龄在20到30之间,邮箱信息不为null的用户信息//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("user_name", "a").between("age", 20, 30).isNotNull("email");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
//b>例2:组装排序条件@Testpublic void test02(){//查询用户信息,按照年龄的降序排序,若年龄相同,则按照id升序排序//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASCQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
//c>例3:组装删除条件@Testpublic void test03(){//删除邮箱地址为null的用户信息//UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");int result = userMapper.delete(queryWrapper);System.out.println("result:"+result);}
//d>例4:条件的优先级@Testpublic void test04(){//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.gt("age", 20).like("user_name", "a").or().isNull("email");User user = new User();user.setName("小明");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("result:"+result);}@Testpublic void test05(){//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改//lambda中的条件优先执行//UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like("user_name", "a").and(i->i.gt("age",20).or().isNull("email"));User user = new User();user.setName("小红");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("result:"+result);}
//e>例5:组装select子句@Testpublic void test06(){//查询用户的用户名、年龄、邮箱信息//SELECT user_name,age,email FROM t_user WHERE is_deleted=0QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.select("user_name", "age", "email");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}
//f>例6:实现子查询@Testpublic void test07(){//查询id小于等于100的用户信息//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 100))QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.inSql("uid", "select uid from t_user where uid <= 100");List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
UpdateWrapper
@Testpublic void test08(){//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();updateWrapper.like("user_name", "a").and(i -> i.gt("age", 20).or().isNull("email"));.set("user_name", "小黑").set("email","abc@atguigu.com");int result = userMapper.update(null, updateWrapper);System.out.println("result:"+result);}
condition
@Testpublic void test10(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(username), "user_name", username).ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
LambdaQueryWrapper
@Testpublic void test11(){//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)String username = "a";Integer ageBegin = null;Integer ageEnd = 30;LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username).ge(ageBegin != null, User::getAge, ageBegin).le(ageEnd != null, User::getAge, ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}
LambdaUpdateWrapper
@Testpublic void test12(){//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.like(User::getName, "a").and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail));.set(User::getName, "小黑").set(User::getEmail,"abc@atguigu.com");int result = userMapper.update(null, updateWrapper);System.out.println("result:"+result);}
插件
分页插件
添加配置
<bean>class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="configLocation" value="classpath:mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property><property name="typeAliasesPackage" value="com.atguigu.mp.pojo"></property><property name="globalConfig" ref="globalConfig"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property>
</bean>
<!--配置MyBatis-Plus插件-->
<bean id="mybatisPlusInterceptor"class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref></list></property>
</bean>
<!--配置MyBatis-Plus分页插件的bean-->
<bean id="paginationInnerInterceptor"class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor">
<!--设置数据库类型-->
<property name="dbType" value="MYSQL"></property>
测试
@Test
public void testPage(){//设置分页参数Page<User> page = new Page<>(1, 5);userMapper.selectPage(page, null);//获取分页数据List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
}
结果
User(id=1, name=Jone, age=18, email=test1@baomidou.com, isDeleted=0) User(id=2, name=Jack, age=20, email=test2@baomidou.com, isDeleted=0) User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=0) User(id=4, name=Sandy, age=21, email=test4@baomidou.com, isDeleted=0) User(id=5, name=Billie, age=24, email=test5@ba omidou.com, isDeleted=0) 当前页:1 每页显示的条数:5 总记录数:17 总页数:4 是否有上一 页:false 是否有下一页:true
xml自定义分页
UserMapper中定义接口方法
/**
* 根据年龄查询用户列表,分页显示
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
* @param age 年龄
* @return
*/
IPage<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integerage);
UserMapper.xml中编写SQL
<!--SQL片段,记录基础字段-->
<sql id="BaseColumns">id,username,age,email</sql>
<!--IPage<User> selectPageVo(Page<User> page, Integer age);-->
<select id="selectPageVo" resultType="User">SELECT <include refid="BaseColumns"></include> FROM t_user WHERE age > #{age}
</select>
测试
@Test
public void testSelectPageVo(){//设置分页参数Page<User> page = new Page<>(1, 5);userMapper.selectPageVo(page, 20);//获取分页数据List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
}
结果:
User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=null) User(id=4, name=Sandy, age=21, email=test4@baomidou.com, isDeleted=null) User(id=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=null) User(id=8, name=ybc1, age=21, email=null, isDeleted=null) User(id=9, name=ybc2, age=22, email=null, isDeleted=null) 当前 页:1 每页显示的条数:5 总记录数:12 总页数:3 是否有上一页:false 是否有下一页:true
乐观锁
乐观锁实现流程
数据库中添加version字段
取出记录时,获取当前version
SELECT id,`name`,price,`version` FROM product WHERE id=1
更新时,version + 1,如果where语句中的version版本不对,则更新失败
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1
Mybatis-Plus实现乐观锁
@Version实体类添加注解
@Data
public class Product {private Long id;private String name;private Integer price;@Versionprivate Integer version;
}
添加乐观锁插件配置
<!--配置MyBatis-Plus插件-->
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref><ref bean="optimisticLockerInnerInterceptor"></ref></list></property>
</bean>
<!--配置乐观锁插件-->
<bean id="optimisticLockerInnerInterceptor"class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor"></bean>
通用枚举
表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus的通用枚举 来实现
数据库表添加字段sex
创建通用枚举类型
@Getter
public enum SexEnum {MALE(1, "男"),FEMALE(2, "女");@EnumValueprivate Integer sex;private String sexName;SexEnum(Integer sex, String sexName) {this.sex = sex;this.sexName = sexName;}
}
配置扫描通用枚举
<bean>class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="configLocation" value="classpath:mybatis-config.xml"></property><property name="dataSource" ref="dataSource"></property><property name="typeAliasesPackage" value="com.atguigu.mp.pojo"></property><!-- 设置MyBatis-Plus的全局配置 --><property name="globalConfig" ref="globalConfig"></property><!-- 配置扫描通用枚举 --><property name="typeEnumsPackage" value="com.atguigu.mp.enums"></property>
</bean>
测试
@Test
public void testSexEnum(){User user = new User();user.setName("Enum");user.setAge(20);//设置性别信息为枚举项,会将@EnumValue注解所标识的属性值存储到数据库user.setSex(SexEnum.MALE);//INSERT INTO t_user ( username, age, sex ) VALUES ( ?, ?, ? )//Parameters: Enum(String), 20(Integer), 1(Integer)userMapper.insert(user);
}
MyBatisX:
MyBatis-Plus为我们提供了强大的mapper和service模板,能够大大的提高开发效率 但是在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表 联查,我们就需要自己去编写代码和SQL语句,我们该如何快速的解决这个问题呢,这个时候可 以使用MyBatisX插件 MyBatisX一款基于 IDEA 的快速开发插件,为效率而生。
MyBatisX插件用法:https://baomidou.com/pages/ba5b24/