Skip to content

mybatis

这里介绍一下 mybatis 的使用。

功能介绍

主要包含在 wmeimob-spring-boot-starter-mybatis jar 中。

支持的功能:

  • 基础 baseEntity
  • 移除 druid ad filter
  • 通用 json 类型处理器
    • FastjsonListTypeHandler
    • FastjsonTypeHandler
    • JacksonTypeHandler
    • JSONArrayTypeHandler
    • JsonTypeHandler
    • IntegerListHandler
    • LongListHandler
    • StringListHandler
    • IntegerToBooleanHandler
  • mapper 扩展
    • mybatis.plus 抽象接口 BaseMapperExtend
    • tk.mybatis 抽象接口 CrudMapper

mybatis-plus 高级特性

  • 自动逻辑删

通过使用如下注解来实现:

java
@TableLogic(delval = "id", value = "0")
  • 乐观锁

通过使用如下注解来实现:

java
@Version
  • 多租户

通过实现TenantLineHandler接口来自定义处理逻辑。下面是一个示例:

java
/**
 * 租户数据隔离处理器
 *
 * @author mjyang
 * @date 2023/9/15 10:58
 */
@AllArgsConstructor
public class TenantLineHandlerImpl implements TenantLineHandler {
    private final List<String> includeTableNames;

    private final String tenantIdColumn;

    @Override
    public Expression getTenantId() {
        return new LongValue(TenantContextHolder.geId());
    }

    @Override
    public String getTenantIdColumn() {
        return tenantIdColumn;
    }

    @Override
    public boolean ignoreTable(String tableName) {
        return !includeTableNames.contains(tableName);
    }
}
java
/**
 * 租户上下文 holder
 *
 * @author mjyang
 * @date 2023/9/15 11:03
 */
public class TenantContextHolder {
    /**
     * 当前租户信息
     */
    private static final ThreadLocal<Long> TENANT_ID = new ThreadLocal<>();

    /**
     * 获得租户 id
     *
     * @return long
     */
    public static Long get() {
        return TENANT_ID.get();
    }

    /**
     * 设置租户id
     *
     * @param id 租户 id
     */
    public static void put(Long id) {
        TENANT_ID.set(id);
    }

    public static void clear() {
        TENANT_ID.remove();
    }
}
java
/**
 * 租户 filter
 *
 * @author mjyang
 * @date 2023/9/15 11:01
 */
@Component
public class TenantTenantFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        TenantContextHolder.setId(xxx);
        try {
            chain.doFilter(request, response);
        } finally {
            TenantContextHolder.clear();
        }
    }
}
java
@Component
@EnableConfigurationProperties(TenantProperties.class)
public class MyBatisInterceptorPostProcessor implements BeanPostProcessor {

    @Resource
    private TenantProperties tenantProperties;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof MybatisPlusInterceptor) {
            MybatisPlusInterceptor interceptor = (MybatisPlusInterceptor) bean;
            interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandlerImpl(
                this.tenantProperties.getIncludeTableNames(),
                this.tenantProperties.getTenantIdColumn()
          )));
        }
        return bean;
    }
}
java
/**
 * 租户配置类
 * 
 * @author mjyang
 * @date 2023/9/15 14:30
 */
@ConfigurationProperties("mybatis-plus")
@Getter
@Setter
public class TenantProperties {
    /**
     * 要包含的表名
     */
    private List<String> includeTableNames;

    /**
     * 租户字段
     */
    private String tenantIdColumn;
}

这样处理后,业务逻辑处理时会自动加上租户字段。如果有些业务想忽略租户时,则可以使用注解@IgnoreTenant。以下是注解实现代码:

java
/**
 * 忽略租户拦截
 *
 * @author mjyang
 * @date 2022/4/1 11:02
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IgnoreTenant {
}
java
/**
 * 忽略租户条件拦截器
 *
 * @author mjyang
 * @date 2022/4/1 11:01
 */
@Aspect
@Component
public class IgnoreTenantAspect {

    @Pointcut("@annotation(IgnoreTenant)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object myAround(ProceedingJoinPoint point) throws Throwable {
        Class<?> targetClass = point.getTarget().getClass();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = targetClass.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        IgnoreTenant ignoreTenant = AnnotationUtil.getAnnotation(method, IgnoreTenant.class);
        if (ignoreTenant == null) {
            return point.proceed();
        }

        InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
        try {
            return point.proceed();
        } finally {
            InterceptorIgnoreHelper.clearIgnoreStrategy();
        }
    }
}

tk.mybatis

  • 自动逻辑删

通过使用如下注解来实现:

java
@LogicDelete
  • 乐观锁

通过使用如下注解来实现:

java
@Version