MyBatisPlus
1.简介
官网:MyBatis-Plus (baomidou.com)
使用第三方组件:
1.导入对应的依赖
2.研究依赖如何配置
3.代码如何编写
4.提高扩展技术能力
步骤:
1.创建数据库mybatis_plus
2.创建user表
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)
);
3.插入数据
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');
4.编写项目,初始化项目,使用springboot初始化!
5.导入依赖
不用同时导入mybatis和mybatis-plus!
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
6.连接数据库
# mysql 5 驱动不同 com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456789
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# mysql 8 需要时区的配置 serverTimezone=GMT%2B8 驱动不同 com.mysql.cj.jdbc.Driver
7.传统:pojo-dao-service-controller
使用mybatis-plus后:
- pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}
- mapper接口
//在对应的mapper上面实现基本的接口
@Repository //持久层
public interface UserMapper extends BaseMapper<User> {
//所有的crud操作都自动编写了
}
- 使用
@SpringBootTest
class MybatisPlusApplicationTests {
//继承了basemapper,所有方法都来自父类
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//查询全部用户,参数是一个wrapper,条件构造器(无条件就为null)
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
- 注意点,需要在主启动类上扫描所有的mapper类
@SpringBootApplication
@MapperScan("com.liu.mapper") //扫描mapper文件夹
2.配置日志
现在的sql是不可见的,需要通过日志来查看sql语句!
配置:
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.CRUD扩展
插入操作
//测试插入
@Test
public void testInsert(){
User user = new User();
user.setName("llx");
user.setAge(20);
user.setEmail("97122@qq.com");
int insert = userMapper.insert(user);
System.out.println(insert);
System.out.println(user); //自动生成了id
}
数据库插入的id默认值为:全局的唯一id
主键生成策略
默认方案:全局唯一id
@TableId(type = IdType.ID_WORKER)
分布式系统唯一id生成
雪花算法:
snowflake是twitter开源的分布式id生成算法,结果是一个long型得到ID。
核心思想是:使用41bit作为毫秒数,10bit作为机器ID,12bit作为毫秒内的流水号(每个节点在每毫秒开源产生4096个id),最后有一个符号位,永远是0。
主键自增
需要配置主键自增:
1.实体类字段上@TableId(type = IdType.AUTO)
2.数据库字段一定要是自增的!
其余主键
public enum IdType {
AUTO(0), //id自增
NONE(1), //未设置主键
INPUT(2),//手动输入
ID_WORKER(3),//默认的全局id
UUID(4),//全局唯一id
ID_WORKER_STR(5);//idworker 字符串表示法
更新操作
//测试更新
@Test
public void testUpdate(){
User user = new User();
user.setId(4L);
user.setName("棒!");
//自动拼接sql
user.setAge(15);
//updateById 但是参数是一个对象
int update = userMapper.updateById(user);
System.out.println(update);
}
自动填充
创建时间,修改时间,这些操作都是自动化完成的,不需要手动更新
所有数据库表:gmt_create、gmt_modified几乎所有的表都要配置上,需要自动化!
方式一:数据库级别
- 在表中新增字段 create_time,update_time
2.再次测试插入方法,需要先把实体类同步!
方式二:代码级别
1.删除数据库的默认值,更新操作!
2.实体类字段属性上添加注解!
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
3.编写处理器处理注解即可!
package com.liu.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@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 insert fill....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4.乐观锁讲解
乐观锁:无论干什么都不上锁,如果出了问题,再次更新测试值(version)
悲观锁:无论干什么都上锁,再去操作!
实现方式:
-
取出记录时,获取当前version
-
更新时,带上version
-
执行更新时,set version = new version where version = old version
-
如果version不对,就更新失败
测试
1.数据库增加字段
2.实体类加字段
@Version //version 注解
private Integer version;
3.组件配置
@MapperScan("com.liu.mapper") //扫描mapper文件夹
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4.测试
//测试乐观锁
@Test
public void testOptimisticLocker(){
//1.查询用户信息
User user = userMapper.selectById(1L);
//2.修改用户信息
user.setName("liuxiang");
user.setEmail("91@qq.com");
//3.执行更新
userMapper.updateById(user); //会带上乐观锁
}
查询
//测试批量查询
@Test
public void testSelectById(){
List<User> user = userMapper.selectBatchIds(Arrays.asList(1,2,3));
user.forEach(System.out::println);
}
//条件查询 map
@Test
public void testSelectByBatchIds(){
HashMap<String, Object> hashMap = new HashMap<>();
// hashMap.put("name","liuxiang");
hashMap.put("age",24);
List<User> userList = userMapper.selectByMap(hashMap);
userList.forEach(System.out::println);
}
分页查询
1.组件配置
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
2.直接使用Page对象即可!
//分页查询
@Test
public void testPage(){
//当前页 页面大小
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
删除
//测试删除
@Test
public void testDelete(){
userMapper.deleteById(1L);
}
//通过id批量删除
@Test
public void testDeleteBatchById(){
userMapper.deleteBatchIds(Arrays.asList(1568154279481020417L,1568158270856126466L));
}
//通过map删除
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","llx");
userMapper.deleteByMap(map);
}
逻辑删除:在数据库中没有被移除,而是通过一个变量让他失效 deleted = 0 => deleted = 1
测试:
1.在数据库中增加一个字段
2.pojo实体类增加属性
@TableLogic //逻辑删除
private Integer deleted;
3.配置
//逻辑删除
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
#配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4.测试(用户还在数据库,但是delete字段值变化了)
再次执行查询操作的时候,会自动拼接deleted字段,查询不到2号用户!
5.性能分析插件
1.dev测试环境
spring.profiles.active=dev
2.配置插件
//sql执行效率插件
@Bean
@Profile({"dev","test"}) //测试环境下开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100);//最大sql运行时间ms
performanceInterceptor.setFormat(true); //是否格式化
return performanceInterceptor;
}
6.条件构造器
@Test
void contextLoads(){
//查询name不为空 的用户,并且邮箱不为空的用户,年龄大于25
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age",20);
userMapper.selectList(wrapper).forEach(System.out::println)
}
eq : 等于
gt : 大于
ge : 大于等于
ne : 不等于
lt : 小于
le : 小于等于
between:在..之间
isNull:非空
like:'%值%'
in:
having:接sql语句
@Test
void test2(){
//查询name不为空 的用户,并且邮箱不为空的用户,年龄大于25
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",20,27);
Integer c = userMapper.selectCount(wrapper);
System.out.println(c);
}
//模糊查询
@Test
void test3(){
//查询name不为空 的用户,并且邮箱不为空的用户,年龄大于25
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.like("name","o")
.likeLeft("email","t");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
void test4(){
//查询name不为空 的用户,并且邮箱不为空的用户,年龄大于25
QueryWrapper<User> wrapper = new QueryWrapper<>();
//在子查询中查
wrapper.inSql("id","select id from user where id<3");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
void test5(){
//降序排序
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("id");
List<User> userList = userMapper.selectList(wrapper);
userList.forEach(System.out::println);
}
7.代码生成器
旧:
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("llx");
gc.setOpen(false);
gc.setFileOverride(false);
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("密码");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.liu");
pc.setEntity("pojo");
pc.setMapper("mapper");
pc.setService("service");
mpg.setPackageInfo(pc);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setInclude("user"); //设置要映射的表名,可以多个参数
strategy.setEntityLombokModel(true);
//驼峰命名风格
strategy.setRestControllerStyle(true);
strategy.setLogicDeleteFieldName("deleted");
//自动填充配置
TableFill gmtCreate = new TableFill("gmt_create",FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified",FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
//乐观锁
strategy.setVersionFieldName("version");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
};
trategy.setRestControllerStyle(true);
strategy.setLogicDeleteFieldName(“deleted”);
//自动填充配置
TableFill gmtCreate = new TableFill(“gmt_create”,FieldFill.INSERT);
TableFill gmtModified = new TableFill(“gmt_modified”,FieldFill.INSERT_UPDATE);
ArrayList tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
//乐观锁
strategy.setVersionFieldName(“version”);
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
};