mybatis-plus
官网介绍
相比mybatis,里面内置了一些常用的sql方法。
还有一些mybatis_plus的插件,可以用来提示写sql。
一般单表查询用mybatis-plus,多表查询还是自己写sql。
👉官方文档
快速开始
步骤
1.环境搭建导入maven依赖
2.Druid配置 数据库保证能连接
3.创建mapper、config、controller、service、urtil、pojo目录
3.接口Mapper类继承BaseMapper类(可以继承一些plus实现的方法)
4.resources文件创建xml文件写sql。
1.环境依赖maven导入包
mybatis_plus 的 maven
<!--springboot整合mybaits-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
springmVC maven:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.2</version>
</dependency>
2.数据源Druid配置
druid是阿里巴巴开源的数据库连接池,并且加了sql日志监控。
springboot 2.0以上默认使用hikari数据源(也很快)。
阿里巴巴druid maven:
<!--druid 阿里巴巴数据源-->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
application.yml配置数据源
spring:
datasource:
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
# 使用阿里巴巴的Druid数据库连接池
type: com.alibaba.druid.pool.DruidDataSource
# 连接池的配置信息
# 初始化大小,最小,最大连接数
initial-size: 10
min-idle: 10
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是ms
timeBetweenEvictionRunsMillis: 60000
# Destory线程中如果检测到当前连接的最后活跃时间和当前时间的差值大于
# minEvictableIdleTimeMillis,则关闭当前连接。单位是ms
minEvictableIdleTimeMillis: 300000
# 用来检测连接是否有效的sql,要求是一个查询语句。
validationQuery: SELECT 1
#建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
testWhileIdle: true
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
testOnBorrow: false
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
# 配置监控统计拦截的filters,监控统计用的stat、日志用的log4j、 防御sql注入的wall
filters: stat,wall,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
useGlobaiDataSourceStat: true
maxPoolPreparedStatementPerConnectionSize: 20
#mybatis配置
mybatis-plus:
type-aliases-package: com.chuan.mybatis_plus.pojo
mapper-locations: classpath:mapper/**.xml
configuration:
#日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
DruidConfig类配置
打开 /localhost/druid 就可以访问
package com.demo.demo2.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* @Author 张川
* @博客 https://blog.csdn.net/weixin_43919632
* @Date 2021-04-07-16:15
*/
@Configuration
public class DruidConfig {
//绑定datasource数据源
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druidDataSource(){
return new DruidDataSource ();
}
//后台检控
//因为springboot 内置了servlet容器,所以没有web.xml
@Bean
public ServletRegistrationBean statViewServlet(){
//配置访问后台页面地址 /druid/*
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
HashMap<String, String> init = new HashMap<>();
//设置登陆信息
//用户名loginUsername和loginPassword是固定的key,不能修改,只能修改value
init.put("loginUsername","roots");
init.put("loginPassword","1234567");
//如果allow值为空,则所有人都可以访问
init.put("allow","");
//设置后台登陆信息,最后将集合作为参数传入
bean.setInitParameters(init);
return bean;
}
//2.配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setFilter((Filter) new WebStatFilter ());
Map<String,String> initParams = new HashMap<>();
//设置filter初始化参数、
initParams.put("exclusions","*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");//排除静态资源和请求
bean.setInitParameters(initParams);
//拦截所有请求
bean.setUrlPatterns(Arrays.asList("/*"));
//加载到容器中
return bean;
}
}
自此数据库可以连接,durid也可以用了。
配置sql日志生成
application.yml配置
mybatis-plus:
type-aliases-package: com.chuan.mybatis_plus.pojo
mapper-locations: classpath:mapper/**.xml
configuration:
#日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
主键的生成策略
1.主键自增(容易单点故障)
2.UUID生成策略(太长是缺点)
3.Twitter的snowfake算法(雪花算法)
snowfake雪花算法
snowfake是推特开源的分布式ID生成算法,结果是一个long型的ID。可以保证全球唯一!
mybatis-plus可以帮助我们自动生成全球唯一ID。
使用注解@TableId(type = IdType.INPUT)
/*对应数据库表中的id */
@TableId(type = IdType.INPUT)
private Long id;
Type源码类型解释:
一般用auto自增。
/**
* 数据库ID自增
*/
AUTO(0),
/**
* 该类型为未设置主键类型
*/
NONE(1),
/**
* 用户输入ID
* 该类型可以通过自己注册自动填充插件进行填充
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 全局唯一ID (idWorker)
*/
ID_WORKER(3),
/**
* 全局唯一ID (UUID)
*/
UUID(4),
/**
* 字符串全局唯一ID (idWorker 的字符串表示)
*/
ID_WORKER_STR(5)
更新操作
通过设置ID,使用updateById就可以实现动态SQL
@Test
public void UpdateTest() {
User user = new User ();
user.setAge (20);
//通过id实现动态sql的拼接
user.setId ((long) 1);
user.setEmail ("2018214201@qq.com");
user.setName ("zhangsan");
try {
//会根据上方setId传递id,从而i需改相应user
userMapper.updateById (user);
System.out.println ("修改成功");
} catch (Exception e) {
e.printStackTrace ();
}
}
id等于1的已经被修改。
原理
根据日志可以看到是根据id来自动实现动态sql的。
自动填充
一般是都是时间字段是填充完成的,不是自己写的,时间都应该是自动生成的。
阿里巴巴手册:所有的数据库表字段都有: gmt_creat 创建时间 gmt_modified 修改时间
方式1:数据库级别
在表着重新增字段,create_time,update_time
并设置自动更新。
不推荐使用,工作中不允许修改数据库的。
2.代码级别
使用我们mybaits-plus注解
@TableField()源码
fill属性选择 相应自动填充的策略,策略的字段是FiledFill
package com.baomidou.mybatisplus.annotation;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableField {
/**
* <p>
* 字段自动填充策略
* </p>
*/
FieldFill fill() default FieldFill.DEFAULT;
}
FiledFill字段有:
/**
* <p>
* 字段填充策略枚举类
* </p>
*
* @author hubin
* @since 2017-06-27
*/
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
2.1使用注解TableFiled(file=FIledFill)加到相应的实体类字段上
/* 插入的时候填充*/
@TableField(fill=FieldFill.INSERT)
private String create_time;
/*修改的时候自动填充*/
@TableField(fill =FieldFill.UPDATE)
当我们执行修改/插入操作的时候就会自动填充。
2.2 创建一个处理器处理上面的TableFiled注解
MyMetaObjectHandler处理器:
一定不要放到IOC容器,@Component不要省略。
package com.chuan.mybatis_plus.config;
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;
/**
* @Description 处理器
* @Author java川
* @Date 2021-04-27-15:07
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/*执行插入操作的时候的填充策略 会处理TableFiled(fill=FiledFill.INSERT)*/
@Override
public void insertFill(MetaObject metaObject) {
log.info ("start insert...");
//create_time字段自动填充LocalDateTIme
//setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
this.setFieldValByName ("create_time",new Date (), metaObject);
}
/*执行修改操作时的填充策略*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName ("update_time", new Date (),metaObject);
}
}
查询操作
查询所有selectList
@Test
public void testSelect() {
//wraper是条件构造器 可以不用
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}
基于id列表 selectBathIds的查询。
@Test
public void selectBy() {
List<User> users = userMapper.selectBatchIds (Arrays.asList (1, 2, 3));
System.out.println (users);
}
基于条件map的查询SelectByMap
/*条件查询 map查询*/
@Test
public void selectByMaps() {
HashMap<String, Object> map = new HashMap<> ();
map.put ("name", "zhangsan");
List<User> users = userMapper.selectByMap (map);
for (User user : users) {
System.out.println (user.toString ());
}
}
分页查询
1.原始的limit分页
2.myabtis-plus插件分页
MybatisplusConfig:
package com.chuan.mybatis_plus.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description
* @Author java川
* @Date 2021-04-27-16:39
*/
@Configuration
@MapperScan("com.chuan.mybatis_plus.mapper*")
public class MybatisplusConfig {
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor (DbType.H2));
return interceptor;
}
}
UserMapper接口
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
//分页查询
IPage<User> selectPageVo(Page<?> page);
}
XXXmapper.xml
UserMapper.xml 等同于编写一个普通 list 查询,mybatis-plus 自动替你分页
<select id="selectPageVo" resultType="com.baomidou.cloud.entity.UserVo">
SELECT id,name FROM user;
</select>
调用分页的方法
// 要点!! 分页返回的对象与传入的对象是同一个 Page对象
@Test
public void selectPage() {
Page<User> page = new Page<> (1,3);
userMapper.selectPageVo (page);
for (User record : page.getRecords ()) {
System.out.println (record);
}
}
原理分析
第一步先计算了查询的数量COUNT(*)
第二部通过limit得到分页的几条数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGf4z2Pg-1619691202303)(C:\Users\MI\AppData\Roaming\Typora\typora-user-images\image-20210427165002223.png)]
删除操作
根据id删除
/*根据id删除*/
@Test
public void deleteBy() {
userMapper.deleteById (1386918138546999298L);
}
根据多个id删除
@Test
public void delete() {
/*删除多个id列表*/
userMapper.selectBatchIds (Arrays.asList (1,3));
}
根据map来删除
(以下是根据id删除)
@Test
public void deleteByMap() {
/*根据map删除*/
HashMap<String, Object> map = new HashMap<> ();
map.put("id",1386918138546999303L);
try {
userMapper.deleteByMap (map);
System.out.println ("删除陈工!");
} catch (Exception e) {
e.printStackTrace ();
}
}
DELETE * FROM user WHERE id=?
逻辑删除
物理删除:直接从数据库中删除
逻辑删除:数据库中没有删除,而是用一个变量让他失效。
步骤1:配置application.yml
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;
测试
@Test
public void logicdelete() {
/*逻辑删除 通过更新字段deleted=1来使得它失效*/
userMapper.deleteById (1L);
}
原理 :
根据注解@TableLogic标注逻辑删除的字段,
mybatis-plus会根据这个字段进行更新操作。
数据库结果
再去查询的时候,就查询不了。
性能分析插件
条件查询器wrapper
十分重要:wrappper。
就是给条件的一个类。
查询一个记录
public void warpperOne() {
/*wrapper是查询条件器 查询id等于2的*/
QueryWrapper<User> wrapper = new QueryWrapper<> ();
wrapper.eq ("id", "2");
userMapper.selectOne (wrapper);
}
原理sql本质:
查询条件是是某个区间
wrapper.between
@Test
public void wrapperBetween() {
/*查询结果数量*/
QueryWrapper<User> wrapper = new QueryWrapper<> ();
wrapper.between ("age", 18, 20);
Integer integer = userMapper.selectCount (wrapper);
System.out.println (integer);
}
本质原理:
SELECT COUNT( * ) FROM user WHERE deleted=0 AND (age BETWEEN ? AND ?)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MYZPkD3N-1619691202310)(C:\Users\MI\AppData\Roaming\Typora\typora-user-images\image-20210427215706651.png)]
模糊查询
@Test
public void wrapperLike() {
/*模糊查询 wrapper.notlike.like*/
QueryWrapper<User> wrapper = new QueryWrapper<> ();
wrapper.notLike ("name", "san").likeLeft ("id", "1");
userMapper.selectMaps (wrapper);
}
sql原理:
SELECT id,name,age,email,create_time,update_time,deleted FROM user WHERE deleted=0 AND (name NOT LIKE ? AND id LIKE ?)
代码生成器
代码自动生成器
dao、pojo、service、controller都给我自己去编写完成!
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、
Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
测试:
maven
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.0.5</version>
<scope>test</scope>
</dependency>
自动生成代码:
package com.chuan.autogenerator;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
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.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.Scanner;
/**
* @Description CodeAutoGenerator
* @Author java川
* @Date 2021-04-27-22:54
*/
@SpringBootTest
public class GeneratorCode {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig ();
String projectPath = System.getProperty("user.dir");//当前的用户目录
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("java川");//作者
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆盖
gc.setServiceName("%sService"); // 去Service的I前缀
gc.setIdType(IdType.AUTO); //主键id生成策略
gc.setDateType(DateType.ONLY_DATE);//日期格式只能是日期
gc.setSwagger2(true);//设置swaagger
mpg.setGlobalConfig(gc);//全局配置生效
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/autogenerator?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");//数据库8的驱动是 com.mysql.cj.jdbc.Driver
dsc.setUsername("root"); String resourcespath = projectPath.toString ().replace ("/", ".");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner ("模块名"));//这里不要改
pc.setParent("com.chuan");//模块里面的目录
pc.setEntity("pojo");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);//包配置生效
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("blog_tags","course"); // 设置要映射数据库中的表名
strategy.setNaming(NamingStrategy.underline_to_camel);//表名下划线
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//列名下划线
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT); //创建时间 插入时自动填充
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);//修改时间 update时自动填充
ArrayList<TableFill> tableFills = new ArrayList<> ();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入"+tip+":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException ("请输入正确的" + tip + "!");
}
}
全部依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- 数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--阿里巴巴数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
<!--实体类getset省略-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mybatis-plus集成依赖包 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- mybatis-plus分页插件 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.4.2</version>
</dependency>
<!--mybatis-plus自动代码生成-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
<scope>test</scope>
</dependency>
<!-- mybatis-plus模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.4.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.20</version>
</dependency>