(MP)MybatisPlus教程
Mybatis-Plus教程
1.Mybatis-Plus的简介
(写这篇博客时发现自己很多基础都忘了**JDBC,MYSQL,MYBATIS,**在我复习完这些时,争取写一篇MP源码级的教程)
MybatisPlus是一种为了简化开发,提高效率而制作的Mybatis的插件。主要用来屏蔽重复的Sql语句编写,使得开发人员可以使用编程(调方法)的方式来完成数据库中数据的CRUD操作。
// 查询表中一个信息
User user = userMapper.selectOne(new QueryWrapper<User>(
User.builder().id(6l).build()
));
等价于 Select * from User where id = 6;
// 同时:userMapper.selectList();代表查询所有数据
通过调用方法来避免编写重复的Sql语句,更加符合业务程序员的习惯的风格。但是这种方式无异于让初学者逐渐丧失编写sql的能力,同时由于MybatisPlus中存在的些许小坑(这些坑大多是由于使用中忽略了MybatisPlus的一些规定,并非MP本身的缺陷),可能给实际项目中带来一些不太危险的后果。
- 我们是否应该学习MP
不管你用不用MP,我都建议你学习一下MP- 学习成本并不高——通常16个小时足够学习结束
- MP确实很实用和强大
- 是否应该使用MP
如果你是团队中的某个成员,我不推荐日常开发中使用MP,因为这样会让你个人丧失战斗力。如果你是项目的负责人,从开发效率的角度可以使用,但是要对MP非常熟悉。
总结一句话:应该学习,但不应该使用。
MP前言
MP支持的数据库:
- mysql 、postgresql 、oracle 。
- mariadb 、db2 、h2 、hsql 、sqlite 、、sqlserver 、presto 、Gauss 、Firebird
- Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库 。
(很多数据库都没听过)
MP的架构
Quick Start
- 数据准备
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)
);
DELETE FROM user;
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');
- 新建SpringBoot项目
- 实际编码
//1. 编写实体类
/**
* @author :是雄不是熊
* @date :Created in 2020/9/21 4:10 下午
* @description:User
* @modified By:
* @version: $
*/
@Builder
@Data
@TableName
public class User {
@TableId(value = "id", type = IdType.ASSIGN_ID/*, type = IdType.ASSIGN_ID*/)
private Long id;
@TableField(value = "name", fill = FieldFill.UPDATE/*, condition = SqlCondition.LIKE*/)
private String name;
@TableField(value = "age", update = "%s+1")
private Integer age;
// @EnumValue
@TableField(value = "email", fill = FieldFill.INSERT, updateStrategy = FieldStrategy.IGNORED)
// @TableLogic(value = "Tomm@email", delval = "delval@email")
private String email;
/* @TableField(exist = false)
private String phoneNumber;*/
}
//2. 编写UserMapper接口,继承BaseMapper<T>接口
public interface UserMapper extends BaseMapper<User> {
}
//3. Application需要添加@MapperScan注解 why?后面要了解
@SpringBootApplication
@MapperScan
public class HaloApplication {
public static void main(String[] args) {
SpringApplication.run(HaloApplication.class, args);
}
}
//4.编写测试用例
@RunWith(SpringRunner.class)
@SpringBootTest
class HaloApplicationTests {
@Autowired
private UserMapper userMapper;
@Autowired
private UserIService userIService;
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
// Assert.assertEquals(6, userList.size());
userList.forEach(System.out::println);
}
}
5.运行结果
User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=wangerha, age=35, email=null)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)
User(id=6, name=Tomm, age=19, email=delval@email)
User(id=11, name=nosnakflow, age=18, email=nosnakflow@email)
User(id=1308430037258141697, name=wangxiaoxiao, age=18, email=wangxiaoxiao@email))
数据不一致是因为我对其中的数据进行了修改
注解
1. @TableName
@TableName表示数据库中表的名字
属性 | 类型 | 必须指定 | 默认 | 描述 | 备注 |
---|---|---|---|---|---|
value | s | s | s | s | 数据 |
schema | |||||
resultMap | String | 否 | “” | xml 中 resultMap 的 id,代表返回结果映射 | 返回结果的封装 |
autoResultMap | boolean | 否 | false | 表示是否自动构建ResultMap,如果设置了ResultMap则不会自动构建 | 后续看源码todo |
keepGlobalPrefix | boolean | 否 | false | 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入) |
备注:
- resultMap
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。 - schema是什么?
此处的schema代表的即是数据库中的schema,只不过每个数据库对schema定义不一样,mysql中基本与数据库相同.在pgsql中一个数据库可有多个schema todo:学习数据库中schema知识
schema设置:
a. schema = "mybatisplus"(此处的“mybatisplus”随数据库的名字而变化)
@TableName(value = "user", keepGlobalPrefix = true, schema = "mybatispluss")
public class User {}
当我把schema的值写错之后,报以下错误
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown database 'mybatispluss'
- keepGlobalPrefix的设置
a.设置前缀
mybatis-plus.global-config.db-config.table-prefix=t_
当我修改user表为t_user表时,运行test报
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table 'mybatisplus.user' doesn't exist
b.增加keepGlobalPrefix=true时 运行正常
@TableName(value = "user", keepGlobalPrefix = true)
public class User {
这到底是不是一个实用的点呢????我觉得这个作用有点浮夸
// @TableName源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public @interface TableName {
String value() default "";
String schema() default "";
boolean keepGlobalPrefix() default false;
String resultMap() default "";
boolean autoResultMap() default false;
String[] excludeProperty() default {};
}
@Builder
@Data
@TableName
public class User {
@TableId(value = "id", type = IdType.ASSIGN_ID/*, type = IdType.ASSIGN_ID*/)
private Long id;
@TableField(value = "name", fill = FieldFill.UPDATE/*, condition = SqlCondition.LIKE*/)
private String name;
@TableField(value = "age", update = "%s+1")
private Integer age;
// @EnumValue
@TableField(value = "email", fill = FieldFill.INSERT, updateStrategy = FieldStrategy.IGNORED)
// @TableLogic(value = "Tomm@email", delval = "delval@email")
private String email;
/* @TableField(exist = false)
private String phoneNumber;*/
}
2. @TableId
@TableId代表表中的主键
属性 | 类型 | 必须指定 | 默认 | 描述 | 备注 |
---|---|---|---|---|---|
value | String | 否 | “” | 主键字段名 | 无 |
type | enum | 否 | IdType.NONE | 主键生成策略 | (IdType) |
备注:
1). IdType
值 | 描述 |
---|---|
AUTO | 数据库id自增 |
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | insert前自行set主键值 |
ASSIGN_ID | 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法) |
ASSIGN_UUID | 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法) |
备注:单独使用nextId,nextUUID:
@Test
public void snakeFlow() {
IdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator();
System.out.println(identifierGenerator.nextId(new Object()));
System.out.println(identifierGenerator.nextUUID(new Object()));
}
nextId:1310190714772242434 雪花算法:默认为Number/String 17——18位
nextUUID:177137f0aa2096a74eff12783a11cbc8 UUID:默认为String类型 约32位
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
String value() default "";
IdType type() default IdType.NONE;
}
3. @TableField
@TableField:代表表中的字段名称
@Builder
@Data
@TableName(value = "user", keepGlobalPrefix = true, schema = "mybatisplus")
public class User {
...
@TableField(exist = false)
private String phoneNumber;
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableField {
String value() default "";
// 此属性使用报错,显示org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
// Error querying database. Cause: java.lang.IndexOutOfBoundsException: Index: 4, Size: 4 不知道是不是MP的bug
boolean exist() default true;
//
String condition() default "";
String update() default "";
FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
FieldFill fill() default FieldFill.DEFAULT;
boolean select() default true;
boolean keepGlobalFormat() default false;
JdbcType jdbcType() default JdbcType.UNDEFINED;
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
boolean javaType() default false;
String numericScale() default "";
}
@Version
@EnumValue
@TableLogic
@SqlParser
@KeySequence