当前位置: 首页 > article >正文

外键约束的应用层维护

1.前言

一般来说 对于不同表格之间的属性约束 我们通常直接使用数据库已经实现好的外键来完成 但是数据库底层实现的外键他的性能很差 这是因为在执行数据库修改操作时 他需要遍历其他所有的表来找出其中可能相关联的属性 一并进行数据库修改(应用层的维护则只需要遍历所有关联外键所在的表) 当然 性能差还有其他很多的原因 这里就提供一个思路 所以要求我们可以通过应用层(业务层)来自行维护一个外键约束

2.实现思路

aop+注解
我们会通过aop去拦截所有形式的数据库修改业务 因为不同形式的数据库修改操作(比如removeById和removeByIds)都有可能影响到其他的约束属性 所以不能够遗漏任何情况 对于任何形式的数据库修改操作而言 都需要对可能存在的约束属性进行检查
同时 也会根据注解来标识外键/主键 同时储存一些相关信息(约束主键所在的表以及属性等等) 注解内部的属性也会提供一些默认值

3.注解实现

1.级联枚举类

所谓级联 其实就是在对某个表格的某条记录执行数据库修改操作时 他的影响会传递给其他所有相关联的记录
有两种策略 一种就是只提醒用户 让用户去做具体决定 另一种就是绕过用户 直接进行当前记录以及相关联的所有记录的数据库修改操作
我们可以设计一个枚举类型来储存有限个的级联策略

/**
 * 级联策略 所谓级联 其实就是对某条记录的影响会传递给其他相关联的记录
 * DEFAULT表示默认策略 即提示用户 让用户做具体决定
 * DELETE表示激进策略 不问用户 直接删除/更新当前记录以及有关联的所有记录
 */
public enum ForeignCascade {
    DEFAULT, DELETE
}

2.ForeignField注解

利用该可选注解我们可以用于标识外键属性/主键属性
在真正应用该注解时 如果主表属性为id 就可以直接全部采取默认值 则不需要为主表属性作用该注解 这就是可选注解的理解

/**
 * Documented注解在于会将该注解加入到javadoc文档中
 * Target注解在于设置该注解的作用类型 比如类、方法、属性等等
 * Retention注解在于设置该注解的作用周期 取值为RUNTIME表示可以作用于编译运行完整的阶段
 * Repeatable注解作用是该注解可以在同一个地方同时设置多次 并且需要依赖于一个容器储存 本质上 多次使用就相当于在外部封装一层容器
 */
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(ForeignField.ForeignFields.class)
public @interface ForeignField {
    // 主表类
    Class<?> value() default Object.class;
    // 主表类
    Class<?> mainTable() default Object.class;
    // 主表属性名
    String mainField() default "id";
    // 对应字段
    String column() default "";
    // 级联策略
    ForeignCascade cascade() default ForeignCascade.DEFAULT;
    // 容器
    @Documented
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface ForeignFields {
        ForeignField[] value() default {};
    }
}

3.ForeignTable注解

利用该可选注解我们可以用于标识外键/主键所在表格

/**
 * Documented注解的作用在于会将该注解加入到javadoc文档中
 * Target注解的作用在于该注解只能作用于类上
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ForeignTable {
    // 表名
    String value() default "";
    // 表名
    String name() default "";
}

3.属性信息类/表格信息类实现

1.属性信息类

/**
 * 该类是属性信息类
 */
@Getter
@Setter
public class ForeignFieldInfo {
    // 当前属性
    private Field field;
    // 当前属性对应字段
    private String column;
    // 当前属性所在的表格信息类
    private ForeignTableInfo table;
    // 引用的属性集合
    private List<ForeignFieldInfo> mainFields;
    // 被引用的属性集合
    private List<ForeignFieldInfo> subFields;
    // 级联策略
    private ForeignCascade cascade;
    // 设置属性 如果属性是私有属性的话 那么就不可以直接由外界访问 这时候 我们应该开放权限
    public void setField(Field field) {
        // 表明任意权限的变量都可以访问 即使是private也行
        field.setAccessible(true);
        this.field = field;
    }
    // 追加引用属性
    public void addMainField(ForeignFieldInfo mainField) {
        // 如果集合不存在的话 那么就先创建集合 如果参数已经存在的话 那么就不追加 否则的话 就直接追加
        if (mainFields == null) {
            mainFields = new ArrayList<>();
        } else if (mainFields.contains(mainField)) {
            return;
        }
        mainFields.add(mainField);
    }
    // 追加被引用属性
    public void addSubField(ForeignFieldInfo subField) {
        // 如果集合不存在的话 先创建集合 如果已经存在 考虑参数是否存在于集合 如果存在 那就不添加 反之则需要添加
        if (subFields == null) {
            subFields = new ArrayList<>();
        } else if (subFields.contains(subField)) {
            return;
        }
        subFields.add(subField);
    }
}

http://www.kler.cn/a/454811.html

相关文章:

  • 如何用WPS AI提高工作效率
  • 嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
  • xwd-ant组件库笔记
  • 金融租赁系统的发展与全球化战略实施探讨
  • MySQL外键类型与应用场景总结:优缺点一目了然
  • 04软件测试需求分析案例-用户登录
  • Spring Boot 自动配置:从 spring.factories 到 AutoConfiguration.imports
  • PlantUML 入门使用指南
  • Llama 3 后训练(三)
  • 逻辑控制语句
  • 【Unity3D】ECS入门学习(六)状态组件 ISystemStateComponentData
  • fisco-bcos手动部署区块链浏览器
  • 【Leetcode】3159. 查询数组中元素的出现位置
  • 顶会评测集解读-AlignBench: 大语言模型中文对齐基准
  • 什么是Top-p采样与Top-k采样?大模型推理时如何同时设置?解析Transformers库源代码
  • 智能合约在Web3中的作用:去中心化应用的基石
  • 探寻 OneCode 核心优势:MVVM 进阶与前后端协同之魅
  • HTML5 开发工具与调试
  • Kubernetes 的资源管理方式
  • 【Java 代码审计入门-02】SQL 漏洞原理与实际案例介绍
  • 负载均衡式在线OJ系统测试报告(Jmeter性能测试、Selenium自动化测试脚本)
  • 嵌入式单片机模数转换控制与实现详解
  • JS 设置按钮的loading效果
  • 开源 SOAP over UDP
  • OpenCV相机标定与3D重建(35)计算两幅图像之间本质矩阵(Essential Matrix)的函数findEssentialMat()的使用
  • Django框架:构建高效Web应用的强大工具