MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
mybatis-plus写的sql与方法
步骤:
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, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
---- 真实开发中,version(乐观锁)、delete(逻辑删除)、gmt_create等
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>最新版本version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.32version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
说明:使用mybatis-plus可以节省大量打啊代码,尽量不用同时导入mybatis和mybatis-plus!(可能会冲突)
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#Mysql8版本需要在url上单独配置时区(serverTimezone=Asia/Shanghai),同时两者的驱动也是有差异的
编写pojo
创建mapper接口
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
// 在对应的Mapper接口上面继承基本的类BaseMapper
@Mapper
//@Repository //代表是Mapper层即可
public interface UserMapper extends BaseMapper<User> {
//所有的crud已基本完成了
//不用需要像之前配置大量文件了
}
注意点:我们需要再主启动类上去扫描我们的mapper包下的所有接口
@MapperScan("com.yjr.springboot005mybatis_plus.mapper")
测试
@SpringBootTest
class Springboot005MybatisPlusApplicationTests {
// 继承了BaseMapper,所有的方法都来自自己的父类,我们可以编写自己的拓展方法。
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//参数是一个Wrapper,条件构造器,这里不用写写为null
//查询所有的用户
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
配置日志
# 配置日志--控制台输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
//测试插入
@Test
public void insert(){
User user=new User();
//mybatis-plus会自动生成id
user.setAge(3);
user.setName("radan");
user.setEmail("[email protected]");
int insert = userMapper.insert(user);//insert是受影响的行数
System.out.println(insert);
System.out.println(user);//当执行insert方法时,mybatis-plus会自动生成id
}
public void update(){
User user=new User();
// user.setAge(3);
user.setId(4l);
// user.setName("radan");
user.setEmail("[email protected]");
//注意:updateById 但是参数是一个对像!重点:通过条件就会拼接sql
// UPDATE user SET name=?, age=?, email=? WHERE id=?
// UPDATE user SET email=? WHERE id=?
int i = userMapper.updateById(user);//受影响的行数
System.out.println(i);
}
对应数据库中的组件 (UUID,自增id,雪花算法,redis生成)
默认ASSIGN_ID全局唯一策略
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想:使用41bit作为毫秒数,10bit作为机器的ID(5bit是数据中心,5个bit是机器的ID),12bit作为毫秒内的流水号(意味着每个节点在没毫秒可以产生4096个ID),最后还有一个符号位,永远是0。
主键自增
IdType 类其它的源码解释
代码级别操作
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
@Component //一定不要忘记将处理器加到IOC容器当中
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("插入填充");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("更新填充");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁:十分乐观,认为不会出现问题。无论干什么不去上锁!如果出现了问题,再次更新值测试。
悲观锁:无论干什么都会上锁,然后再去操作。
乐观锁实现方式:
配置乐观锁的实现步骤:
@Configuration //标明这是一个配置类
@ComponentScan("com.yjr.springboot005mybatis_plus.mapper") //指定扫描的包
public class MybatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
@Test
public void testOptimisticLockerInterceptor(){
//查询指定用户
User user = userMapper.selectById(2L);
user.setName("王冬");
//更新指定用户
userMapper.updateById(user);
}
当oldVersion和newVersion信息不一致就会导致更新失败
// 1. 按照id进行单个用户的查询
User user = userMapper.selectById(1L);
// 3. 多条件查询之一:使用 map 操作
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("id",1l);
hashMap.put("name","radan");
List<User> users = userMapper.selectByMap(hashMap);
// 2. 查询批量用户 前三个用户 SELECT id,name,age,email,version,create_time,update_time FROM user WHERE id IN ( ? , ? , ? )
for (User u1 : userMapper.selectBatchIds(Arrays.asList(1, 2, 3))) {
System.out.println(u1);
}
mybatis-plus中的使用分页插件的步骤:
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Test
public void pageLimit(){
//参数一(当前页) 参数二:页面大小
Page<User> objectPage = new Page<>(2,5);
userMapper.selectPage(objectPage,null);
List<User> records = objectPage.getRecords();//objectPage.getRecords()得到分页后的所有记录
for (User user : records) {
System.out.println(user);
}
System.out.println("当前的记录总数:"+objectPage.getTotal());//得到当前的记录总数
System.out.println("当前的页数:"+objectPage.getCurrent());
}
//通过id进行删除
int result = userMapper.deleteById(1691640078306185217L); //返回值为受影响的行数
//批量删除
int batchIds = userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
//多条件删除方式之一,map
HashMap<String,Object> map=new HashMap<>();
map.put("name","jom");
int i = userMapper.deleteByMap(map);
逻辑删除:从数据库中并没有移除,而是通过一个变量来让他失效!deleteState=0或1
物理删除:从数据库中直接移除
管理员可以查看到被删除的记录!防止数据的丢失,类似于回收站。
逻辑删除的使用步骤
#逻辑删除组件
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
2 .在实体类字段上加上@TableLogic注解
@TableLogic //逻辑删除注解
private Integer deleted;
常见问题:
Mybatis-Plus提供共性能分析插件,如果超这个时间就会停止运行!
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间
该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长 3.1.0 以上版本
<dependency>
<groupId>p6spygroupId>
<artifactId>p6spyartifactId>
<version>最新版本version>
dependency>
spring:
# 数据源
datasource:
username: root
password: 123456
# GMT%2B8:GMT+8 格林尼治东八时区
url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
测试结果
复杂的sql就可以利用Warpper进行实现
@Test
public void test(){
//查询name不为空的用户,并且邮箱不为空的数据,年龄大于等于12的
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name");
wrapper.isNotNull("email"); //name和email不为空
wrapper.ge("age",12); //age>=12
for (User user : userMapper.selectList(wrapper)) {
System.out.println(user);
}
}
//SELECT * FROM user WHERE deleted=0 AND (name IS NOT NULL AND email IS NOT NULL AND age >= 12)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","Tom");
userMapper.selectOne(wrapper); //查询一个数据,出现多个数据会报错的
//SELECT * FROM user WHERE deleted=0 AND (name = 'Tom')
注意:查询一个数据,查询多个数据结果使用list 或者 map
@Test
public void test12(){
//查询age在(12,20)之间的用户数
//SELECT COUNT( * ) AS total FROM user WHERE deleted=0 AND (age BETWEEN ? AND ?)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",12,20);
Long aLong = userMapper.selectCount(wrapper);//selectCount查询结果数
System.out.println(aLong);
}
public void test3(){
//模糊查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
//like==>%e%, likeLeft==>%t(末尾有t) likeRight==>t%(开头有t)
wrapper.like("name","e")
.likeRight("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
// SELECT * FROM user WHERE deleted=0 AND (name LIKE '%e%' AND email LIKE 't%')
}
public void test6(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// id在子查询中查出
wrapper.inSql("id","select id from user where id< 3");
for (User user : userMapper.selectList(wrapper)) {
System.out.println(user);
}
//SELECT * FROM user WHERE deleted=0 AND (id IN (select id from user where id< 3))
}
@Test
public void test7(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
// wrapper.orderByAsc("id");//通过id升序排序
wrapper.orderByDesc("id");//通过id降序排序
//SELECT * FROM user WHERE deleted=0 ORDER BY id DESC
for (User user : userMapper.selectList(wrapper)) {
System.out.println(user);
}
}
适用版本:mybatis-plus-generator 3.5.1 及其以上版本,对历史版本不兼容!
MyBatis-Plus 的代码生成器可以生成 Entity、Mapper、Mapper XML、Service、Controller 模块代码。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.32version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>2.3version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
server.port=8088
spring.profiles.active=dev
##数据库连接配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plue?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
package com.yjr;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author radan
* @Description
* @date 2023/8/17 17:51
*/
public class PracticeApplication {
public static void main(String[] args) {
List<String> tables = new ArrayList<>();
tables.add("user"); //可以给tables添加多个表名
FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plue","root","123456")
.globalConfig(builder -> {
builder.author("radan") //作者
.outputDir(System.getProperty("user.dir")+"\\src\\main\\java") //输出路径(写到java目录)
// .enableSwagger() //开启swagger
.commentDate("yyyy-MM-dd")
.disableOpenDir() //不打开文件管理
.fileOverride(); //开启覆盖之前生成的文件
})
.packageConfig(builder -> {
builder.parent("com.yjr")
// .moduleName("practice")
.entity("pojo")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.mapper("mapper")
.xml("mapper")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml,System.getProperty("user.dir")+"\\src\\main\\resources\\mapper"));
})
.strategyConfig(builder -> {
builder.addInclude(tables)
// .addTablePrefix("p_")//过滤表前缀
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.entityBuilder()
.enableLombok()
.logicDeleteColumnName("deleted")
.enableTableFieldAnnotation()
.controllerBuilder()
// 映射路径使用连字符格式,而不是驼峰
.enableHyphenStyle()
.formatFileName("%sController")
.enableRestStyle()
.mapperBuilder()
//生成通用的resultMap
.enableBaseResultMap()
.superClass(BaseMapper.class)
.formatMapperFileName("%sMapper")
.enableMapperAnnotation()
.formatXmlFileName("%sMapper");
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}