一个基本的快速弹簧数据JDBC示例,介绍如何映射实体中的一对一数据库表关系。
1. 项目配置
1.1. 使用的技术 :
- Spring Boot 2.3.0.RELEASE
- Spring Data JDBC 2.0.0.RELEASE
- Spring Framework 5.2.6.RELEASE
- H2 / MySql DB
- Lombok 1.18.12
- JUnit 5
1.2. Maven 依赖关系 :
要开始使用Spring Boot与Spring Data JDBC,您需要依赖项spring-boot-starter-data-jdbc
。使用Lombok 来避免样板代码。下面是示例应用程序中使用的完整依赖项列表。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1.3. 数据库表 :
以下是数据库表“客户”和“地址”。假设Customer
与Address
关联,并且每个客户只有一个地址。
CREATE TABLE `CUSTOMER` (
`ID` INT NOT NULL AUTO_INCREMENT,
`NAME` varchar(45) NOT NULL,
`MEMBERSHIP` varchar(100) NOT NULL,
PRIMARY KEY (`ID`)
);
CREATE TABLE `ADDRESS` (
`CUSTOMER` INT NOT NULL,
`BUILDING` VARCHAR(45) NOT NULL,
`STREET` VARCHAR(100) NOT NULL,
`STATE` VARCHAR(45) NOT NULL,
`COUNTRY` VARCHAR(45) NOT NULL,
`ZIPCODE` VARCHAR(45) NOT NULL,
CONSTRAINT `BK_PUB_ID_FK`
FOREIGN KEY (`CUSTOMER`) REFERENCES `CUSTOMER` (`ID`)
);
2. 映射
自春季数据 JDBC 1.1 起,它支持使用弹性数据 JDBC 对实体关系进行基于注释的配置。让我们看一下以下代码片段以了解实体映射。
2.1. 地址实体 :
@Table("ADDRESS")
@Data // lombok
@AllArgsConstructor @NoArgsConstructor
public class Address {
//@Id
//private Long id;
private String building;
private String street;
private String state;
private String country;
private String zipcode;
}
2.2. 客户实体 :
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("CUSTOMER")
public class Customer {
@Id
private Long id;
private String name;
private String membership;
private Address address;
}
上述实体我们可以称为客户聚合,并且Customer
是聚合的根实体,它由Address
实体组成。春季数据 JDBC 使用该 ID 来标识实体。实体的 ID 必须使用 Spring 数据的@Id
注释进行注释。如果数据库具有 ID 列的自动增量列,则在将生成的值插入数据库后,将在实体中设置该值。不需要任何其他映射来关联 ,以关联Customer
中Address
实体的一对一映射,除非关联的外键名称和实体名称不同,否则只需要存在地址引用(请参阅第 4 节中的下一个示例)。
Spring Data JDBC将Id生成留给数据库,这意味着我们需要通过在数据库中使用自动递增或其他策略来处理在数据库中插入Id。聚合内部的关系必须是单向的。
您可以注意到,只有聚合使用@Id批注批注的根实体。如果忽略在地址实体中包括“id”字段,则插入由数据库处理的 Id 值。如果在 Address 实体中包含 id 字段,则必须使用 @Id对 id 字段进行批注,或者必须在调用存储库方法插入数据之前将值设置为属性。
3. 测试映射
3.1. 测试仓库
@Repository
public interface CustomerOneToOneTestRepository extends CrudRepository<Customer, Long>{
}
3.2. 测试映射的测试用例
@SpringBootTest
public class OneToOneMappingTest {
@Autowired
private CustomerOneToOneTestRepository customerOneToOneTestRepository;
@Test
@DisplayName("One-to-One Mapping Test1")
void oneToOne_MappingTest1() {
Address address = new Address();
address.setBuilding("102, North Wing, Lotus Avenue");
address.setStreet("Parklane, Los Angeles");
address.setState("California");
address.setCountry("United States");
address.setZipcode("90011");
Customer customer = new Customer();
customer.setName("Peter");
customer.setMembership("FREE");
customer.setAddress(address);
Customer saved = customerOneToOneTestRepository.save(customer);
System.err.println(saved);
Assertions.assertTrue(saved != null);
Optional<Customer> loaded = customerOneToOneTestRepository.findById(1L);
System.err.println(loaded.get());
Assertions.assertTrue(loaded != null);
}
}
4.另一个一对一的例子
4.1. 为了更多地了解实体映射,我想再举一个例子。首先,让我们看一下表格设计的另一个示例。
CREATE TABLE `USER_DETAILS` (
`ID` INT NOT NULL AUTO_INCREMENT,
`CREATED_TIME` datetime NOT NULL,
`UPDATED_TIME` datetime DEFAULT NULL,
`USER_TYPE` varchar(45) NOT NULL,
`DOB` date NOT NULL,
PRIMARY KEY (`ID`)
);
CREATE TABLE `USER_CREDENTIALS` (
`ID` INT NOT NULL AUTO_INCREMENT,
`USER_NAME` VARCHAR(20) NOT NULL,
`PASSWORD` VARCHAR(45) NOT NULL,
`USER_DETAIL` INT NOT NULL,
UNIQUE (`USER_NAME`),
PRIMARY KEY (`ID`),
CONSTRAINT `UD_CREDS_ID_FK`
FOREIGN KEY (`USER_DETAIL`) REFERENCES `USER_DETAILS` (`ID`)
);
4.2. USER_DETAILS和USER_CREDENTIALS表的实体映射。
@Table("USER_CREDENTIALS")
@Data // lombok
@AllArgsConstructor @NoArgsConstructor
public class Credentials {
@Id
private Long id;
private String userName;
private String password;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table("USER_DETAILS")
public class User {
@Id
private Long id;
private Date createdTime;
private Date updatedTime;
@Column("DOB")
private Date dateofBirth;
private UserType userType;
@Column("USER_DETAIL")
private Credentials credentials;
}
从上面的示例和数据库表中,您可以注意到USER_CREDENTIALS表中关联的外键名称(USER_DETAIL)和相应的实体名称是不同的。因此,在这种情况下,我们需要使用@Column注释来映射关联,如上面的用户实体映射所示。
5. 结论
我们演示了一个春季数据 JDBC 示例,介绍如何在实体中映射一对一数据库表关系。
在 Git 中心查看源代码。
其他春季数据 JDBC 示例 :