全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-20 8 分钟 ✍️ juanwangdev

复杂继承映射

复杂继承映射处理 Java 类层次结构与数据库表之间的映射关系,核心是通过 discriminator 根据列值动态选择不同子类的映射规则。

继承映射三种策略

策略表结构优点缺点
单表继承 (STI)一张表包含所有字段查询简单,无 JOIN存在大量 NULL 字段
类表继承 (CTI)父类表 + 子类表无冗余字段查询需 JOIN
具体表继承 (CCTI)每个子类一张完整表结构清晰公共字段重复,多态查询困难

单表继承映射 (STI)

所有子类字段存储在一张表中,通过 discriminator 列区分类型:

SQL
CREATE TABLE shape (
  id INT PRIMARY KEY,
  type VARCHAR(20) NOT NULL,
  color VARCHAR(20),
  -- Circle 专用
  radius DOUBLE,
  -- Rectangle 专用
  width DOUBLE,
  height DOUBLE,
  -- Triangle 专用
  base DOUBLE,
  side_a DOUBLE,
  side_b DOUBLE
);

Java 类层次:

Java
public abstract class Shape {
  private Integer id;
  private String color;
}

public class Circle extends Shape {
  private Double radius;
}

public class Rectangle extends Shape {
  private Double width;
  private Double height;
}

public class Triangle extends Shape {
  private Double base;
  private Double sideA;
  private Double sideB;
}

映射配置:

XML
<resultMap id="shapeResultMap" type="Shape">
  <id property="id" column="id"/>
  <result property="color" column="color"/>
  <discriminator javaType="string" column="type">
    <case value="CIRCLE" type="Circle">
      <result property="radius" column="radius"/>
    </case>
    <case value="RECTANGLE" type="Rectangle">
      <result property="width" column="width"/>
      <result property="height" column="height"/>
    </case>
    <case value="TRIANGLE" type="Triangle">
      <result property="base" column="base"/>
      <result property="sideA" column="side_a"/>
      <result property="sideB" column="side_b"/>
    </case>
  </discriminator>
</resultMap>

<select id="selectAllShapes" resultMap="shapeResultMap">
  SELECT * FROM shape
</select>

单表继承查询简单,一条 SQL 即可获取所有类型数据,但字段稀疏时浪费存储空间。

类表继承映射 (CTI)

父类字段存入基表,子类特有字段存入各自扩展表:

SQL
CREATE TABLE shape_base (
  id INT PRIMARY KEY,
  type VARCHAR(20) NOT NULL,
  color VARCHAR(20)
);

CREATE TABLE circle_ext (
  shape_id INT PRIMARY KEY,
  radius DOUBLE,
  FOREIGN KEY (shape_id) REFERENCES shape_base(id)
);

CREATE TABLE rectangle_ext (
  shape_id INT PRIMARY KEY,
  width DOUBLE,
  height DOUBLE,
  FOREIGN KEY (shape_id) REFERENCES shape_base(id)
);

映射配置使用 discriminator + 嵌套 association:

XML
<resultMap id="shapeCTIResultMap" type="Shape">
  <id property="id" column="id"/>
  <result property="color" column="color"/>
  <discriminator javaType="string" column="type">
    <case value="CIRCLE" type="Circle">
      <association property="radius" column="shape_id"
                   select="selectCircleExt"/>
    </case>
    <case value="RECTANGLE" type="Rectangle">
      <association property="width" column="shape_id"
                   select="selectRectangleExt"/>
    </case>
  </discriminator>
</resultMap>

<!-- 更优方案:JOIN 查询 + columnPrefix -->
<resultMap id="shapeCTIJoinResultMap" type="Shape">
  <id property="id" column="id"/>
  <result property="color" column="color"/>
  <discriminator javaType="string" column="type">
    <case value="CIRCLE" type="Circle">
      <result property="radius" column="radius"/>
    </case>
    <case value="RECTANGLE" type="Rectangle">
      <result property="width" column="width"/>
      <result property="height" column="height"/>
    </case>
  </discriminator>
</resultMap>

<select id="selectShapesCTI" resultMap="shapeCTIJoinResultMap">
  SELECT s.id, s.type, s.color,
         c.radius, r.width, r.height
  FROM shape_base s
  LEFT JOIN circle_ext c ON s.id = c.shape_id
  LEFT JOIN rectangle_ext r ON s.id = r.shape_id
</select>

深度继承层次映射

处理多层继承关系时,使用嵌套 discriminator 或组合映射:

Java
public class Vehicle {
  private Integer id;
  private String brand;
}

public class Car extends Vehicle {
  private Integer doorCount;
}

public class ElectricCar extends Car {
  private Double batteryCapacity;
  private Integer chargingTime;
}

public class GasCar extends Car {
  private Double engineDisplacement;
  private Integer cylinderCount;
}
XML
<resultMap id="vehicleResultMap" type="Vehicle">
  <id property="id" column="id"/>
  <result property="brand" column="brand"/>
  <discriminator javaType="string" column="type">
    <case value="CAR" type="Car">
      <result property="doorCount" column="door_count"/>
      <discriminator javaType="string" column="energy_type">
        <case value="ELECTRIC" type="ElectricCar">
          <result property="batteryCapacity" column="battery_capacity"/>
          <result property="chargingTime" column="charging_time"/>
        </case>
        <case value="GAS" type="GasCar">
          <result property="engineDisplacement" column="engine_disp"/>
          <result property="cylinderCount" column="cylinder_count"/>
        </case>
      </discriminator>
    </case>
  </discriminator>
</resultMap>

嵌套 discriminator 适用于三层及以上继承,但会增加映射复杂度,建议控制继承层级不超过三层。

多态查询实践

统一查询接口

Java
public interface ShapeMapper {
  // 多态查询:返回 Shape 及其所有子类
  List<Shape> selectAllShapes();
  
  // 按类型过滤
  List<Shape> selectShapesByType(@Param("types") List<String> types);
  
  // 获取特定子类
  List<Circle> selectCircles();
}
XML
<select id="selectAllShapes" resultMap="shapeResultMap">
  SELECT * FROM shape
</select>

<select id="selectShapesByType" resultMap="shapeResultMap">
  SELECT * FROM shape
  <where>
    <if test="types != null and types.size() > 0">
      type IN
      <foreach collection="types" item="t" open="(" separator="," close=")">
        #{t}
      </foreach>
    </if>
  </where>
</select>

多态更新操作

XML
<!-- 更新公共字段 -->
<update id="updateShapeColor">
  UPDATE shape SET color = #{color} WHERE id = #{id}
</update>

<!-- 更新子类特有字段 -->
<update id="updateCircleRadius">
  UPDATE shape SET radius = #{radius} WHERE id = #{id} AND type = 'CIRCLE'
</update>

更新操作需根据 type 列区分处理逻辑,避免将子类字段更新到错误的记录上。

策略对比与选型

维度单表继承类表继承具体表继承
查询性能最优(单表)中(需 JOIN)差(多表 UNION)
存储空间浪费(NULL 多)最优
扩展子类加列即可新建扩展表新建完整表
多态查询支持支持困难
映射复杂度
适用场景字段重叠率高子类差异大完全独立业务

选型建议:

  • 字段重叠率 > 60%:单表继承,查询效率最优。
  • 子类特有字段多且差异大:类表继承,避免大量 NULL。
  • 子类业务完全独立:具体表继承,保持边界清晰。

要点总结

  • 单表继承 (STI) 查询最优但存在字段稀疏问题,适合重叠率高的场景。
  • 类表继承 (CTI) 通过 JOIN 扩展表获取子类字段,结构清晰但查询略慢。
  • discriminator 支持嵌套使用,可处理三层及以上继承关系。
  • 嵌套 discriminator 复杂度随层级增长,建议控制继承深度不超过三层。
  • 多态查询配合 discriminator 可统一返回父类引用,运行时自动实例化为子类。
  • 策略选型核心指标:字段重叠率决定 STI 还是 CTI,业务独立性决定 CCTI。

📝 发现内容有误?点击此处直接编辑

← 上一篇 动态表名与列名
下一篇 → 大数据量查询优化
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库