- Mybatis和MybatisPlus3.4的使用
- 1 RESTFUL
- 2 逆向工程
- 2.1 tkMybatis逆向工程
- 2.1.1 导入依赖
- 2.1.2 添加插件
- 2.1.3 添加配置文件
- 2.1.4 执行逆向
- 2.1.5 生成成功
- 2.1.6 使用tkMybatis
- 2.2 MybatisPlus使用教程
- 2.2.1 在mapper子项目中添加依赖
- 2.2.2 配置`application.yml`
- 2.2.3 配置`@MapperScan`
- 2.2.4 编写实体类`Users`
- 2.2.5 编写`Mapper.java`继承模版`baseMapper`
- 2.2.6 测试是否能够正常调用MP
- 2.2.7 配置日志
- 2.2.8 CRUD扩展
- 2.2.8.1 数据库插入的id的默认值:全局的唯一id
- 2.2.8.2 自动填充
- 2.2.9 乐观锁
- 2.2.10 查询
- 2.2.11 删除
- 2.2.12 性能分析插件(新版本已经移除)
- 2.2.13 条件构造器`wrapper`
- 2.2.14 代码生成器,`MP`逆向工程
- 3 常见问题解决办法
- 3.1 数据库url中的SSL问题
- 3.2 插件没找到
- 3.3 将数据库中的其他表都生成了
- 3.4 users表生成了其他表
前后端风你开发的项目中,前后端之间是接口进行请求和响应,后端向前端提供请求时就要对外暴露一个URL;URL的设计不能是随意的,需要遵从一定的设计规范----RESTFUL。
RESTful是一种web api的标准,也就是一种url设计风格/规范
-
每个URL请求路径代表服务器上的唯一资源。
传统的URL设计:
http://localhost:8080/goods/delete?goodsId=1 商品1
http://localhost:8080/goods/delete?goodsId=2 商品2
RESTful设计:
http://localhost:8080/goods/delete/1 商品1
http://localhost:8080/goods/delete/1 商品1
示例:
@DeleteMapping("/delete/{id}") public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003,"请求成功",goodsId); } -
使用不同的请求方式表示不同的操作,保证唯一URL对应唯一资源
- @GetMapping 查询
- @PutMapping 修改
- @PostMapping 添加
- @DeleteMapping 删除
根据id删除一个商品:
//http://localhost:8080/goods/1 [delete] @DeleteMapping("/{id}") public ResultVO deleteGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003,"请求成功",goodsId); }根据id查询一个商品:
//http://localhost:8080/goods/1 [get] @GetMapping("/{id}") public ResultVO getGoods(@PathVariable("id") Integer goodsId) { return new ResultVO(10003,"请求成功",goodsId); } -
接口响应的资源表现形式使用JSON
- 可以在控制类或者需要的接口方法上添加@ResponseBody注解讲返回的对象格式化为JSON
- 也可以在控制类上使用@RestController声明控制器
-
前端(AndroidiosPC)通过无状态的HTTP协议与后端接口交互
2.1 tkMybatis逆向工程mybatis官方提供了一种根据数据库表生成mybatis执行代码的工具,这个工具就是一个逆向工程
逆向工程:针对数据库单表—->生成代码(mapper.xml、mapper.java、pojo。。)
这里我最开始使用的是mybatis逆向工程,可以生成mapper.xml、mapper.java、pojo
后面我想尝试使用MP做逆向工程,所以使用了两种方式,从简洁上来看,还是MP比较方便一点.
2.1.1 导入依赖逆向工程并且自动添加swagger注解,注意需要在beans的pom也要添加swagger依赖
tk.mybatis mapper-spring-boot-starter 2.1.5
- 修改启动类注解@MapperScan的包,因为这个注解还有个包是org.mybatis.spring.annotation.MapperScan;
org.mybatis.generator mybatis-generator-maven-plugin 1.3.5 true true ${basedir}/src/main/resources/generator/generatorConfig.xml mysql mysql-connector-java 8.0.22 tk.mybatis mapper 4.1.5 com.github.misterchangray.mybatis.generator.plugins myBatisGeneratorPlugins 1.2
同步成功后会出现
2.1.3 添加配置文件generatorConfig.xml
-
调整配置信息
-
创建GeneralDao接口
package com.mymall.general; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; public interface GeneralDao
extends Mapper , MySqlMapper { } -
配置数据库连接信息
-
配置实体类路径
-
配置mapper.xml目录
-
配置dao的目录和生成表的名称
-
将配置文件generatorConfig.xml配置到逆向工程的maven插件中
org.mybatis.generator mybatis-generator-maven-plugin 1.3.5 ${basedir}/src/main/resources/generator/generatorConfig.xml
-
-
将生成的entity剪切到beans子项目中
将生成的entity移到到beans目录之后会出现报错,因为使用了tkMapper的注解,所以需要将tkMapper的依赖直接剪切到beans中,mapper项目引用了beans的依赖所以就可以不再pom中声明tkMapper的依赖了.
package com.qc.dao;
import com.qc.TkMapperDemoApplication;
import com.qc.entity.Category;
import org.apache.ibatis.session.RowBounds;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import tk.mybatis.mapper.entity.Example;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest(classes = TkMapperDemoApplication.class)
@RunWith(SpringRunner.class)
public class CategoryDaoTest {
@Autowired
private CategoryDao categoryDao;
@Test
public void testInsert() {
Category category = new Category(0,"test02",1,0,"01.png","hehe","111.jpg","black");
//将数据插入表中,返回结果,1,成功
//int i = categoryDao.insert(category);
//将数据插入后将生成的主键返回给对象保存
int i = categoryDao.insertUseGeneratedKeys(category);
System.out.println(category.getCategoryId());
assertEquals(1,i);
}
@Test
public void testUpdate() {
Category category = new Category(13,"test03",1,0,"01.png","hehe","111.jpg","black");
//根据主键修改数据
int i = categoryDao.updateByPrimaryKey(category);
assertEquals(1,i);
}
@Test
public void testDelete() {
//根据主键删除数据
int i = categoryDao.deleteByPrimaryKey(13);
assertEquals(1,i);
}
@Test
public void testSelect1() {
//查询所有
List categories = categoryDao.selectAll();
for (Category category : categories) {
System.out.println(category);
}
}
@Test
public void testSelect2() {
// 根据主键查询
Category category = categoryDao.selectByPrimaryKey(13);
System.out.println(category);
}
@Test
public void testSelect3() {
// 条件查询
// 1.创建一个example封装,类别category查询条件
Example example = new Example(Category.class);
Example.Criteria criteria = example.createCriteria();
//criteria.andEqualTo("categoryLevel", 1);
criteria.andLike("categoryName", "%干%");
List categories = categoryDao.selectByExample(example);
for (Category category : categories) {
System.out.println(category);
}
}
@Test
public void testSelect4() {
// 分页查询
int pageNum = 2;
int pageSize= 5;
int start =(pageNum-1)*pageSize;
RowBounds rowBounds = new RowBounds(start,pageSize);
List categories = categoryDao.selectByRowBounds(new Category(), rowBounds);
for (Category category : categories) {
System.out.println(category);
}
// 查询总记录数
int i = categoryDao.selectCount(new Category());
System.out.println(i);
}
@Test
public void testSelect5() {
//准备条件
Example example = new Example(Category.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("categoryLevel", 1);
//准备分页条件
int pageNum = 1;
int pageSize= 3;
int start =(pageNum-1)*pageSize;
RowBounds rowBounds = new RowBounds(start,pageSize);
//条件分页显示
List categories = categoryDao.selectByExampleAndRowBounds(example, rowBounds);
for (Category category : categories) {
System.out.println(category);
}
// 查询满足条件的记录数
int i = categoryDao.selectCountByExample(example);
System.out.println(i);
}
}
2.2 MybatisPlus使用教程
2.2.1 在mapper子项目中添加依赖
2.2.2 配置application.yml在创建mapper子项目的时候已经添加了mybatis-plus-boot-starter,所以这里不需要额外添加依赖
当时用mysql8时,需要mysql的驱动同:com.mysql.cj.jdbc.Driver,同时需要增加时区设置:serverTimezone=GMT%2b8
datasource:
druid:
#数据库连接驱动
driver-class-name: com.mysql.cj.jdbc.Driver
#数据库连接地址
url: jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true
#数据库连接用户名和密码
username: root
password: 123456
2.2.3 配置@MapperScan
package com.mymall;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.oas.annotations.EnableOpenApi;
@SpringBootApplication
@MapperScan("com.mymall.dao")
@EnableOpenApi
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
2.2.4 编写实体类Users
package com.mymall.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Users {
Integer userId;
String username;
String password;
}
2.2.5 编写Mapper.java继承模版baseMapper
package com.mymall.dao; import com.baomidou.mybatisplus.core.mapper.baseMapper; import com.mymall.entity.Users; import org.springframework.stereotype.Repository; @Repository public interface UsersMapper extends baseMapper2.2.6 测试是否能够正常调用MP{ }
package com.mymall;
import com.mymall.entity.Users;
import com.mymall.dao.UsersMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class ApiApplicationTests {
@Autowired
private UsersMapper usersMapper;
@Test
void contextLoads() {
List users = usersMapper.selectList(null);
for (Users user : users) {
System.out.println(user);
}
System.out.println(users);
}
}
测试成功!
2.2.7 配置日志mybatis-plus:
configuration:
# 配置日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
显示效果
-
生成策略:分布式系统唯一ID生成方案汇总 - nick hao - 博客园 (cnblogs.com)
-
雪花算法:snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。雪花算法支持的TPS可以达到419万左右(2^22*1000)。
-
注意:使用雪花或者uuid的时候在数据中的字段不能是自增,不然不会生效.
-
设置要求:
-
主键需要设置成自增
-
实体类字段上添加MP注解@TableId(type = IdType.ASSIGN_ID)
-
IdType类型源码
package com.baomidou.mybatisplus.annotation; import lombok.Getter; @Getter public enum IdType { AUTO(0), NONE(1), INPUT(2), ASSIGN_ID(3), ASSIGN_UUID(4), private final int key; IdType(int key) { this.key = key; } }
-
-
Insert自动生成id
@Test//测试插入 public void insertTest(){ User user = new User(); user.setName("wsk"); user.setEmail("2803708553@qq.com"); Integer result = userMapper.insert(user); //会帮我们自动生成id System.out.println(result); //受影响的行数 System.out.println(user); //通过日志发现id会自动回填 }
创建时间、更改时间! 这些操作一般都是自动化完成,我们不希望手动更新
阿里巴巴开发手册︰几乎所有的表都要配置 gmt_create、gmt_modified !而且需要自动化
-
方式一:数据库级别(工作中不允许修改数据库级别)
1、在表中增加字段:create_time,update_time
-- auto-generated definition create table mp_user ( user_id bigint auto_increment comment '用户id' primary key, username varchar(32) not null comment '用户名', password varchar(32) not null comment '密码', create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', update_time datetime default CURRENT_TIMESTAMP not null comment '更新时间' );2、更新实体类中的成员变量
package com.mymall.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor public class MpUser { @TableId(type = IdType.ASSIGN_ID) Long userId; String username; String password; Date createTime; Date updateTime; }3、再次运行之前插入或更新一条数据的代码显示成功自动插入时间
-
方式二:代码级别
1、删除数据库的默认值,更新操作!
2、实体类字段属性上需要增加注解
@Data @AllArgsConstructor @NoArgsConstructor public class MpUser { @TableId(type = IdType.ASSIGN_ID) Long userId; String username; String password; //插入时注解 @TableField(fill = FieldFill.INSERT) Date createTime; //更新时注解 @TableField(fill = FieldFill.UPDATE) Date updateTime; }注解详情
package com.baomidou.mybatisplus.annotation; public enum FieldFill { DEFAULT, INSERT, UPDATE, INSERT_UPDATE }3、编写处理器来处理这个注解即可!
@Slf4j @Component public class MymetaObjectHandler implements metaObjectHandler { @Override public void insertFill(metaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用) // 或者 this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // 或者 this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) } @Override public void updateFill(metaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐) // 或者 this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // 或者 this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) } }注意事项:
- 填充原理是直接给entity的属性设置值!!!
- 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null
- metaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充
- 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段
- 填充处理器MymetaObjectHandler在 Spring Boot 中需要声明@Component或@Bean注入
- 要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法
- 不需要根据任何来区分可以使用父类的fillStrategy方法
4.测试运行插入或更新语句
在面试过程中经常被问到乐观锁/悲观锁,这个其实很简单
乐观锁:顾名思义十分乐观,他总是认为不会出现问题,无论干什么都不上锁!如果出现了问题,再次更新值测试
悲观锁:顾名思义十分悲观,他总是认为出现问题,无论干什么都会上锁!再去操作!
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
-
取出记录时,获取当前version
-
更新时,带上这个version
-
执行更新时,set version = newVersion where version = oldVersion
-
如果version不对,就更新失败
乐观锁:先查询,获得版本号 -- A update user set name = "wsk",version = version+1 where id = 1 and version = 1 -- B (B线程抢先完成,此时version=2,会导致A线程修改失败!) update user set name = "wsk",version = version+1 where id = 1 and version = 1
-
更新数据库,添加version字段
-- auto-generated definition create table mp_user ( user_id bigint auto_increment comment '用户id' primary key, username varchar(32) not null comment '用户名', password varchar(32) not null comment '密码', version int null comment '乐观锁', create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间', update_time datetime default CURRENT_TIMESTAMP not null comment '更新时间' ); -
实体类添加加对应的字段和注解
@Version Integer version;
-
注册组件
//扫描mapper文件夹 @MapperScan("com.mymall.dao")//交给mybatis做的,可以让这个配置类做扫描 @EnableTransactionManagement//自动管理事务 @Configuration//配置类 public class MyBatisPlusConfig { //注册乐观锁插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } } -
测试
-
测试乐观锁成功
@Test void testOptimisticLocker1() { //1、查询用户信息 MpUser mpUser = mpUserMapper.selectById(1L); //2、修改用户信息 mpUser.setUsername("qq"); //3、执行更新操作 int update = mpUserMapper.updateById(mpUser); System.out.println(mpUser); } -
模拟多线程测试乐观锁插入数据失败
@Test void testOptimisticLocker2() { //线程1 MpUser mpUser = mpUserMapper.selectById(1L); mpUser.setUsername("aa"); mpUser.setPassword("666666"); //模拟另外一个线程执行了插队操作 MpUser mpUser1 = mpUserMapper.selectById(1L); mpUser1.setUsername("bb"); mpUser1.setPassword("12344444"); mpUserMapper.updateById(mpUser1); //自旋锁来多次尝试提交! mpUserMapper.updateById(mpUser);//如果没有乐观锁就会覆盖插队线程的值 }
-
-
通过id查询单个用户
@Test public void testSelectById(){ User user = userMapper.selectById(1L); System.out.println(user); } -
通过id查询多个用户
@Test public void testSelectBatchIds(){ Listusers = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L)); users.forEach(System.out::println); } -
条件查询 通过map封装
@Test public void testMap(){ HashMapmap = new HashMap<>(); //自定义要查询的 map.put("name","www"); map.put("age",18); List users = userMapper.selectByMap(map); users.forEach(System.out::println); } -
分页查询
分页在网站的使用十分之多!
1、原始的limit分页
2、PageHelper第三方插件
3、MybatisPlus其实也内置了分页插件!
使用步骤:
-
配置拦截器组件
package com.mymall.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @MapperScan("com.mymall.dao") @EnableTransactionManagement public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加乐观锁 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); //新的分页插件,一缓和二缓遵循mybatis的规则, //需要设置 MybatisConfiguration#useDeprecatedExecutor = false // 避免缓存出现问题(该属性会在旧插件移除后一同移除) //也可以不传DbType.MYSQL,为空时会通过URL判断数据库类型 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } } -
测试分页查询
@Test public void testPage(){ //参数一current:当前页 参数二size:页面大小 //使用了分页插件之后,所有的分页操作都变得简单了 Pagepage = new Page<>(2,5); //第二个参数是高级查询,暂设为null userMapper.selectPage(page,null); page.getRecords().forEach(System.out::println); System.out.println("总页数==>"+page.getTotal()); }
-
-
基本删除操作
@Test public void testDeleteById(){ userMapper.deleteById(1); } @Test public void testDeleteBatchIds(){ userMapper.deleteBatchIds(Arrays.asList(1,2)); } @Test public void testD(){ HashMapmap = new HashMap<>(); map.put("age","18"); map.put("name","lol"); userMapper.deleteByMap(map); } -
逻辑删除
物理删除:从数据库中直接删除
逻辑删除:在数据库中没有被删除,而是通过一个变量来使他失效! deleted=0 ==> deleted=1
管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
实现步骤:
-
数据库中添加deleted字段
deleted int default 0 null comment '逻辑删除:0显示1删除',
-
添加配置application.yml
mybatis-plus: global-config: db-config: logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) -
在实体类上添加deleted字段并加上@TableLogic注解(上面配置了application.yml后可以不添加注解,但是deleted字段一定要添加)
@TableLogic private Integer deleted;
-
测试删除一条数据后查询是否数据还存在,测试结果,只是deleted设置为了1
@Test void testLogicDelete() { //删除id为2的数据 int i = mpUserMapper.deleteById(2); MpUser mpUser = mpUserMapper.selectById(2); System.out.println(mpUser); }
-
查看数据库,发现记录还在,deleted变为1
再次测试查询被删除的用户,发现查询为空
2.2.13 条件构造器wrapper我们在平时的开发中,会遇到一些慢Sql。测试、druid···
MybatisPlus也提供了性能分析插件,如果超过这个时间就停止运行!
警告:
不支持以及不赞成在 RPC 调用中把 Wrapper 进行传输
- wrapper 很重
- 传输 wrapper 可以类比为你的 controller 用 map 接收值(开发一时爽,维护火葬场)
- 正确的 RPC 调用姿势是写一个 DTO 进行传输,被调用方再根据 DTO 执行相应的操作
- 常用api请到网页中查看条件构造器 | MyBatis-Plus (baomidou.com)
- 使用示例
-
查询不为空且比某值大的数据
@Test void testWrapper() { //参数是一个wrapper ,条件构造器,和刚才的map对比学习! //查询username不为空,password不为空,user_id大于18的用户 //注意这里的column参数一定是字段名,不是实体类中的成员变量 QueryWrapperwrapper = new QueryWrapper<>(); wrapper .isNotNull("username") .isNotNull("password") .ge("user_id",2); List userList = mpUserMapper.selectList(wrapper); userList.forEach(System.out::println); } -
查询某字段值为确定值的数据,返回结果有一个和多个的可能
@Test public void testWrapper2() { //查询name=wsk的用户 QueryWrapperwrapper = new QueryWrapper<>(); wrapper.eq("username","MPInsertTest1"); //查询一个数据selectOne,若查询出多个会报错 //Expected one result (or null) to be returned by selectOne(), but found: * //若出现多个结果使用list或map MpUser mpUser = mpUserMapper.selectOne(wrapper);//查询一个数据,若出现多个结果使用list或map System.out.println(mpUser); List mpUsers = mpUserMapper.selectList(wrapper); } -
查询字段值范围在某个区间的数据
@Test public void testWrapper3() { //查询age在10-20之间的用户的用户数量 QueryWrapperwrapper = new QueryWrapper<>(); wrapper.between("age", 10, 20);//区间 Integer count = userMapper.selectCount(wrapper);//输出查询的数量selectCount System.out.println(count); } -
模糊查询,notLike,likeRight,likeLeft
@Test public void testWrapper4() { //模糊查询 QueryWrapperwrapper = new QueryWrapper<>(); wrapper .notLike("name","s") .likeRight("email","t");//qq% 左和右? List -
子查询
@Test public void testWrapper5() { // SELECT id,name,age,email,version,deleted,create_time,update_time //FROM user //WHERe deleted=0 AND id IN //(select id from user where id<5) QueryWrapperwrapper = new QueryWrapper<>(); //id 在子查询中查出来 wrapper.inSql("id","select id from user where id<5"); List -
通过id进行排序
@Test public void testWrapper6() { QueryWrapperwrapper = new QueryWrapper<>(); //通过id进行降序排序 wrapper.orderByDesc("id"); List userList = userMapper.selectList(wrapper); userList.forEach(System.out::println); }
-
-
添加依赖
MyBatis-Plus 从 3.0.3 之后移除了代码生成器与模板引擎的默认依赖,需要手动添加生成器和模版引擎依赖
这里尝试使用3.5.1版本(以下教程仅适用 3.5.1 以上版本,对历史版本的不兼容)
// 注意!!当前包未传递依赖 mp 包,需要自己引入
com.baomidou mybatis-plus-generator Latest Version 添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎。这里按照官方文档选择了freemarker
Velocity(默认):
Freemarker:org.apache.velocity velocity-engine-core latest-velocity-version Beetl:org.freemarker freemarker 2.3.31 com.ibeetl beetl latest-beetl-version -
在mapper子项目中创建代码生成器配置类
package com.mymall; import com.baomidou.mybatisplus.generator.FastAutoGenerator; import com.baomidou.mybatisplus.generator.config.OutputFile; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; import java.util.Collections; public class CodeGenerator { public static void main(String[] args) { FastAutoGenerator.create("jdbc:mysql://localhost:3306/mymall?serverTimezone=GMT%2b8&useSSL=false&allowPublicKeyRetrieval=true", "root", "123456") .globalConfig(builder -> { builder.author("QC") // 设置作者 .enableSwagger() // 开启 swagger 模式 .fileOverride() // 覆盖已生成文件 //禁止打开目录 .disableOpenDir() // 指定输出目录,这里使用绝对路径 .outputDir("F:\JavaProjcet\MyMallPractice2\mapper\src\main\java"); //如果使用/src/main/java会在根目录下创建文件,也就是没成功 //源码:this.outputDir = System.getProperty("os.name").toLowerCase().contains("windows") ? "D://" : "/tmp"; //System.getProperty("os.name")获取操作系统名称,如果名称包含windows就"D://"否则就"/tmp" //判断是windows系统,否则就是linux系统,所以还是只能使用绝对地址 //.outputDir("classpath:/src/main/java"); }) .packageConfig(builder -> { builder.parent("com.mymall") // 设置父包名 //.moduleName("mapper") // 设置父包模块名,也就是在父包名中添加一个包 //但是这里设置相对路径成功了一次,但后面还是生成了根目录,所以还是使用绝对路径 //.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "/src/main/resources/mapper")); // 设置mapperXml生成路径 .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F:\JavaProjcet\MyMallPractice2\mapper\src\main\resources\mapper")); // 设置mapperXml生成路径 }) .strategyConfig(builder -> { builder.addInclude("users") // 设置需要生成的表名 .addInclude("category") .addInclude("index_img") .addInclude("mp_user") .addInclude("product") .addInclude("product_sku") .addInclude("product_img") .addInclude("orders") .addInclude("product_comments") .addInclude("product_params") //.setEntityLombokModel(true) //开启lombook支持,新版本已经没有了 .addTablePrefix("mp_"); // 设置过滤表前缀,也就是将前缀去掉,只保留后面对的内容作为实体名 }) .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 .execute(); } }生成成功
解决办法:将gerneratorConfig.xml中的url改成useSSL=false
connectionURL="jdbc:mysql://localhost:3306/mymall?useSSL=false&serverTimezone=GMT%2b8"&useUnicode=true&characterEncoding=utf-83.2 插件没找到
解决:调整mybatis-generator-maven-plugin版本
3.3 将数据库中的其他表都生成了org.mybatis.generator mybatis-generator-maven-plugin 1.3.5
解决:在gerneratorConfig.xml只添加需要生成的表名
解决办法:
-
修改我的表名称
-
想办法不让MySql保留表影响到我的逆向工程
要保证只生成自己指定的 database 中的 User 表,首先要在 中的 connectionURL 中指定数据库的实例名,然后在 中添加相关配置信息,即 ,即可保证只生成自己需要的 User 类。
配置如下:



