# 功能说明

  • 代码生成、自动实现基础CRUD操作方法
  • 基于配置文件多数据源支持(一主多从)
  • 读写分离,强制读主库策略
  • 多租户模式
  • 自动缓存管理:所有查询方法结果自动缓存、自动更新,事务回滚缓存同步回滚机制
  • 数据权限:改写SQL方式自动实现数据权限
  • 数据变更日志记录:通过执行SQL前后数据对比生成数据变更记录
  • 分页组件
  • 敏感操作保护:无查询条件删除等敏感操作保护

# 使用说明

# 添加依赖

<dependency>
    <groupId>com.jeesuite</groupId>
    <artifactId>jeesuite-mybatis</artifactId>
    <version>[最新版本]</version>
</dependency>

# 初始化

# 数据源配置

以下是配置的一主二从的数据源配置,如未开启读写分离则无需配置从库配置

master.db.url=jdbc:mysql://localhost:3306/demo_db?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT&allowPublicKeyRetrieval=true
master.db.username=root
master.db.password=123456
master.db.initialSize=2
master.db.minIdle=2
master.db.maxActive=20

#slave ....
slave1.db.url=jdbc:mysql://127.0.0.1:3306/demo_db_bak1?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT&allowPublicKeyRetrieval=true
slave1.db.username=root
slave1.db.password=123456
#
slave2.db.url=jdbc:mysql://localhost:3306/demo_db_bak2?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT&allowPublicKeyRetrieval=true
slave2.db.username=root
slave2.db.password=123456

# spring XML方式

只需要修改以下两处的配置内容 ,其他保持不变。

<!--数据源-->
<bean id="myDataSource" class="com.jeesuite.mybatis.datasource.MultiRouteDataSource" />

<!--mybatis SqlSessionFactory-->
<bean id="mySqlSessionFactory" class="com.jeesuite.mybatis.spring.SqlSessionFactoryBean">
	<property name="configLocation" value="classpath:mybatis-configuration.xml" />
	<property name="mapperLocations" value="classpath:mapper/*Mapper.xml" />
	<property name="typeAliasesPackage" value="com.jeesuite.mybatis.test.entity" />
	<property name="dataSource" ref="myDataSource" />
</bean>

# springboot方式

# 添加依赖

<dependency>
    <groupId>com.jeesuite</groupId>
    <artifactId>jeesuite-springboot-starter</artifactId>
    <version>[最新版本]</version>
</dependency>

# 启动注解

@EnableJeesuiteMybatis

# 分页插件

# 添加配置

jeesuite.mybatis.paginationEnabled=true
//分页最大pageSize
jeesuite.mybatis.pagination.maxLimit=1000

# 用法

以员工StaffEntity为例,定义Mapper接口如下:

public interface StaffEntityMapper extends BaseMapper<StaffEntity,Integer> {
	List<StaffEntity> findListByParam(StaffQueryParam param);
}

以上接口除了可以按正常方式调用,还可以通过以下方式分页方式查询

//不封装DTO
Page<StaffEntity> pageInfo = PageExecutor.pagination(new PageParams(1,10), new PageDataLoader<UserEntity>() {
    @Override
    public List<UserEntity> load() {
       return staffEntityMapper.findListByParam(param);
    }
});

//查询并转换成dto的方式
Page<Staff> page = PageExecutor.pagination(pageParams, new ConvertPageDataLoader<StaffEntity,Staff>() {
	@Override
	public List<StaffEntity> load() {
		return staffMapper.selectAll();
	}

	@Override
	public Staff convert(StaffEntity e) {
		return entityConvertDTO(e);
	}
});

# 读写分离

读写分离除了要配置从库数据源外,还需要添加以下配置

jeesuite.mybatis.rwRouteEnabled=true

考虑到主从同步延迟问题,一些查询方法希望也通过主库查询,默认启用事务注解@Transactional的方法都强制通过主库查询,另外你也通过注解@UseMaster强制使用主库。

# 自动缓存

# 添加配置

jeesuite.mybatis.cacheEnabled=true
//空值是否缓存(防止缓存穿透)
jeesuite.mybatis.nullValueCache=true
//默认缓存失效时间,不配置或者配置为0,默认就是当天零点失效
jeesuite.mybatis.cacheExpireSeconds=3600
//是否开启动态缓存失效时间,设置默认缓存失效时间才生效
jeesuite.mybatis.dynamicExpire=false

# 注解说明

所有缓存配置只需要一个注解@Cache搞定,以下是注解选项说明

选项 必填 说明
expire 过期时间(秒),不指定则按默认过期规则
uniqueIndex 是否业务上唯一索引,如果为true则仅缓存引用关系
concurrency 是否允许并发查询,默认为:true。为false则在缓存未命中启动分布式锁确保只有一个请求去查询数据库
userScope 当前登录用户范围
evictOnMethods 默认同一Mapper下的CUD方法都会自动刷新同一实体关联的缓存,如果是关联查询可以配置evictOnMethods跨Mapper刷新缓存。
refKey 缓存引用,引用已存在的缓存

# 使用举例

public interface AccountEntityMapper extends BaseMapper<AccountEntity, Integer> {
    
    @Cache(uniqueIndex = true,expire = 7200)
    @Select("SELECT * FROM omp_account WHERE mobile=#{mobile} AND deleted=0 LIMIT 1")
    @ResultMap("BaseResultMap")
    AccountEntity findByMobile(String mobile);

    @Cache(evictOnMethods = {"SnsAccounyBindingEntityMapper.*"})
    @Select("SELECT a.*,b.union_id FROM omp_account a LEFT JOIN omp_account_weixin_binding b ON a.id = b.account_id WHERE a.enabled = 1 and b.open_id = #{openId} LIMIT 1 ")
    @ResultMap("BaseResultMap")
    AccountEntity findByWeixinOpenId(@Param("openId") String openId);
}

# CacheIgnore

如果开启缓存功能默认所有按主键查询都会自动缓存,如果希望某个实体不自动缓存,只需要在对应的mapper接口类加上注解@CacheIgnore即可

# 数据权限

# 添加配置

jeesuite.mybatis.dataProfileEnabled=true
//以下是数据权限的规则(以表为维度)
jeesuite.mybatis.dataProfile.mappings[t_users]=cityId:city_id,areaId:area_id

# 查询上下文(在拦截器根据当前登录用户数据权限信息设置)

List<KeyValues> profiles = LoginContext.getDataProfiles();//这是假设的一个方法
if(profiles != null) {
	for (KeyValues keyValues : profiles) {
		MybatisRuntimeContext.addDataProfileMappings(keyValues.getKey(), keyValues.getValues().toArray(new String[0]));
	}
}

# 查询示例

假如当前用户的数据权限为:cityId("440"),areaId("440105","440106")

@Before
public void init(){
	MybatisRuntimeContext.addDataProfileMappings("cityId", "440");
	MybatisRuntimeContext.addDataProfileMappings("areaId", "440105","440106");
}

@Test
public void testQuery(){
   //
   userMapper.findByType(1);
   //
   userDetailMapper.findList();
}

不启用数据权限的情况以上测试的执行SQL如下:

SELECT * FROM t_users where type = 1 AND deleted = 0

SELECT d.* FROM t_user_details d JOIN t_users u ON u.id = d.user_id where u.deleted = 0

启用数据权限后执行SQL如下:

SELECT * FROM t_users where type = 1 AND deleted = 0 AND city_id = '440' AND area_id IN ("440105","440106")

SELECT d.* FROM t_user_details d JOIN t_users u ON u.id = d.user_id where u.deleted = 0 AND u.city_id = '440' AND u.area_id IN ("440105","440106")

# 跳过数据权限的方式

  • 开始事务的方法内部查询默认不启用数据权限
  • 添加注解@DataProfileIgnore的方法的查询方法不启用数据权限
  • 配置项jeesuite.mybatis.dataProfile.excludeMapperIds配置的Mapper接口

# 多租户模式

开启租户模式很简单,只需要打开租户模式开关并在数据源配置加上前缀 tenant[租户key]即可

jeesuite.mybatis.tenantModeEnabled=true
//
tenant[tenant1].master.db.url=jdbc:mysql://localhost:3306/tenant1?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT&allowPublicKeyRetrieval=true
tenant[tenant1].master.db.username=root
tenant[tenant1].master.db.password=123456

tenant[tenant2].master.db.url=jdbc:mysql://localhost:3306/tenant2?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT&allowPublicKeyRetrieval=true
tenant[tenant2].master.db.username=root
tenant[tenant2].master.db.password=123456

# 多数据源支持

Last Updated: 5/16/2021, 4:38:49 PM