領先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多我很高興地宣佈,Spring Data JDBC 和 R2DBC 從版本 4.0.0-M4 開始最終支援複合 ID。
你們中的大多數人可能知道,但為了確保每個人都有相同的理解:從資料庫的角度來看,複合 ID(或複合鍵)是由多個列組成的主鍵。在 Java 端,這些列被對映到一個實體,每個列都有一個屬性。用法應該很簡單,我將在下面的文章中為 JDBC 進行演示。R2DBC 中的用法類似。
要開始使用,只需在您的聚合根中引用實體的欄位上新增 @Id 註解,而不是簡單的型別。
class Employee {
@Id
EmployeeId id;
String name;
// ...
}
record EmployeeId(
Organization organization,
Long employeeNumber) {
}
enum Organization {
RND,
SALES,
MARKETING,
PURCHASING
}
該引用會自動成為嵌入式引用,即實體的欄位會成為聚合根表的列。
create table employee
(
organization varchar(20),
employee_number int,
name varchar(100)
);
如果您想調整名稱,可以新增 @Embedded 註解,它允許您提供一個字首。當載入實體時所有值都為 null 時,指定應該發生什麼看起來有點奇怪。但是使用 Embedded,您必須這樣做,儘管為 null 的主鍵會在所有地方引起問題並且根本無法工作。
class Employee {
@Id
@Embedded.Nullable(prefix = "id_")
EmployeeId id;
String name;
// ...
}
create table employee
(
id_organization varchar(20),
id_employee_number int,
name varchar(100)
);
與普通 ID 一樣,Spring Data Relational 使用 ID 值作為新實體的指示:如果 ID 值為 null,則該實體被視為新實體,將執行插入操作。如果 ID 值不為 null,則需要進行更新。
當儲存具有複合 ID 的新實體時,您現在面臨一個小問題:複合 ID 無法透過自增列輕鬆生成,因為它根據定義由多列組成。處理此問題的一種方法是使用 BeforeConvertCallback。
@Bean
BeforeConvertCallback<Employee> idGeneration() {
return new BeforeConvertCallback<>() {
AtomicLong counter = new AtomicLong();
@Override
public Employee onBeforeConvert(Employee employee) {
if (employee.id == null) {
employee.id = new EmployeeId(Organization.RND, counter.addAndGet(1));
}
return employee;
}
};
}
repository.save(new Employee("Mark Paluch"));
在大多數具有複合 ID 的情況下,預先設定 ID 並使用樂觀鎖(即 null 版本欄位將標記實體為新實體)或顯式呼叫 JdbcAggregateTemplate.insert 可能會更容易。
interface EmployeeRepository extends Repository<Employee, EmployeeId>, InsertRepository<Employee> {
Employee findById(EmployeeId id);
Employee save(Employee employee);
}
interface InsertRepository<E> {
E insert(E employee);
}
class InsertRepositoryImpl<E> implements InsertRepository<E> {
@Autowired
private JdbcAggregateTemplate template;
@Override
public E insert(E employee) {
return template.insert(employee);
}
}
@Autowired
EmployeeRepository repository;
// ...
repository.insert(new Employee(new EmployeeId(Organization.RND, 23L), "Jens Schauder"));
我希望您發現 Spring Data Relational 的這一新增功能很有用。本文中使用的示例的完整程式碼可以在 https://github.com/spring-projects/spring-data-examples/tree/main/jdbc/composite-ids 找到。
如果您發現錯誤或有改進建議,請在 https://github.com/spring-projects/spring-data-relational/issues 建立工單。