乐趣区

关于java:Spring-Data-JDBC-如何使用自定义-ID-生成

原题目:Spring 认证 |Spring Data JDBC- 如何应用自定义 ID 生成

这是对于如何解决应用 Spring Data JDBC 时可能遇到的各种挑战的系列文章的第一篇。

如果你不理解 Spring Data JDBC,你应该首先浏览它的介绍和文章,它解释了 Spring Data JDBC 上下文中的相关性。置信我,这很重要。

文章基于我在 2021 年秋季一期上这篇文章的局部演讲。

应用 ID – 特地是当您想要管制实体的 ID 并且不会抉择什么数据库时,您的抉择是什么。

假如状况下,类型数据列 JDBC 假如的 ID 通过生成 SERIAL 或 AUTOINCREMENT 失去。,聚合根执行插入操作。数据库生成一个 ID,这个 ID 由 Spring Data JDBC 在聚合根中设置。

思考一个由单个简略的类组成的简略聚合:

类小黄人 {

@ID

长 ID;

字符串名称;

Minion(字符串名称){

this.name = 名称;

}

}

进一步思考默认 CrudRepository。

接口 MinionRepository 扩大 CrudRepository {

}

存储库会主动连贯到您的代码中,如下所示:

@主动连线

MinionRepository 随从;

以下工作失常:

Minion before = new Minion(“Bob”);

assertThat(before.id).isNull();

Minion after = minions.save(before);

assertThat(after.id).isNotNull();

然而下一点点:

Minion before = new Minion(“Stuart”);

before.id = 42L;

minions.save(before);

更新语句,Spring Data JDBC 尝试执行更新,因为 ID 曾经设置。然而,因为实际上是新的,更新语句影响零行 Spring Data JDBC 抛出异样。

有几种办法能够解决这个问题。我曾经找到了你不同的解决办法,并且曾经找到了我认为最简略的办法,因而能够找到适宜的办法,你就能够进行浏览。之后回来浏览其余选项并进步您的 Spring Data 技能。

版本

将版本属性增加到您的聚合属性。“版本属性”是指用 @Version。此类的次要目标是能够乐观锁定。然而,作为属性,Spring Data JDBC 应用版本属性来确定聚合根是否是新的。只有版本是 null 或 0 原始类型,聚合就被认为是新的,即便 id 设置了。

应用这种办法,您必须更改实体和(当然)零碎,但别无其他。

此外,对于许多应用程序来说,乐观的最后是很多。

咱们把原来的 Minion 变成了一个 VersionedMinion:

类 VersionedMinion {

@Id 长 ID;

字符串名称;

@Version 整数版本;

VersionedMinion(长 ID,字符串名称){

this.id = id;

this.name = 名称;

}

}

通过此更改,以下结构无效:

VersionedMinion before = new VersionedMinion(23L, “Bob”);

assertThat(before.id).isNotNull();

versionedMinions.save(before);

VersionedMinion 从新加载 = versionedMinions.findById(before.id).get();

assertThat(reloaded.name).isEqualTo(“Bob”);

样板

一种让您的遗赠附带 ID 的办法是本人另外插入物。您能够通过注入 JdbcAggregateTemplate 并调用 JdbcAggregateTemplate.insert(T)。这 JdbAggregateTemplate 是存储库上面的底层,因而您应用存储库用于插入的雷同代码,但您决定何时应用插入:

Minion before = new Minion(“Stuart”);

before.id = 42L;

模板. 插入(之前);

Minion reloaded = minions.findById(42L).get();

assertThat(reloaded.name).isEqualTo(“Stuart”);

请留神,咱们不应用存储库农场应用模板,其中注入了以下内容:

@主动连线

JdbcAggregateTemplate 模板;

事件监听器

模板办法十分实用于您曾经晓得 ID 的状况 – 例如,当您从另一个零碎导入数据并且您想要重用该零碎的 ID 时。

如果您不晓得 ID 并且不想在您的业务代码中蕴含任何 ID 相干的内容,那么应用 ID 可能是更好的抉择。

咱们的目标正确的目标是在某些生命周期事件期间被调用的豆子。它返回批改潜在的聚合根,因而它也实用于不造成实体类。

在指标中,咱们确定有问题的聚合根是否须要新 ID。如果是这样,咱们将应用咱们抉择的算法生成它。

咱们应用另一种变体 Minion

类 StringIdMinion {

@ID

字符串标识;

字符串名称;

StringIdMinion(字符串名称){

this.name = 名称;

}

}

然而,咱们在配置中注册了一个惊人的例子:

@豆角,扁豆

BeforeSaveCallback beforeSaveCallback() {

返回(minion,mutableAggregateChange)-> {

如果(minion.id == null){

minion.id = UUID.randomUUID().toString();

}

返回仆从;

};

}

保留实体的代码当初看起来就像是由数据库生成的:

StringIdMinion before = new StringIdMinion(“Kevin”);

stringions.save(before);

assertThat(before.id).isNotNull();

StringIdMinion reloaded = stringions.findById(before.id).get();

assertThat(reloaded.name).isEqualTo(“Kevin”);

长久的

一个选项是让化根管制是否应该更新或插入。你能够实现长久化的办法(尤其是实现是新的)来实现这一点。您也想应用聚合根进行更新时,这会抓住。在这种状况下,您须要提出更灵便的策略。

咱们须要 Minion 再次调整咱们的:

类 PersistableMinion 实现 Persistable {

@Id 长 ID;

字符串名称;

PersistableMinion(长 ID,字符串名称){

this.id = id;

this.name = 名称;

}

@笼罩

公共长 getId() {

返回标识;

}

@笼罩

公共布尔 isNew() {

// 这个实现必定不适宜生产应用

返回真;

}

}

保留一个的代码 PersistableMinion 看起来是一样的:

PersistableMinion before = new PersistableMinion(23L, “Dave”);

persistableMinions.save(before);

PersistableMinion 从新加载 = persistableMinions.findById(before.id).get();

assertThat(reloaded.name).isEqualTo(“Dave”);

论断

Spring Data JDBC 提供了大量对于如何管制聚合 ID 的选项。尽管我在示例中应用了十分重大的逻辑,但根本没有什么能阻止您实现您所思考的任何逻辑,因为它们都归结为 Java 代码。

残缺的示例代码可在 Spring 中国教育管理中心(Spring 认证)数据示例库拜访!

退出移动版