一对一指关系数据库中第一个表中的单个行只可以与第二个表中的一个行相关,且第二个表中的一个行也只可以与第一个表中的一个行相关。
下面将通过用户和用户身份证号码为例,介绍一对一关系。
通常,在一对一关系中,需要在主表的一方添加一个外键关联附表。如下图:
(1)用户表对应的 User 实体,代码如下:
@Data @Entity @Table public class User { @Id @GeneratedValue private int id; @Column private String name; // 这里是关键 @OneToOne private IdNumber idNumber; }
(2)用户身份证表对应的 IdNumber 实体,代码如下:
@Data @Entity @Table public class IdNumber { @Id @GeneratedValue private int id; @Column private String number; }
从上面代码可以看到,在表结构方面,我们应该是在 user(用户)表中添加外键列来维护用户的身份证号码。在对象设计方面,在 User 对象中关联 IdNumber 对象,来封装当前用户的身份证号码。
(1)persistence.xml 配置
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"> <persistence-unit name="demo_onetoone" transaction-type="RESOURCE_LOCAL"> <!-- JPA提供者 --> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> <!-- 声明实体类 --> <class>com.hxstrive.openjpa.annotation.demo_onetoone.User</class> <class>com.hxstrive.openjpa.annotation.demo_onetoone.IdNumber</class> <!-- 配置JPA数据库属性 --> <properties> <property name="openjpa.ConnectionURL" value="jdbc:mysql://localhost:3306/openjpa_learn?useSSL=false& serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"/> <property name="openjpa.ConnectionDriverName" value="com.mysql.jdbc.Driver"/> <property name="openjpa.ConnectionUserName" value="root"/> <property name="openjpa.ConnectionPassword" value="aaaaaa"/> <property name="openjpa.Log" value="SQL=TRACE"/> <!-- 自动生成表 --> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/> <!-- 不使用加载时强化和编译时强化,使用运行时Unenhanced(不能发挥OpenJPA的最大效能,所以也不推荐) --> <property name="openjpa.ClassLoadEnhancement" value="false"/> <property name="openjpa.DynamicEnhancementAgent" value="false"/> <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/> </properties> </persistence-unit> </persistence>
(2)User 用户实体
@Data @Entity @Table public class User { @Id @GeneratedValue private int id; @Column private String name; @OneToOne private IdNumber idNumber; }
(3)IdNumber 身份证实体
@Data @Entity @Table public class IdNumber { @Id @GeneratedValue private int id; @Column private String number; }
(4)客户端代码
import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; public class Demo { /** 持久化单元名称 */ private static final String NAME = "demo_onetoone"; public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory(NAME); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // 身份证号码 IdNumber idNumber = new IdNumber(); idNumber.setNumber("身份证号码1"); // 用户 User user = new User(); user.setName("用户1"); user.setIdNumber(idNumber); em.persist(idNumber); em.persist(user); em.getTransaction().commit(); em.close(); emf.close(); System.out.println("finished."); } }
运行输出 SQL 日志如下:
INSERT INTO IdNumber (id, number) VALUES (?, ?) [params=?, ?] INSERT INTO User (id, name, IDNUMBER_ID) VALUES (?, ?, ?) [params=?, ?, ?]
数据表数据如下图: