Java持久层框架-MybatisPlus

基础

概述

定义:
	是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使用过程

  1. 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的方法:BaseMapperService
	查询: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是机器的ID12bit是毫秒内的流水号;

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. 功能代码编写;
  1. 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可以在方法或类上,读写分离的时候,可以将该注解加到不同的方法上;
  1. pom依赖:
<dependency>
      <groupId>com.baomidou</groupId>
       <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
       <version>3.2.1</version>
</dependency>
  1. 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中也会生成。

  1. 跳转:
    在这里插入图片描述
  2. 自动生成代码
    在这里插入图片描述

实战

插入操作默认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 (),()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值