mybatis 自动填充无效_开发小知识-mybatis-plus自动填充与读写分离

mybatis-plus 自动填充

说明

我们在设计表结构的时候,往往会额外添多如下几个字段

create_time【表字段】-- createTime【实体字段】 : 创建时间

update_time【表字段】-- updateTime【实体字段】:更新时间

create_by【表字段】-- createBy 【实体字段】: 创建人

update_by【表字段】--updateBy 【实体字段】:更新人

del_flag【表字段】-- delFlag【实体字段】 : 逻辑删除标识【0:未删除、1:已删除】

在编写实体类【与数据映射】的时候,不能总在每个类上都编写上述几个属性,显得有些冗余,于是我们将这几个属性提取出来

并在对应的属性上标注mybatis-plus的填充注解,那么所有继承BaseEntity的类将会拥有createTime,updateTime属性,继承DefaultEntity的类将会拥有createTime、updateTime、createBy、updateBy、delFlag属性。

至于为什么会设计两个类,是因为有些中间表可能不需要用到createBy、updateBy、delFlag属性,只需要createTime,updateTime属性。

依赖引入

com.baomidou

mybatis-plus-boot-starter

3.3.2

org.projectlombok

lombok

1.18.12

公用实体类定义

package com.cloud.pango.common.core.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;

import com.baomidou.mybatisplus.annotation.TableField;

import lombok.Data;

import lombok.EqualsAndHashCode;

import lombok.ToString;

import java.util.Date;

@Data

@ToString

@EqualsAndHashCode

public class BaseEntity{

@TableField(fill = FieldFill.INSERT)//插入时填充

private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)//插入货更新时填充

private Date updateTime;

}

package com.cloud.pango.common.core.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;

import com.baomidou.mybatisplus.annotation.TableField;

import com.baomidou.mybatisplus.annotation.TableLogic;

import lombok.Data;

import lombok.EqualsAndHashCode;

import lombok.ToString;

@Data

@ToString

@EqualsAndHashCode

public class DefaultEntity extends BaseEntity{

@TableField(fill = FieldFill.INSERT) //插入时填充

private String createBy;

@TableField(fill = FieldFill.INSERT_UPDATE)//插入或更新时填充

private String updateBy;

@TableField(fill = FieldFill.INSERT) //插入时填充

@TableLogic//逻辑删除

private Integer delFlag;

}

自动填充处理

package com.cloud.pango.common.mybatis;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;

import lombok.extern.slf4j.Slf4j;

import org.apache.ibatis.reflection.MetaObject;

import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

@Slf4j

public class EntityMetaObjectHanlder implements MetaObjectHandler {

private final static String CREATE_TIME = "createTime";

private final static String UPDATE_TIME = "updateTime";

private final static String CREATE_BY = "createBy";

private final static String UPDATE_BY = "updateBy";

private final static String DEL_FLAG = "delFlag";

@Autowired

private MetaObjectOperator metaObjectOperator;

private void setMeta(MetaObject metaObject,String field,Object defaultValue){

if(metaObject.hasGetter(field)){

Object value = metaObject.getValue(field);

if(null != value){

this.setFieldValByName(field,value,metaObject);

}else {

this.setFieldValByName(field,defaultValue,metaObject);

}

}

}

private void setCreateTime(MetaObject metaObject){

setMeta(metaObject,CREATE_TIME,new Date());

}

private void setUpdateTime(MetaObject metaObject){

setMeta(metaObject,UPDATE_TIME,new Date());

}

private void setCreateBy(MetaObject metaObject){

Object createBy = metaObjectOperator.getCreateBy();

if(null == createBy){

return ;

}

setMeta(metaObject,CREATE_BY,createBy);

}

private void setUpdateBy(MetaObject metaObject){

Object updateBy = metaObjectOperator.getUpdateBy();

if(null == updateBy){

return ;

}

setMeta(metaObject,UPDATE_BY,updateBy);

}

private void setDelFlag(MetaObject metaObject){

setMeta(metaObject,DEL_FLAG,0);

}

@Override

public void insertFill(MetaObject metaObject) {

String name = metaObject.getOriginalObject().getClass().getName();

if(log.isDebugEnabled()){

log.debug("{} 自动装配 createTime、updateTime、createBy、updateBy、delFlag",name);

}

setCreateTime(metaObject);

setUpdateTime(metaObject);

setCreateBy(metaObject);

setUpdateBy(metaObject);

setDelFlag(metaObject);

}

@Override

public void updateFill(MetaObject metaObject) {

String name = metaObject.getOriginalObject().getClass().getName();

if(log.isDebugEnabled()){

log.debug("{} 自动装配 updateTime、updateBy",name);

}

setUpdateTime(metaObject);

setUpdateBy(metaObject);

}

}

数据库读写分离

在分布式纵横的年代,人们想方设法提高应用程序的性能,将数据库拆分为读写分离模式【主从复制】是一项提供性能的一种方案。

当然这种方案只针对对数据一致性没那么高要求的程序【弱一致性】。因为在主数据库同步给从数据库时候有可能会出现一些额外情况,如网络原因等,导致主从数据库数据不一致。

本案例采用动态数据源及mybatis-plus来实现读写分离

引入依赖

com.baomidou

mybatis-plus-boot-starter

3.3.2

org.projectlombok

lombok

1.18.12

com.baomidou

dynamic-datasource-spring-boot-starter

3.1.1

配置application.yml文件

配置名为master的主数据库【用于写操作】及名为slave的从数据库【读操作】

spring:

datasource:

dynamic:

druid: # 全局druid参数,绝大部分值和默认保持一致。(现已支持的参数如下,不清楚含义不要乱设置)

# 连接池的配置信息

# 初始化大小,最小,最大

initial-size: 5

min-idle: 5

maxActive: 20

# 配置获取连接等待超时的时间

maxWait: 60000

# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒

timeBetweenEvictionRunsMillis: 60000

# 配置一个连接在池中最小生存的时间,单位是毫秒

minEvictableIdleTimeMillis: 300000

validationQuery: SELECT 1 FROM DUAL

testWhileIdle: true

testOnBorrow: false

testOnReturn: false

# 打开PSCache,并且指定每个连接上PSCache的大小

poolPreparedStatements: true

maxPoolPreparedStatementPerConnectionSize: 20

# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙

filters: stat,wall,slf4j

# 通过connectProperties属性来打开mergeSql功能;慢SQL记录

connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000

datasource:

master:

url: ${MYSQL_URL:jdbc:mysql://localhost:3306/master?characterEncoding=UTF-8&useUnicode=true&useSSL=false}

username: ${MYSQL_USER:root}

password: ${MYSQL_PASS:123456}

driver-class-name: com.mysql.cj.jdbc.Driver

slave:

url: ${MYSQL_URL:jdbc:mysql://localhost:3306/slave?characterEncoding=UTF-8&useUnicode=true&useSSL=false}

username: ${MYSQL_USER:root}

password: ${MYSQL_PASS:123456}

driver-class-name: com.mysql.cj.jdbc.Driver

程序使用读写分离

显式使用

只需在对应的方法上加上@DS注解并指明对应的数据源即可

package com.cloud.pango.uc.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.cloud.pango.uc.demo.DemoEntity;

import com.cloud.pango.uc.mapper.DemoMapper;

import com.cloud.pango.uc.service.DemoService;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

@Service

public class DemoServiceImpl extends ServiceImpl implements DemoService {

@DS("master")//标明使用master数据源

@Override

public Boolean insert(DemoEntity demo) {

save(demo);

return true;

}

@DS("slave")//标明使用slave数据源

@Override

public DemoEntity findById(String id){

DemoEntity demo = getById(id);

return demo;

}

}

隐式使用

在未使用注解时,使用mybatis-plus拦截器,将读请求转移到slave数据源处理,将写请求转移到master数据源处理

package com.cloud.pango.uc.common;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;

import org.apache.ibatis.executor.Executor;

import org.apache.ibatis.mapping.MappedStatement;

import org.apache.ibatis.mapping.SqlCommandType;

import org.apache.ibatis.plugin.*;

import org.apache.ibatis.session.ResultHandler;

import org.apache.ibatis.session.RowBounds;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Properties;

@Intercepts({

@Signature(type = Executor.class, method = "update", args = {

MappedStatement.class, Object.class }),

@Signature(type = Executor.class, method = "query", args = {

MappedStatement.class, Object.class, RowBounds.class,

ResultHandler.class }) })

@Slf4j

@Component

public class DynamicInterceptor implements Interceptor {

private static final String MASTER = "master";

private static final String SLAVE = "slave";

@Override

public Object intercept(Invocation invocation) throws Throwable {

boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();

if(!synchronizationActive) {

Object[] objects = invocation.getArgs();

MappedStatement ms = (MappedStatement) objects[0];

String currentDataSource = DynamicDataSourceContextHolder.peek();

if(StringUtils.isEmpty(currentDataSource)){

if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {

DynamicDataSourceContextHolder.push(SLAVE);

}else{

DynamicDataSourceContextHolder.push(MASTER);

}

Object proceed = invocation.proceed();

DynamicDataSourceContextHolder.clear();

return proceed;

}

}

return invocation.proceed();

}

@Override

public Object plugin(Object target) {

if (target instanceof Executor) {

return Plugin.wrap(target, this);

} else {

return target;

}

}

@Override

public void setProperties(Properties properties) {

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值