基础
概述
定义:
是mybatis的增强工具,只做增强不做改变,为简化开发、提高效率而生;
并提供了通用的mapper和service;
官网:https://baomidou.com/
说明文档:https://baomidou.com/introduce/
特点:
润物无声(只增强不做改变)、效率至上、丰富功能(代码生成、自动分页、逻辑删除、自动填充);
特性:
组成及实现原理
MybatisPlus组成:
启动器:mybatis-plus-boot-start
注解部分annotation、扩展部分extension、核心部分core、代码生成部分generator;
实现原理:
扫描实体 Scan Entity;
不需要书写sql命令,都是框架写好的;
访问的表由访问的实体类对象决定;
反射技术:
实现实体类中属性的抽取,分析表与实体类之间的关系,以及当前字段与属性的关系;
调用方法:
根据调用的方法,生成sql语句;
容器:
将生成的sql语句,注入到mybatis容器中,实现对应的功能;
配置文件properties yml
spring:
# 配置数据源
datasource:
# 配置数据源类型
type: com.zaxxer.hikari.HikariDataSource
# 配置连接数据库的各个信息
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库驱动信息,jdbc不同的版本需要不同的驱动类信息;jdbc5 和 jdbc8 不同
url: xxx
# 数据库url也根据mysql版本的不同而不同,mysql5.7 和 mysql8.0 不同
username: xxx
password: xxx
# 仅通过上述配置,无法在console中查看具体mybatis为我们自动生成的sql语句是什么,需要进行如下配置:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
项目中的配置文件:
mybatis-plus:
config-location: # 指定mybatis的全局配置文件的位置
# 一般为classpath:mybatis-config.xml
mapper-locations: # 指定mybatis的mapper接口的xml映射文件的位置
global-config: # 全局配置
db-config: # 数据库配置
id-type: input # 定义主键的类型,表示主键通过程序输入,插入一条新记录,需要手动指定一个主键值;
# 设置实体类所对应的数据库表的统一前缀
table_prefix: t_ # 也就是数据库表名的前缀
# xxxMapper.xml中的内容 resultType=对象类所在的包路径,同样也可以使用类别名,其中需要进一步设置如下属性,属性值为 对象所在的包路径
type-aliases-package: com.unicom.opn.api.dao.entity
Lombok介绍
用于简化实体类的开发;
通常情况下,构建与数据库表对应的实体类,是需要手动添加get、set、构造方法等内容;
但是Lombok是可以通过注解实现自动创建的;
@NoArgsConstructor 无参构造
@AllArgsConstructor 有参构造
@Getter get方法
@Setter set方法
@EqualsAndHashCode 重写equal和hashcode方法
@Data 将上述所有内容都自动写出;
Springboot+MybatisPlus使用过程
- pom依赖
<!--springboot默认依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatisPlus启动器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!-- lombok 简化实体类开发,需要在idea下载插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependncy>
整体过程:
2. 依赖包导入:
3. mybaits-config.xml文件
配置文件添加语句,了解mapper具体执行过程,在console输出
配置:
<setting name="logImpl" value="STDOUT_LOGGING" />
// 日志实现方式为输出到控制台(STDOUT_LOGGING) // stdout_logging
4. 创建实体类:
public class object{}
5. 创建xxxMapper接口
//在对应Mapper上面继承基本接口BaseMapper 该接口是由mybatis-plus提供
@Repository //代表持久层
public interface xxxMapper extends BaseMapper<XXX> {
//继承之后就是所有东西已经把连接mybatis,配置mapper.xml文件,service-controller层都搞定
}
6. 项目启动类添加扫描包
在springboot的启动类上添加注解;
@MapperScan("具体包的位置") // 用于扫描指定包下的mapper接口
// 具体包的位置 = 在mapper文件夹右键,选择copy reference 复制路径/引用
7. 创建xxxMapper.xml文件 (可有可无)
// 没有则使用baseMapper中的方法,如有则使用其中的方法;
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxx.dao.mapper.MsRiskInfoMapper">
<select id="selectBlog" resultType="Blog">
// 其中id的值与mapper接口中调用的方法名一致;
select *from Blog where id = #{id}
// 具体的sql语句
</select>
</mapper>
8. xxxDao接口及实现类创建
public interface xxxDao extends Dao<xxx>{}
// xxx表示数据表所对应的类
public class xxxDaoImpl extends BaseDao<xxxMapper,xxx> implements xxxDao{}
// Dao<xxx> 是接口 extends IService<T> ,其也是接口;
// BaseDao<xxxMapper,xxx> 是抽象类;
// public abstract class BaseDao<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements Dao<T> 泛型类,继承ServiceImpl类,实现Dao接口
// public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> 泛型类,实现IService接口
9. xxxService接口及实现类创建
public interface xxxService{ //具体抽象方法 }
public class xxxServiceImpl{
@Autowired
private xxxDao xxxdao;
// 实现抽象方法;
}
上述89是现有项目的搭建方式;
下述是视频讲解的搭建方式:
public interface xxxService extends IService<xxx>{}
public class xxxServiceImpl extends ServiceImpl<xxxMapper,xxx> implements xxxService{}
BaseMapper
int insert(T entity);
// 插入一条数据,参数=实体类对象;
int deleteById(Serializable id);
// 根据id删除一条数据,id为主键;
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据map集合进行删除;
// map中是条件,是where中的内容,key=字段,value=值
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 根据条件构造器(参数)进行删除,
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据多个id进行批量删除;采用in方式实现;
// 批量删除sql有两种形式,通过where id = 1 or id = 2 或者where id in(1,2)
int updateById(@Param(Constants.ENTITY) T entity);
// 根据对象来进行修改
// 实体类中需要设置 where查询条件id属性 以及要修改的属性
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据条件构造器进行修改
//selectxxx方法与deletexxx方法类似;
通用的Service接口
mybatis通用的接口为IService 以及 ServiceImpl实现类;
为了区别于BaseMapper的方法:BaseMapper与Service
查询:select 与 get
删除:delete 与 remove
分页:selectPage 与 page开头
public interface IService<T> {}
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {}
// M 自己所写的mapper
使用通用接口:
不建议直接实现,因为该类功能毕竟有限,通常是继承该接口;
public interface xxxService extends IService<xxx>{}
public class xxxServiceImpl extends ServiceImpl<xxxMapper,xxx> implement xxxService{}
IService:
ServiceImpl:
注解
@TableName
问题:
自定义的xxxMapper,所操作的表,由实体类xxx决定;
public interface xxxMapper extends BaseMapper<xxx>{}
当数据库表名与实体类xxx不一致时候,按照上述内容创建,程序会出现异常;
分析与解决:
1. 在xxx类上,使用@TableName('表名')
2. 全局配置方式:
mybatis-plus:
config-location:
mapper-locations:
global-config: # 全局配置
db-config: # 数据库配置
# 设置实体类所对应的数据库表的统一前缀
table_prefix: t_ # 也就是数据库表名的前缀
@Tableld
问题:
使用mybatisplus实现增删改查,会默认将id作为主键,如果某个表的主键不是id,而是uid
那么uid就不会作为主键使用;
分析:
在实体类中的uid上,添加@TableId,将属性对应的字段指定为主键;
value属性:
如果类的属性为id,数据库字段为uid,那么会报错?
可以通过@TableId(value = 'uid')实现;
private long id;
该value属性的作用,指定主键的字段(数据库的字段);
type属性:
设置主键生成的策略;
常用类型:
Idtype.ASSIGN_ID 基于雪花算法的策略生成数据Id,与数据库Id是否设置成自增无关;
Idytpe.AUTO 使用数据库的自增策略,数据库id属性必须设置自增策略;
如果使用sql中的自动递增,应该怎么操作?
数据库中设置表的id属性为自增,且在代码中的实体类的id属性上,设置@TableId(type = Idtype.AUTO)
问题2:
实体类的id属性,没有设置生成策略,默认为雪花算法;
测试方法中,已明确设置id为xxx,那么最终的操作id属性值为xxx;
问题3:
给所有实体类的主键id设置统一的主键生成策略,通过mybatis的全局配置;
mybatis-plus:
config-location:
mapper-locations:
global-config: # 全局配置
db-config: # 数据库配置
id_type: auto # 自动递增
采用上述配置,结合问题2,则新的对象id为xxx+1
@TableField
问题:
非主键属性,存在属性名与数据库字段不一致的问题;
1. 属性名-驼峰,数据库字段-含有下划线;
mybatisPlus,上述内容是有默认映射关系,不需要进行额外配置;
2. 属性名 与 字段名不一致;
通过@TableField('字段名')
private 类型 属性名;
@TableLogic
物理删除:在某个表中,通过delete从数据库中删除,之后就查询不到了;
逻辑删除:假删除,通过一个字段表示该数据是否被删除;可以实现数据的恢复;
实体类设置为:
@TableLogic
private 类型 xxx;
之后使用delete操作,从原来的删除操作,变成对该字段的修改操作,0=未删除,1=已删除
经过上述设置后,查询操作不可看到逻辑删除的数据,即展示的是xxx=0的数据行;
使用逻辑删除之后,就不会有真正的删除功能了;
雪花算法
背景:
选择合适的方式去应对数据库规模增长;
数据库扩展方式:
业务分库、主从复制、数据库分表;
单表拆分:垂直分表、水平分表;
水平分表:id分区划分、取模划分、雪花算法;
雪花算法:
不同表的主键不重复,相同表的主键的有序性,后添加的数据的键比之间添加的值大;
64位,第1是符号位,41个bit是时间戳,10个bit是机器的ID,12bit是毫秒内的流水号;
Wrapper条件构造器
基础
查询操作:
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
如果方法(参数),所需参数是Wrapper,如果写null,表示删除/查询所有;
queryWrapper中的很多方法都是AbstractWrapper中的方法;(图片不完整)
QueryWrapper
都通过wrapper条件构造器实现;
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
组装查询条件:
queryWrapper有很多方法,like、between、isNotNull等;
采用链式方式;queryWrapper.xxx().xxx(); 多个条件之间默认是AND方法;
xxxMapper.selectList(queryWrapper);
组装排序条件:
// 按照字段的升序 降序输出;
queryWrapper的方法:orderBy、orderByAsc、orderByDesc等;
组装删除条件:
queryWrapper的方法:锁定要删除的数据行;
通过xxxMapper.delete(queryWrapper);实现
组装修改功能:
xxxMapper.update(XXX xxx,Wrapper<XXX> Wrapper)
// 两种用法:
// 1. 参数1实现要修改的内容,参数2通过queryWrapper设置要修改的条件;
// 2. 参数1为null,参数2设置修改的条件,以及修改的字段;使用updateWrapper;
或使用 queryWrapper.or()方法 后面再链式书写条件;
// 用法1:
定义QueryWrapper,以及xxx对象,并给对象设置属性
xxxMapper.update(xxx,queryWrapper);
条件的优先级发生了变化:
// (条件a and 条件b)or 条件c
queryWrapper.条件a().条件b().or() .条件c()
// 条件a and (条件b or 条件c)
// lamba中的条件优先执行
queryWrapper.条件a().and(i -> i.条件b().or().条件c())
组装查询操作:
// 查询行数据中的某些字段
queryWrapper.select('字段列表');
xxxMapper.selectMaps(queryWrapper);
组装子查询:
queryWrapper.inSql(String column,String inValue):
// 参数1:子查询要判断的字段;参数2:查询的数据从一个sql语句而来,直接写sql语句
updateWrapper
修改数据的内容;
UpdateWrapper<xxx> updateWrapper = new UpdateWrapper<>();
// 两个功能;
// 1. 设置要修改条件,2. 设置要修改的内容
updateWrapper.条件a().and(i->条件b().or().条件c());
updateWrapper.set('字段名','值');
xxxMapper.update(null,updateWrapper);
校验属性信息再组合条件构造器
问题:
前端页面用户输入某些信息,根据信息,进行sql操作;
如果不进行信息判断,那么可能会存在sql语句查询无果的情况,消耗系统资源;
分析:
// 针对上述情况,需要进行信息判断;
// 方式1:
字段1=值1,字段2=值2,字段3=值3
QueryWrapper<xxx> queryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(字段1)){
queryWrapper.条件a(字段1);
}
if(字段2 != null){
queryWrapper.条件b(字段2);
}
// 方式2:
字段1=值1,字段2=值2,字段3=值3
QueryWrapper<xxx> queryWrapper = new QueryWrapper<>();
queryWrapper.like(boolean condition,String column,Object val)
queryWrapper.like(String column,Object val)
// 同一个方法会存在两个,其中一个多condition参数,该参数如果为true才会拼接条件构造器,反之不拼接
// 替换方法1功能:
queryWrapper.like(StringUtils.isNotBlank(属性1),'属性1','值1');
Lambda-Query/Update-Wrapper
问题:
使用queryWrapper和updateWrapper会涉及到字段名的书写,可能会存在书写错误的情况;
分析:
// LambdaQueryWrapper
LambdaQueryWrapper<xxx> queryWrapper = new LambdaQueryWrapper<>();
该对象的方法中,字段有发生变化:
LambdaQueryWrapper.like(SFunction<xxx,?> column,Object val)
// LambdaQueryWrapper.like(xxx::属性,字段值)
QueryWrapper.like(String column,Object val)
// LambdaUpdateWrapper
LambdaQueryWrapper<xxx> updateWrapper = new LambdaQueryWrapper<>();
updateWrapper.like(xxx::字段名,值);
updateWrapper.set(xxx:字段名,值);
分页插件
配置
// 书写一个java配置文件,配置分页插件
@Configuration
@MapperScan("mapper文件路径")
public class MyBatisPlusConfig{
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
// mybatisplus的拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 添加内部插件,插件名字为new PaginationInnerInterceptor(数据库类型)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 数据库分页的实现方式不同,要和项目数据库类型保持一致;
// 添加乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
测试:
Page<xxx> page = new Page<>(long current,int size);
// current=当前页,size=页大小
xxxMapper.selectPage(page,queryWrapper);
自定义sql实现分页
问题:
使用分页插件MybatisPlusInterceptor,使用xxxMapper自带的方法selectPage实现;
如何使用自定义的sql语句,再结合分页插件实现分页功能?
分析:
xxxMapper接口 文件中定义方法;
Page<xxx> selectPageVo(@Param("page") Page<xxx> page,@Param("参数") 类型 参数x);
// 如果方法存在两个参数,有两种访问方式:
// 1. mybatis的访问方式;
// 2. 使用@Param设置命名参数,来规定当前参数的访问规则;
// page,mybatisplus提供的分页对象,且该对象必须是第一个参数;
xxxMapper.xml文件:
select方法中的resultType的值,可以写类别名,需要在mybatis-config.xml文件中进行配置;
mybatis-plus.type-aliases-package = 类所在包的路径
具体的sql语句:
select xx1,xx2,xx3 from table where xx2 > #{参数x}
乐观锁与悲观锁
定义:
悲观锁 = 两个线程同时操作一个数据,其中一个正在操作,则另一个持续等待,直至前一个完成操作再执行;
乐观锁 = 通过版本号实现,两个线程同时操作一个数据,对数据操作的同时,也会对其中的版本号进行操作,即加操作;另一个线程更新数据前,会先比较版本号,如果和获取数据时的不一致,则会终止此次更新操作;
乐观锁实现:
在数据表中增加version字段;
首先获取数据,然后对数据进行修改;执行更新操作,将获取数据时的version作为更新数据where条件中的一个;
模拟冲突:
// 用户1获取信息
user1 = xxxMapper.selectById(1);
// 用户2获取信息
user2 = xxxMapper.selectById(1);
user1修改数据,xxxMapper.updateById(user1);
user2修改数据,xxxMapper.updateById(user2);
// 用户3获取信息
user3= xxxMapper.selectById(1);
解决冲突:
// 乐观锁方式
1. 实体类修改
@Version //添加注解
private integer version;
// 标识该属性是版本号;
2. 配置mybatisInterceptor类中配置乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 冲突不会发生了,但是user2用户对数据的修改失败了;
3. 完成功能:
判断update结果result的值,如果为0,则重试;
重试:
获取信息 user2 = xxxMapper.selectById();
修改user2对象;
执行更新操作:xxxMapper.update(user2);
通用枚举
1. 创建枚举类型:
@Getter
public enum xxxEnum{
AA(1,"xxAA");
BB(2,"xxBB");
@EnumValue // 将注解所标识的属性的值存储到数据库中
private Integer xx1;
private String xx2;
xxxEnum(Integer xx1,String xx2){
this.xx1 = xx1;
this.xx2 = xx2;
}
}
2. 实体类中枚举属性设置
private xxxEnum xxx;
3. 使用
对象.setxxx(xxxEnum.AA);
// 这种方式设置属性,会报错,是将“xxAA”放入数据库中;
4. 如何将AA的数值部分放入数据库中
在xxxEnum类中的属性上,添加@EnumValue注解;
yml文件中配置:
mybatis-plus.type-enums-package: # Enum枚举类所在的包的路径
代码生成器
概念:
mybatis中有逆向工程,通过表逆向生成实体类、mapper接口、以及映射文件;
mybatis-plus中的逆向工程,通过表逆向生成控制层、业务层、持久层、mapper接口以及映射文件;
实现:
1. pom依赖添加;
2. 功能代码编写;
- pom文件添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>最新版本</version>
</dependency>
2-1 功能实现
// builder模式实现;
FastAutoGenerator.create("url", "username", "password") // 连接数据库
.globalConfig(builder -> builder // 全局配置
.author("Baomidou") // 设置作者
.outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java") // 指定输出目录
.commentDate("yyyy-MM-dd") //生成代码的注解中日期的格式
)
.packageConfig(builder -> builder // 包配置
.parent("com.baomidou.mybatisplus") // 父包名
.entity("entity") // 设置entity包名
.mapper("mapper") // mapper包名
.service("service") // service包名
.serviceImpl("service.impl") // serviceImpl包名
.xml("mapper.xml") //映射文件包名
)
.strategyConfig(builder -> builder // 策略配置
.entityBuilder() // 设置entity类的生成策略
.enableLombok() // 启动lombok插件
)
.templateEngine(new FreemarkerTemplateEngine()) // 设置模板引擎为Freemarker
.execute(); // 执行上述配置文件
2-2 功能实现
public static void creatTable(String tableName) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");//获取当前项目的根目录路径 等号右侧是固定的,包括参数;
gc.setOutputDir(projectPath + "/src/main/java");//设置生成代码的输出路径为根目录下的"/src/main/java"路径
gc.setAuthor("xxx");//设置作者
gc.setOpen(false);//生成代码后是否打开包含生成代码的目录
gc.setServiceName("%sDao");//设置service接口的命名规范
gc.setServiceImplName("%sDaoImpl");//设置serviceImpl类的命名规范
mpg.setGlobalConfig(gc);//配置全局配置到代码生成器上
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://ip:3306/database?rewriteBatchedStatements=true&serverTimezone=GMT%2B8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(null);
pc.setParent("com.unicom.opn.api");
pc.setEntity("dao.domain");
pc.setMapper("dao.mapper");
pc.setService("dao");
pc.setServiceImpl("dao.impl");
pc.setXml(projectPath + "/src/main/resources/newMappers/");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
List<FileOutConfig> focList = new ArrayList<>();
focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
// String TEMPLATE_SERVICE = "/templates/service.java";
// String TEMPLATE_SERVICE_IMPL = "/templates/serviceImpl.java";
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输入文件名称
return projectPath + "/src/main/resources/newMappers/" + 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(tableName);
//strategy.setSuperEntityColumns("id");
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
strategy.setEntityTableFieldAnnotationEnable(true);
strategy.setSuperServiceClass("com.unicom.qh.common.mybatis.dao.Dao");
strategy.setSuperServiceImplClass("com.unicom.qh.common.mybatis.dao.impl.BaseDao");
mpg.setStrategy(strategy);
// 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
多数据源
场景:
多表放在多个数据库中、读写分离、一主多从、混合模式等;
使用:
1. pom引入依赖;
2. yml配置文件;
3. 指定数据源,@DS注解,在xxxService类上;
@DS可以在方法或类上,读写分离的时候,可以将该注解加到不同的方法上;
- pom依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.1</version>
</dependency>
- yml配置文件:
spring:
datasource:
dynamic:
primary: master # 默认数据源
strict: false # 严格匹配数据源,默认为false,为true 未匹配到数据源会抛出异常,所以一般采用默认方式;
datasource:
master: # 数据源的名字
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_1: # 数据源的名字
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_2: # 数据源的名字
url: ENC(xxxxx)
username: ENC(xxxxx)
password: ENC(xxxxx)
driver-class-name: com.mysql.jdbc.Driver
MyBatisX插件
概念:
实现复杂sql、多表联查等功能;基于IDEA的插件;
安装:
setting-插件/plug
作用:
1. 可以快速找到mapper接口对应的mapper.xml文件;通过代码左侧的小鸟可以实现接口到xml以及xml到接口的跳转;
2. 代码生成器功能;idea需要配置database数据源
可以生成xxxService接口、ServiceImpl实现类、xxxMapper接口、xxxMapper.xml等内容生成;
在xxxMapper接口自定义功能方法;书写方法名,按照代码提示选择书写,alt+enter,选择第二个,这样会直接生成,在xxxMapper.xml中也会生成。
- 跳转:
- 自动生成代码
实战
插入操作默认id?
如果采用Mybatisplus实现数据插入,对应自增长id而言,会默认采用雪花算法生成,它的长度较长,所以id字段的类型一般采用bigint(20)实现。
直接创建xxxMapper对象爆红?
描述:
直接在测试类或者服务中编写
@Autowired
private xxxMapper xxxmapper;
xxxmapper会报红;
分析:
通过@MapperScan扫描所有mapper文件,不是将所有的接口交由ioc管理,(ioc中只能存在类所对应的bean,而不能存在接口对应的bean)而是将mapper动态生成的代理类交由ioc管理,那么在idea编译的时候会认为xxxmapper是无法进行自动装配的;但在运行阶段是没有问题的。
处理:
想将爆红去掉,需要在xxxMapper接口的定义前加注解@Repository
BaseMapper中没有exists方法?
描述:
本地mybatis-plus版本为3.3.0,其中方法如下图,缺少很多方法,包括exists方法;
分析:
是不是由于教程与本地版本不一致导致;教程中的版本为:3.0.5 版本更新了 所以少了方法?
批量insert操作?
描述:
BaseMapper中的插入方法只有insert,且只能添加一个对象;
分析:
通过IService接口中的saveBatch()实现;
具体sql执行,时通过单个insert添加操作,循环多次实现的,而不是sql语句中的批量添加操作;
insert into table (字段1,字段2,字段3) values (),()