表名注解,当数据库中的表名和实体类名之间不能完全匹配时,需要使用这个注解进行绑定。
如:数据库表中的数据库表名为 t_student
,而实体类的类名为: Student
,则需要在该类上增加注解:
@TableName(value = "t_student")
public class Student {
private Long stuId;
}
当数据库表中的所有表名前有前缀时,需要每次指定 @TableName
注解,很麻烦,需要使用全局配置:
mybatis-plus:
global-config:
db-config:
table-prefix: "t_"
主键注解,当数据库中的主键和实体类中主键属性不同时,使用这个注解进行绑定。 如:数据库表中的主键是 id
,而实体类中的属性值是 stuId
,那么就在实体类主键属性上加上注解
public class Student {
@TableId(value = "id")
private Long stuId;
}
@TableId
注解还有一个属性配置是主键的主键类型,具体可选值如下,默认值为:IdType.NONE
值 | 描述 |
AUTO | 数据库自增 |
INPUT | 自行输入 |
ID_WORKER | 分布式全局唯一ID 长整型类型 |
UUID | 32位UUID字符串 |
NONE | 无状态(默认) |
IDWORKERSTR | 分布式全局唯一ID 字符串类型 |
全局设置设置注解策略
设置主键策略,默认值:ID_WORKER
mybatis-plus:
global-config:
db-config:
id-type: AUTO
mybatisPlus 有一个全局的配置策略,可以实现数据库表中的列名字段是下划线分割,自动对应实体类中驼峰名:
如:数据库中的 stu_address
字段与实体类中的 stuAddress
属性字段相对应。
mybatis-plus:
global-config:
db-config:
table-underline: true
# 表名、是否使用下划线命名(默认 true:默认数据库表下划线命名)
在 Springboot 中,可以通过设置 map-underscore-to-camel-case
属性为 true 来开启驼峰功能。因此 mybatisPlus 也继承了这种配置,默认为 true:
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
当显示配置的时候,则按设置的值为准。
标识该字段是数据库表字段,当实体类中有属性字段不在数据库表中的时候,就需要在数据库操作时忽略这些字段,因此可以配置 exist=false
属性配置,如果不配置,默认为:true
BaseMapper 接口是专门用来进行通用增删改查的接口,通过指定泛型可以对数据实体对象进行通用的CIUD操作,大致可以分为四类:
intinsert(T entity)
insert 方法会将实体对象中的非空属性值映射到数据库,进行插入操作,也就是说有多少非空属性,执行的SQL语句中才插入多少,和 mybatis 中的 insertSeletive 一样,有值才操作。
亮点:
插入成功默认返回主键,mybatis Plus 插入数据之后,实体类中的主键会返回给实体类,相比 mybatis 原生的默认不返回要很多繁琐的配置:
id="insert" useGeneratedKeys="true" keyProperty="stuId" parameterType="org.woodwhales.king.Student">
insert into student(userName, password, comment)
values(#{userName}, #{password}, #{comment})
其中: keyProperty
中配置的是实体类中的属性字段,用来接收数据库表返回的主键值。
intupdateById(T entity)
intupdate(T entity,Wrapper
如:更新姓名为 Tom
且年龄为 28 的学生数据:
LambdaQueryWrapper
.eq(Student::getName, "Tom")
.eq(Student::getAge, 28);
Student student = Student.builder()
.name("woodwhales")
.age(20)
.email("[email protected]").build();
int row = studentMapper.update(student, lambdaQueryWrapper);
SQL脚本执行日志:
==> Preparing: UPDATE student SET name=?, age=?, email=? WHERE name = ? AND age = ?
==> Parameters: woodwhales(String), 20(Integer), [email protected](String), Tom(String), 28(Integer)
<== Updates: 1
EntityWapper
注意:条件构造器中使用的是数据列名,而不是实体类对象属性。
对于条件构造器的编写,可以使用最原始写法:
QueryWrapper
queryWrapper.eq(“stu_name”, "Tom");
queryWrapper.like("email", "woodwhale");
也可以使用 QueryWrapper
这样类似于 JDK1.8 的 lambda表达式
编写条件构造器,下文中均采用此写法。
例:查询数据库中 student 表( Student
实体类)中的所有姓名为 Tom
且年龄在10-20 岁之间的分页数据,当前页为 1,每页显示数为 2
IPage
new QueryWrapper
.eq(Student::getName, "Tom")
.between(Student::getAge, 10, 20));
List
studentList.forEach(System.out::println);
System.out.println("total: " + pager.getTotal());
System.out.println("pages: " + pager.getPages());
System.out.println("size: " + pager.getSize());
SQL脚本执行日志:
==> Preparing: SELECT id,name,age,email FROM student WHERE name = ? AND age BETWEEN ? AND ? LIMIT ?,?
==> Parameters: Tom(String), 10(Integer), 20(Integer), 0(Long), 1(Long)
注意:上面代码查询出来的对象 pager
中的 total
和 pages
总是为 0 ,解决办法:编写一个配置类,自定义一个分页插件 PaginationInterceptor
配置到 spring 中即可:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
@Configuration
public class AppConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType(DbType.MYSQL.getDb()); // 设置数据库方言
return page;
}
}
上述代码中:只需要返回 newPaginationInterceptor()
即可使得 selectPage
返回对象中有数据总记录数。
查询数据库中 student 表( Student
实体类)中的所有邮箱名字含有 woodwhale
且年龄在10-20 岁之间的所有数据:
List
.lambda()
.like(Student::getEmail, "woodwhale")
.between(Student::getAge, 10, 20));
SQL脚本执行日志:
==> Preparing: SELECT id,name,age,email FROM student WHERE email LIKE ? AND age BETWEEN ? AND ?
==> Parameters: %woodwhale%(String), 10(Integer), 20(Integer)
IPage
new QueryWrapper
.eq(Student::getName, "Tom")
.between(Student::getAge, 10, 20)
.or()
.like(Student::getEmail, "woodwhale"));
注意: or()
中可以传参一个布尔表达式,当条件为 false
时,或者作用失效,后面的条件会与前面的条件形成并且的关系。引用官方的解释:
主动调用
or
表示紧接着下一个方法不是用and
连接!(不调用or
则默认为使用and
连接)
SQL脚本执行日志:
==> Preparing: SELECT COUNT(1) FROM student WHERE name = ? AND age BETWEEN ? AND ? OR email LIKE ?
==> Parameters: Tom(String), 10(Integer), 20(Integer), %woodwhale%(String)
==> Preparing: SELECT id,name,age,email FROM student WHERE name = ? AND age BETWEEN ? AND ? OR email LIKE ? limit ?
==> Parameters: Tom(String), 10(Integer), 20(Integer), %woodwhale%(String), 1(Long)
orderBy(booleancondition,booleanisAsc,R...columns)
对查询的结果进行降序排列( isAsc
设置成了 false
)
List
studentList.forEach(System.out::println);
SQL 脚本执行日志:
==> Preparing: SELECT id,name,age,email FROM student ORDER BY age DESC
==> Parameters:
<== Total: 8
mybatis Plus 提供了更加便捷的方法:
降序排序
orderByDesc(R column)
orderByDesc(R...columns)
orderByDesc(booleancondition,R...columns)
升序排序
orderByAsc(R column)
orderByAsc(R...columns)
orderByAsc(booleancondition,R...columns)
ActiveRecord
必须存在对应的 原始mapper
并继承 baseMapper
并且可以使用的前提下,才能使用此 AR 模式。
实体类对象继承 Model
抽象类即可。
@Data
@Builder
public class Student extends Model
@TableId(type=IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
对数据的增删改查操作,直接操作自己即可。
Student student = Student.builder().id(null).name("adc").age(20).email("[email protected]").build();
boolean insert = student.insert();
领域模式下查询主键的方法,有参数传入时以传入为准,无参数时以对象为准。当对象没有主键时,会报 com.baomidou.mybatisplus.core.exceptions.MybatisPlusException:selectById primaryKeyisnull.
异常,删除主键的方法同理,另外删除逻辑上不存在的数据也是返回成功。
Student student = Student.builder().id(5L).build();
Student result = student.selectById(6L);
SQL脚本执行日志:
==> Preparing: SELECT id,name,age,email FROM student WHERE id=?
==> Parameters: 6(Long)
<== Total: 1
分页返回的数据对象是 IPage
,从 IPage
可以获取相应的总记录数,记录,当前页,每页数。
IPage
AutoGenerator 是 MyBatis-Plus 的代码生成器,MyBatis-Plus 的代码生成器比 Mybatis 原生的代码生成器强大的地方在于,能够快速生成通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
以下代码生成器中开启了 lombok
, sprigboot-web
, swagger2
, freemarker
,因此需要添加依赖:
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-web
com.baomidou
mybatis-plus-boot-starter
3.1.0
com.alibaba
druid
1.1.10
com.baomidou
mybatis-plus-generator
3.1.0
org.springframework.boot
spring-boot-starter-freemarker
io.springfox
springfox-swagger2
2.7.0
io.springfox
springfox-swagger-ui
2.7.0
import java.util.ArrayList;
import java.util.List;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
public class Generator {
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setActiveRecord(true); // 开启领域模式
gc.setIdType(IdType.AUTO);
gc.setServiceName("%sService"); // 各层文件名称方式,例如: %sAction 生成 UserAction
gc.setOutputDir(projectPath + "/src/main/java"); // 生成文件的输出目录【默认 D 盘根目录】
gc.setAuthor("woodwhales"); // [开发者]
gc.setFileOverride(true); // 开启文件覆盖
gc.setOpen(false); // 是否打开输出目录
gc.setSwagger2(true); // 开启 swagger2 模式
gc.setBaseResultMap(true); // 开启 BaseResultMap
gc.setBaseColumnList(true); // 开启 baseColumnList
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mytest?useUnicode=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver"); // 注意:mysql 5.7 之后的驱动是com.mysql.cj.jdbc.Driver
dsc.setDbType(DbType.MYSQL);
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setParent("org.woodwahles"); // [实体类所在模块的父模块名]
pc.setModuleName("king"); // [实体类所在模块名]
pc.setXml("mapper"); // 默认包名:mapper.xml
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义mapper文件名称
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/"
+ tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
mpg.setTemplate(new TemplateConfig().setXml(null));
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel); // 下划线转驼峰命名
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setInclude("student"); // [表名]
strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
// strategy.setTablePrefix(pc.getModuleName() + "_"); // 数据库表名前缀
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
生成的项目结构如下:
作用!阻止恶意的全表更新删除
@Configuration
public class AppConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType(DbType.MYSQL.getDb()); // 设置数据库方言
List
// 攻击 SQL 阻断解析器、加入解析链
sqlParserList.add(new BlockAttackSqlParser());
page.setSqlParserList(sqlParserList);
return page;
}
}
该插件只用于开发环境,不建议生产环境使用。
@Configuration
public class AppConfig {
/**
* 性能分析插件
*/
@Bean
@Profile({"dev","test"}) // 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
// maxTime 指的是 SQL 执行最大时长,超过自动停止运行,有助于发现问题。
performanceInterceptor.setMaxTime(100);
// SQL 是否格式化
performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
}
目的:当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁的实现思路:
取出记录时,获取当前 version
更新时,带上这个 version
执行更新时, set version = newVersion where version = oldVersion
如果 version
不对,就更新失败
插件使用步骤:
1. 将插件注入spring 框架:
@Configuration
public class AppConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
2. 使用注解 @Version
注解实体字段(必要步骤)
@Version
private Integer version;
特别说明:
支持的数据类型只有: int
, Integer
, long
, Long
, Date
, Timestamp
, LocalDateTime
整数类型下 newVersion=oldVersion+1
newVersion
会回写到 entity
中
仅支持 updateById(id)
与 update(entity,wrapper)
方法
在 update(entity,wrapper)
方法下, wrapper不能复用!
首先指定逻辑删除字段在数据库表中的取值:
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
将插件注入spring中:
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfiguration {
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
实体类字段上加上 @TableLogic
注解
@TableLogic
private Integer deleted;
使用 Mybatis-Plus 自带方法删除和查找都会附带逻辑删除功能(自己写的 xml
不会)
MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。
安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx
搜索并安装。
插件功能:Java 与 XML 调回跳转,Mapper 方法自动生成 XML。
插件源码:https://gitee.com/baomidou/MybatisX。
-END-