在正式了解 @SecondaryTable 注解用法之前,我们先看看一个关于主表(users)和子表(users_ext)的实例:

上图中,users 为主表,该表记录了用户主要信息;users_ext 为子表(也称为附表),该表用来记录用户的扩展信息。我们可以使用 @SecondaryTable 注解将一个实体中的数据分别存储到不同的数据表中。
@SecondaryTable 注解的主要用是将主表提取成公共表,子表是自行定义。@SecondaryTable 和 @Table 注解一样,也支持如下属性:
name
该属性用于指定数据库表名称,即主表的附表名称;例如:
// users_ext 为副表 @SecondaryTable(name = "users_ext", pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id") )
catalog
可选属性,用于指定数据库实例名,一般来说 persistence.xml 文件中必须指定数据库 url,url 中将包含数据库实例;
schema
作用与 catalog 属性作用一致,可自行测试;
uniqueConstraints
该属性用于设定约束条件,即唯一性约束;
pkJoinColumns
指定用于和主表连接的列;例如:
// user_id 用来和主表进行关联 @SecondaryTable(name = "users_ext", pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id") )
使用 @SecondaryTable 将 users 和 users_ext 表进行关联(根据 user_id 列进行关联),将 User7 实体中的数据分别存储到 users 主表 和 users_ext 附表。代码如下:
@Entity
@Table(name = "users")
@SecondaryTable(name = "users_ext",
pkJoinColumns = @PrimaryKeyJoinColumn(name = "user_id")
)
public class User7 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(table = "users")
private Integer id;
@Column(name = "name", table = "users")
private String name;
@Column(precision = 8, table = "users")
private Integer age;
// 下面字段数据来自 users_ext 表
@Column(name = "user_id", table = "users_ext")
private Integer userId;
@Column(name = "email", table = "users_ext")
private String email;
@Column(name = "home_url", table = "users_ext")
private String homeUrl;
}客户端代码,使用 EntityManager 实例插入和查询 User7 对应的数据,代码如下:
import com.alibaba.fastjson.JSONObject;
import com.huangx.openjpa.annotation.entity.User7;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;
public class OpenJpaDemo7 {
/** 持久化单元名称 */
private static final String NAME = "openJPA";
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME);
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// INSERT
User7 user = new User7();
user.setName("武松-" + System.currentTimeMillis());
user.setAge(27);
user.setEmail("wusong@outlook.com");
user.setHomeUrl("http://www.wusong.com/index.html");
em.persist(user);
// SELECT
String qlString = "select t from User7 t";
Query query = em.createQuery(qlString);
List<User7> userList = (List<User7>) query.getResultList();
for (User7 item : userList) {
System.out.println(JSONObject.toJSONString(item));
}
em.getTransaction().commit();
em.close();
emf.close();
System.out.println("finished.");
}
}如果在 @Entity 实体上未指定 @SecondaryTable 注释,则实体的所有可持久化字段或属性都映射到主表。
如果注释 @SecondaryTable 未指定主键连接列(pkJoinColumns 属性),则假设连接列引用主表的主键列。实例:
@Entity
@Table(name = "users")
@SecondaryTable(name = "users_ext2")
public class User9 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(table = "users")
private Integer id;
@Column(name = "name", table = "users")
private String name;
@Column(precision = 8, table = "users")
private Integer age;
// 下面字段数据来自 users_ext 表
@Column(name = "email", table = "users_ext2")
private String email;
@Column(name = "home_url", table = "users_ext2")
private String homeUrl;
}等价于
@SecondaryTable(name = "users_ext2", pkJoinColumns = {
@PrimaryKeyJoinColumn(name = "USER9_ID")
}上面实例将自动在 users_ext 表中创建一个 user9_id 字段来存放关联主键,SQL 脚本如下:
CREATE TABLE `users_ext2` ( `email` varchar(255) DEFAULT NULL, `home_url` varchar(255) DEFAULT NULL, `USER9_ID` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
该注解用来为一个实体指定多个辅助表。例如:
实例1:多个辅助表假设所有表中的主键列名称相同。
@Entity
@Table(name="users")
@SecondaryTables({
@SecondaryTable(name="users_ext"),
@SecondaryTable(name="users_ext2")
})
public class User9 {
// ...
}实例2:具有不同名称的主键列的多个辅助表。
@Entity
@Table(name="users")
@SecondaryTables({
@SecondaryTable(name="users_ext",
pkJoinColumns=@PrimaryKeyJoinColumn(name="user_id")),
@SecondaryTable(name="users_ext2",
pkJoinColumns=@PrimaryKeyJoinColumn(name="user9_id"))
})
public class User9 {
// ...
}