项目应用实践:基于grpc从零开始搭建一个准生产分布式应用(0) - quickStart
也是属于闲来无事吧,这个插件的出镜率还是很高的,所以挑重点记录一下。供日后开发参考,笔者是采用的springboot-starter的方式进行的集成。
一、基础例子
Maven引入
--因为这是非官方的插件,所以需要在maven的setting文件中配置如下仓库。
<repository>
<id>snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
项目的pom.xml文件引入如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/>
</parent>
<!--spring-boot安装和配置-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies>
spring-boot配置yml文件
<!--application.yml-->
# DataSource Config
spring:
datasource:
driver-class-name: org.h2.Driver
schema: classpath:db/schema-h2.sql
data: classpath:db/data-h2.sql
url: jdbc:h2:mem:test
username: root
password: test
插件全局配置类
public GlobalConfig globalConfig() {
GlobalConfig conf = new GlobalConfig();
conf.setDbConfig(new GlobalConfig.DbConfig().setColumnFormat("`%s`"));
DefaultSqlInjector logicSqlInjector = new DefaultSqlInjector() {
/**
* 注入自定义全局方法
*/
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
// 不要逻辑删除字段, 不要乐观锁字段, 不要填充策略是 UPDATE 的字段
methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete() && !t.isVersion() && t.getFieldFill() != FieldFill.UPDATE));
// 不要填充策略是 INSERT 的字段, 不要字段名是 column4 的字段
methodList.add(new AlwaysUpdateSomeColumnById(t -> t.getFieldFill() != FieldFill.INSERT && !t.getProperty().equals("column4")));
return methodList;
}
};
conf.setSqlInjector(logicSqlInjector);
return conf;
}
简单实现
实体类
(callSuper = true)
(chain = true)
("t_case")
public class UserEntity {
private Long id;
private String name;
private Integer age;
private String email;
}
public interface UserMapper extends BaseMapper<UserEntity> {
}
dao实现
public interface IUserDao extends IService<UserEntity>
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
public class UserDaoImpl extends ServiceImpl<UserMapper, UserEntity> implements IUserDao
spring启动类
("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
二、安装maven-test-plug
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter-test</artifactId>
<version>3.5.1</version>
</dependency>
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.assertj.core.api.Assertions.assertThat;
class MybatisPlusSampleTest {
private SampleMapper sampleMapper;
void testInsert() {
Sample sample = new Sample();
sampleMapper.insert(sample);
assertThat(sample.getId()).isNotNull();
}
}
三、注解
@TableName
描述:表名注解,标识实体类对应的表,使用位置:实体类
"sys_user")(
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
@TableId
描述:主键注解,使用位置:实体类主键字段
"sys_user")(
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
value==主键字段名;type==指定主键类型(默认值IdType.NONE),IdType的可选值
- -->AUTO:数据库 ID 自增
- -->NONE:insert 前自行 set 主键值
- -->INPUT:insert 前自行 set 主键值
- -->ASSIGN_ID:分配 ID(主键类型为 Number(Long 和 Integer)或 String),使用接口IdentifierGenerator的方法nextId(默认实现类DefaultIdentifierGenerator雪花算法)
- -->ASSIGN_UUID:分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
@TableField
字段注解(非主键)
"sys_user")(
public class User {
private Long id;
("nickname")
private String name;
private Integer age;
private String email;
}
- value:默认为“”, 数据库字段名
- exist:默认为true,是否为数据库表字段
- condition:默认为“”,字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}
- update:默认为“”,字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
- insertStrategy:默认值FieldStrategy.DEFAULT,当值为NOT_NULL时,则生成的语句如下:insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
- updateStrategy:FieldStrategy.DEFAULT,举例:当值为IGNORED时,则生成的语句为update table_a set column=#{columnProperty}
- whereStrategy:默认值FieldStrategy.DEFAULT,当NOT_EMPTY时,生成语句为where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
- IGNORED:忽略判断
- NOT_NULL:非 NULL 判断
- NOT_EMPTY:非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)
- DEFAULT:追随全局配置
- fill:默认值为FieldFill.DEFAULT,字段自动填充策略
- DEFAULT:默认不处理
- INSERT:插入时填充字段
- UPDATE:更新时填充字段
- INSERT_UPDATE:插入和更新时填充字段
- select:是否进行 select 查询,默认为ture
- keepGlobalFormat:是否保持使用全局的 format 进行处理,默认为false
- typeHandler:Class<? extends TypeHandler>,默认值为UnknownTypeHandler.class, 类型处理器 (该默认值不代表会按照该值生效)
@Version
描述:乐观锁注解、标记 @Verison 在字段上
@EnumValue
描述:普通枚举类注解(注解在枚举字段上)
@TableLogic
描述:表字段逻辑处理注解(逻辑删除)
属性 |
类型 |
必须指定 |
默认值 |
描述 |
value |
String |
否 |
"" |
逻辑未删除值 |
delval |
String |
否 |
"" |
逻辑删除值 |
@OrderBy
描述:内置 SQL 默认指定排序,优先级低于 wrapper 条件查询
属性 |
类型 |
必须指定 |
默认值 |
描述 |
isDesc |
boolean |
否 |
true |
是否倒序查询 |
sort |
short |
否 |
Short.MAX_VALUE |
数字越小越靠前 |
四、mybatis缓存
一般在开发时不太需要关注的,这里只是简单描述下其原理。Mybatis 中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且不能关闭。一级缓存是指 SqlSession 级别的缓存,当在同一个 SqlSession 中进行相同的 SQL 语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存 1024 条 SQL。二级缓存是指可以跨 SqlSession 的缓存。是 mapper 级别的缓存,对于 mapper 级别的缓存不同的 sqlsession 是可以共享的。整体结构如下图所示:
一级缓存-sqlsession
第一次发出一个查询 sql,sql 查询结果写入 sqlsession 的一级缓存中,缓存使用的数据结构是一个 map,格式为:
{key:MapperID+offset+limit+Sql+所有的入参;value:结果数据}
同一个 sqlsession 再次发出相同的 sql,就从缓存中取出数据。如果两次中间出现 commit 操作 (修改、添加、删除),本 sqlsession 中的一级缓存区域全部清空,下次再去查询先从数据库查询,从数据库查询到再写入缓存。
二级缓存-mapper
二级缓存的范围是 mapper 级别(mapper 同一个命名空间),mapper 以命名空间为单位创建缓存数据结构,结构是 map。mybatis 的二级缓存是通过 CacheExecutor 实现的。CacheExecutor其实是 Executor 的代理对象。所有的查询操作,在 CacheExecutor 中都会先匹配缓存中是否存在,不存在则查询数据库,格式为{key:MapperID+offset+limit+Sql+所有的入参},具体使用需要配置:
- Mybatis 全局配置中启用二级缓存配置;
- 在对应的 Mapper.xml 中配置 cache 节点;
- 在对应的 select 查询节点中添加 useCache=true