在面向对象编程中,继承是复用代码、梳理类关系的重要特性,但mysql作为关系型数据库,本身并不支持原生的表继承语法,需要开发者通过合理的表结构设计来模拟实现继承效果,适配面向对象的业务设计需求。

常见的mysql表继承实现方案
1. 单表继承(Single Table Inheritance)
单表继承是将所有父类和子类的字段都放在同一张表中,通过一个类型标识字段区分不同的子类。这种方案结构最简单,查询效率最高,适合子类字段差异不大的场景。
比如我们有一个父类vehicle(交通工具),子类car(汽车)和bicycle(自行车),汽车有座位数属性,自行车有车筐容量属性,用单表继承设计的表结构如下:
-- 创建单表继承的交通工具表
CREATE TABLE vehicle (
id INT PRIMARY KEY AUTO_INCREMENT,
type VARCHAR(20) NOT NULL COMMENT '类型标识:car表示汽车,bicycle表示自行车',
name VARCHAR(50) NOT NULL COMMENT '交通工具名称',
-- 汽车特有字段
seat_count INT DEFAULT NULL COMMENT '座位数',
-- 自行车特有字段
basket_capacity DECIMAL(5,2) DEFAULT NULL COMMENT '车筐容量,单位升'
);
-- 插入汽车数据
INSERT INTO vehicle (type, name, seat_count) VALUES ('car', '家用轿车', 5);
-- 插入自行车数据
INSERT INTO vehicle (type, name, basket_capacity) VALUES ('bicycle', '通勤自行车', 15.5);
-- 查询所有汽车数据
SELECT id, name, seat_count FROM vehicle WHERE type = 'car';
这种方案的优点是查询时不需要关联多张表,所有数据都在一张表中,查询效率高;缺点是表中会有很多冗余字段,不同子类的特有字段对其他子类来说是无效的,当子类数量多、字段差异大时,表结构会非常臃肿。
2. 类表继承(Class Table Inheritance)
类表继承是为父类和每个子类分别创建独立的表,父类表存放所有子类的公共字段,子类表存放自身特有的字段,子类表通过主键关联父类表的主键。这种方案符合面向对象的类结构,数据冗余少。
还是以上面的交通工具场景为例,类表继承的表结构设计如下:
-- 父类表:交通工具公共信息
CREATE TABLE vehicle (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL COMMENT '交通工具名称'
);
-- 子类表:汽车特有信息
CREATE TABLE car (
vehicle_id INT PRIMARY KEY COMMENT '关联vehicle表的主键',
seat_count INT NOT NULL COMMENT '座位数',
FOREIGN KEY (vehicle_id) REFERENCES vehicle(id)
);
-- 子类表:自行车特有信息
CREATE TABLE bicycle (
vehicle_id INT PRIMARY KEY COMMENT '关联vehicle表的主键',
basket_capacity DECIMAL(5,2) NOT NULL COMMENT '车筐容量,单位升',
FOREIGN KEY (vehicle_id) REFERENCES vehicle(id)
);
-- 插入汽车数据:先插父类表,再插子类表
INSERT INTO vehicle (name) VALUES ('家用轿车');
INSERT INTO car (vehicle_id, seat_count) VALUES (LAST_INSERT_ID(), 5);
-- 插入自行车数据
INSERT INTO vehicle (name) VALUES ('通勤自行车');
INSERT INTO bicycle (vehicle_id, basket_capacity) VALUES (LAST_INSERT_ID(), 15.5);
-- 查询所有汽车及完整信息,需要关联两张表
SELECT v.id, v.name, c.seat_count
FROM vehicle v
JOIN car c ON v.id = c.vehicle_id;
这种方案的优点是表结构清晰,符合面向对象的继承关系,没有无效冗余字段;缺点是查询子类完整数据时需要关联父类表,当继承层级多时,关联查询的复杂度会上升,查询效率略低于单表继承。
3. 具体表继承(Concrete Table Inheritance)
具体表继承是为每个子类创建独立的完整表,每个子类的表都包含所有字段(包括从父类继承的公共字段和自身特有字段),父类不单独建表。这种方案适合子类之间字段差异大、很少需要查询所有父类数据的场景。
同样以交通工具为例,具体表继承的表结构设计如下:
-- 汽车表,包含所有需要的字段
CREATE TABLE car (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL COMMENT '交通工具名称',
seat_count INT NOT NULL COMMENT '座位数'
);
-- 自行车表,包含所有需要的字段
CREATE TABLE bicycle (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL COMMENT '交通工具名称',
basket_capacity DECIMAL(5,2) NOT NULL COMMENT '车筐容量,单位升'
);
-- 插入汽车数据
INSERT INTO car (name, seat_count) VALUES ('家用轿车', 5);
-- 插入自行车数据
INSERT INTO bicycle (name, basket_capacity) VALUES ('通勤自行车', 15.5);
-- 查询所有汽车数据
SELECT id, name, seat_count FROM car;
-- 如果需要查询所有交通工具,需要用UNION合并结果
SELECT id, name, 'car' AS type FROM car
UNION ALL
SELECT id, name, 'bicycle' AS type FROM bicycle;
这种方案的优点是每个子类的表结构独立,查询单个子类数据时不需要关联,效率很高;缺点是公共字段在多个表中重复存储,数据冗余高,如果需要修改公共字段,所有子类表都要同步修改,维护成本高,也不方便做公共字段的统一约束。
方案选择建议
在实际的mysql面向对象设计中,选择哪种表继承方案需要结合业务场景判断:
- 如果子类数量少,字段差异小,且经常需要查询所有父类的公共数据,优先选择单表继承,开发和维护成本最低。
- 如果子类字段差异大,需要严格遵循面向对象的类结构,且经常需要单独查询某个子类的完整数据,优先选择类表继承,结构清晰冗余少。
- 如果子类之间几乎没有公共字段,或者很少需要查询所有父类的公共数据,优先选择具体表继承,查询效率最高。
注意事项
无论选择哪种方案,都需要注意以下几点:
- 如果选择类表继承,子类表的主键建议直接使用父类表的主键作为外键,避免额外生成自增主键,减少字段冗余。
- 单表继承的类型标识字段建议加索引,提升按类型查询的效率。
- 如果业务中有多态关联的需求(比如一张
order表需要关联不同的交通工具子类),类表继承可以通过在order表中存父类主键实现,单表继承也可以直接存对应表的主键,具体表继承则需要额外设计关联表来适配。