mybatis-plus 入门和进阶
简介
所有的crud的代码都可以自动完成
JAP、tk -mapper、mybatis-plus
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
快速入门
地址:官网地址
使用第三方插件
-
导入依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency>
-
写入配置
-
编写代码
步骤
-
创建数据库 mybatis-plus
-
创建表
DROP TABLE IF EXISTS user; CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年龄', email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱', PRIMARY KEY (id) ); -- 真实开发中 version(乐观锁)、deleted(逻辑删除) gmt_create、gmt_modified
-
插入数据
INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');
-
添加依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<!--这个是非官方的 尽量不要同时导入mybatis-->
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
-
连接数据库
mysql 5 和,mysql8有区别,但是可以先前兼容,但不同版本最好写成不一样的
# mysql5 com.mysql.jdbc.Driver
# mysql8 com.mysql.cj.jdbc.Driver 需要增加时区配置 serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#运行错误
#1、就是mysql版本不能太高
#2、单元测试少包
#配置日志,输出到控制台
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
逻辑代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Lf9T3tq-1607589902913)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1607155042072.png)]
@Repository
public interface UserMapper extends BaseMapper<User> {
}
@MapperScan("com.yanghao.mybatis_plus.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//对应数据库中主键(uuid、自增id、雪花算法、redis、zookeeper)
@TableId(type = IdType.ID_WORKER)
private Long id;//这要用大写的Long
private String name;
private Integer age;
private String email;
}
思考问题?
- sql 谁帮我们写? mybatis-plus
- 方法都已经写好啦
测试插入
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;
// 查询所有
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
// 插入
@Test
void contextLoads2() {
User user = new User();
user.setAge(12);
user.setName("zhangsan");
user.setEmail("112344151@qq.com");//帮我们自动生成id
int insert = userMapper.insert(user);
System.out.println(insert);
}
//更新,通过字符串进行拼接,传入的是一个对象
@Test
void contextLoads3() {
User user = new User();
user.setId(0L);
user.setName("lisi");
int insert = userMapper.updateById(user);
System.out.println(user);
System.out.println(insert);
}
}
主键自增
//自增,但是数据库必须成设置自增,否则报错
@TableId(type = IdType.AUTO)
private Long id;//这要用大写的Long
//其他源码解释
public enum IdType {
AUTO(0),//自增
NONE(1),//未设置
INPUT(2),//需要手动设置id
ASSIGN_ID(3),
ASSIGN_UUID(4),//uuid
ID_WORKER(3),//默认全局唯一
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5yprtXjC-1607589902917)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1607156182834.png)]
CRUD扩展
时间填充
自动填充
创建时间、修改时间。这些操作自动完成。
数据库界级别
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NUwJO3kY-1607589902919)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1607158676929.png)]
代码级别的自动填充时间
//实体类中的配置
@TableField(fill = FieldFill.INSERT)//插入的时候起作用
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//更新和插入的时候都起作用
private Date updateTime;
//需要配置类中说明
//@Slf4j是用作日志输出的,一般会在项目每个类的开头加入该注解,如果不写下面这段代码,并且想用log
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//更新时填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁
乐观锁:顾名思义,认为不会出现问题,出了问题,再更新测试
悲观锁:干什么都会上锁。
乐观锁实现方式:
-
取出记录时,获取版本version
-
更新时带上这个版本
-
执行更新时 set version=new version where version =oldversion
-
如果version不对,就更新失效
乐观锁 1、先查询,获取版本号 version=1 A--- set name='张三' ,version=version+1 where version=1 and id=2 B---线程强先完成,会导致A更新失败 set name='李四' ,version=version+1 where version=1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TO0fSqVe-1607589902926)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1607232089902.png)]
1、添加字段
@Version //乐观锁version注解
private Integer version;
2、注册组件
@MapperScan("com.yanghao.mybatis_plus.mapper")//可以把启动类中的注解移到这
@EnableTransactionManagement //开启事务
@Configuration//配置类
public class MybatisPlusConfig {
//注册乐观锁组件
@Bean
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
return new OptimisticLockerInnerInterceptor();
}
}
//上面那个拦截器用不了,需要包装一层MybatisPlusInterceptor
@MapperScan("com.yanghao.mybatis_plus.mapper")//可以把启动类中的注解移到这
@EnableTransactionManagement //开启事务
@Configuration//配置类
public class MybatisPlusConfig {
//注册乐观锁组件
@Bean
public MybatisPlusInterceptor optimisticLockerInnerInterceptor() {
// return new OptimisticLockerInnerInterceptor();
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
3、测试
//测试乐观锁,第一个user没更改成功
@Test
void contextLoads4() {
User user = userMapper.selectById(0L);
user.setName("yanghao");
//模拟另一个线程插队
User user2 = userMapper.selectById(0L);
user2.setName("lihao");
userMapper.updateById(user2);
//可以尝试使用自旋锁。
userMapper.updateById(user);
}
其他api的使用
//根据id查询多个用户
@Test
void contextLoads5() {
// List<User> users = userMapper.selectList();
List<User> users = userMapper.selectBatchIds(Arrays.asList(0, 1, 2));
users.forEach(System.out::println);
} //按条件查询之一使用map,就是存储的where条件
@Test
void contextLoads6() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","lihao");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
分页查询
网站分页技术非常多!
- 原始limit
- pageHelper
- MP内置插件
如何使用
-
配置拦截器插件即可
@Bean public PaginationInnerInterceptor paginationInnerInterceptor(){ return new PaginationInnerInterceptor(); } //上面这个不好使啦 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }
-
直接使用page对象即可
@Test void contextLoads7() { /** * @Param 1 当前页 * @Param 2 当前页大小 */ Page<User> page = new Page<>(1,5); Page<User> userPage = userMapper.selectPage(page, null); userPage.getRecords().forEach(System.out::println); System.out.println(page.getTotal()); }
删除操作
@Test
void contextLoads9() {
int i = userMapper.deleteBatchIds(Arrays.asList(0,1));
}
//通过map删除,map代表where后面的条件
@Test
void contextLoads10() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","Tom");
int i = userMapper.deleteByMap(map);
}
逻辑删除
物理删除:从数据库总删除
逻辑删除:用一个变量表示他删除,其实没删除,类似于垃圾箱。delete
管理员可以查看
@TableLogic //逻辑删除
private Integer deleted;
配置文件
mybatis-plus.global-config.db-config.logic-delete-value=1 #表示逻辑删除
mybatis-plus.global-config.db-config.logic-not-delete-value=0 #表示未删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YywRKYYE-1607589902926)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1607250796786.png)]
//是一个更新操作,并不删除
int i = userMapper.deleteBatchIds(Arrays.asList(2));
#配置开发环境
spring.profiles.active=dev
性能分析插件
作用:拦截慢sql,用于输出每条sql运行时间
-
导入插件
这个性能分析插件早,3.2以上就没有啦 @Bean @Profile({"dev", "test"})// 设置 dev test 环境开启 public PerformanceInterceptor performanceInterceptor() { return new PerformanceInterceptor(); } <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency>
-
测试使用
@Test
void contextLoads() {
// 查询 name 不为空的用户,并且邮箱不为空的用户,年龄大于等于12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age","12");//ge表示大于
userMapper.selectList(wrapper).forEach(System.out::println);// 和我们学习的 Map 对于以下
}
@Test
void contextLoads2() {
// 查询 name 不为空的用户,并且邮箱不为空的用户,年龄大于等于12
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.eq("name","yanghao");//name等于yanghao
userMapper.selectOne(wrapper).forEach(System.out::println);// 和我们学习的 Map 对于以下
}
@Test
void contextLoads13() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,24);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
//左右模糊查询
@Test
void contextLoads14() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.notLike("name","e")
.likeRight("email","t");
//Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted //FROM user WHERE deleted=0 AND (name NOT LIKE ? AND email LIKE ?)
//==> Parameters: %e%(String), t%(String)
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
//嵌套查询
@Test
void contextLoads15() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from user where id<5");
userMapper.selectList(wrapper).forEach(System.out::println);
}
//排序查询
@Test
void contextLoads16() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");//按id降序查询
wrapper.orderByAsc("id");//升序排列
userMapper.selectList(wrapper).forEach(System.out::println);
}
代码自动生成器
AutoGenerator是mybatis-plus的自动生成器,可以快速生成Entity、Mapper、Mapper.xml、service
等各种模块,提高效率。
<!--mybatis-plus 码生成器 添加 模板引擎依赖 这个需要增加模板引擎依赖,如freemarker-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatisPlus.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
自动生成代码
public class GenerateCode {
public static void main(String[] args) {
//构建代码生成器对象
AutoGenerator generator = new AutoGenerator();
GlobalConfig gc = new GlobalConfig();//全局配置
String property = System.getProperty("user.dir");//项目目录
gc.setOutputDir(property+"/src/main/java");
gc.setAuthor("yanghao");
gc.setOpen(false);
gc.setFileOverride(false);//是否覆盖
gc.setServiceName("%sService");//去掉Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
generator.setGlobalConfig(gc);
//设置数据源
DataSourceConfig config = new DataSourceConfig();
config.setUrl("jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false&useUnicode=true&characterEncoding=utf-8");
config.setUsername("root");
config.setPassword("root");
config.setDriverName("com.mysql.jdbc.Driver");
config.setDbType(DbType.MYSQL);
generator.setDataSource(config);
//包的配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setModuleName("com.yanghao.mybatis_plus");
packageConfig.setParent("com.yanghao.mybatis_plus");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setService("service");
packageConfig.setController("controller");
generator.setPackageInfo(packageConfig);
//策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setInclude("user");//设置映射的表名
strategyConfig.setNaming(NamingStrategy.underline_to_camel);//驼峰命名法
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
//strategyConfig.setSuperEntityClass("自己的父类实体,没有就不用设置");
strategyConfig.setEntityLombokModel(true);
strategyConfig.setRestControllerStyle(true);
strategyConfig.setLogicDeleteFieldName("deleted");
//自动填充配置
TableFill gmt_createTime = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmt_updateTime = new TableFill("gmt_update",FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFill = new ArrayList<>();
tableFill.add(gmt_createTime);
tableFill.add(gmt_updateTime);
strategyConfig.setTableFillList(tableFill);
//乐观锁配置
strategyConfig.setVersionFieldName("version");
strategyConfig.setControllerMappingHyphenStyle(true);
generator.setStrategy(strategyConfig);
generator.execute();
}
}
特此说明:
本文章来自狂神,可以bilibili搜索狂神说。