@mappedsuperclass用于定义不映射为表但可被继承的父类,与抽象类职责不同:前者专注共享映射配置,后者强调不可实例化;二者可共存但非必须搭配。

在 JPA/Hibernate 中,@MappedSuperclass 是专门用于定义**可被继承但自身不映射为数据库表的父类**,它和抽象类(abstract class)可以结合使用,但二者职责不同:抽象类强调“不能实例化、需子类实现”,而 @MappedSuperclass 强调“共享映射配置、不单独建表”。两者可以共存,但不是必须搭配。
为什么不用 @Entity 修饰抽象类?
如果给一个抽象类加上 @Entity,JPA 会尝试为其创建对应的数据表(即使它不能 new 实例),这通常不符合设计意图——你只是想复用字段和映射逻辑,而非持久化父类本身。
例如:
- ❌ 错误做法:
@Entity+abstract class BaseEntity { ... }→ 会生成base_entity表,且子类仍需独立映射,易出错; - ✅ 正确做法:
@MappedSuperclass+abstract class BaseEntity { ... }→ 无表,字段直接“注入”到子类表中。
@MappedSuperclass 的基本写法(含抽象类)
父类声明为抽象类,并标注 @MappedSuperclass,内部可定义 @Id、@Column、@Version、@CreatedDate 等常见注解。所有属性默认继承到子类实体中,无需重复声明。
示例:
@MappedSuperclass
public abstract class BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@Column(name = "created_at", updatable = false)
@CreatedDate
protected LocalDateTime createdAt;
@Column(name = "updated_at")
@LastModifiedDate
protected LocalDateTime updatedAt;
}
子类只需用 @Entity 继承它即可获得这些字段映射:
@Entity
@Table(name = "users")
public class User extends BaseEntity {
@Column(name = "username", nullable = false)
private String username;
@Column(name = "email")
private String email;
}
最终生成的 users 表包含字段:id, created_at, updated_at, username, email。
关键注意事项
-
@MappedSuperclass类不能被EntityManager直接查询或保存(如em.find(BaseEntity.class, 1L)会报错); - 不支持
@Inheritance策略(如SINGLE_TABLE/JOINED),那是@Entity抽象类才用的; - 若父类中有
@Transient字段,子类也会忽略该字段的持久化; - 生命周期回调方法(如
@PrePersist)在父类中定义,会被子类继承并触发; - 泛型、构造器、普通方法均可存在,但只有带 JPA 注解的属性和回调方法影响映射行为。
和 @Inheritance 抽象 @Entity 的区别
如果你需要多态查询(比如 em.createQuery("FROM Person", Person.class) 返回 Student 和 Teacher),那就该用 @Entity + abstract + @Inheritance;
如果只是提取公共字段(如审计字段、ID 生成策略),@MappedSuperclass 更轻量、更安全、更常用。
一句话总结:用 @MappedSuperclass 复用映射结构,用抽象类表达业务约束,二者配合自然,但不要混淆目的。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











