一、概述
默认情况下,MongoDB Java 驱动程序生成类型的 ID。 有时,我们可能希望使用另一种类型的数据作为对象的唯一标识符,例如 UUID。 但是, MongoDB Java 驱动程序不能自动生成 UUID 。ObjectId
在本教程中,我们将研究使用 MongoDB Java 驱动程序和 Spring Data MongoDB 生成 UUID 的三种方法。
2. 共同点
一个应用程序只管理一种类型的数据是非常罕见的。 为了简化 MongoDB 数据库中 ID 的管理,实现一个抽象类来定义我们所有 Document
类的 ID 会更容易。
public abstract class UuidIdentifiedEntity { @Id protected UUID id; public void setId(UUID id) { if (this.id != null) { throw new UnsupportedOperationException("ID is already defined"); } this.id = id; } // Getter }
对于本教程中的示例,我们将假设 MongoDB 数据库中持久化的所有类都继承自该类。
3.配置UUID支持
为了允许在 MongoDB 中存储 UUID,我们必须配置驱动程序。 这个配置非常简单,只告诉驱动程序如何在数据库中存储 UUID。 如果多个应用程序使用同一个数据库,我们必须小心处理。
我们所要做的就是在启动时在我们的 MongoDB 客户端中指定uuidRepresentation
参数:
@Bean public MongoClient mongo() throws Exception { ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test"); MongoClientSettings mongoClientSettings = MongoClientSettings.builder() .uuidRepresentation(UuidRepresentation.STANDARD) .applyConnectionString(connectionString).build(); return MongoClients.create(mongoClientSettings); }
如果我们使用 Spring Boot,我们可以在 application.properties 文件中指定这个参数:
spring.data.mongodb.uuid-representation=standard
4. 使用生命周期事件
处理 UUID 生成的第一种方法是使用 Spring 的生命周期事件。 对于 MongoDB 实体,我们不能使用 JPA 注释等。 因此,我们必须实现在中注册的事件监听器类。 为此,我们的类必须扩展 Spring 的AbstractMongoEventListener
类:@PrePersist
ApplicationContext
public class UuidIdentifiedEntityEventListener extends AbstractMongoEventListener<UuidIdentifiedEntity> { @Override public void onBeforeConvert(BeforeConvertEvent<UuidIdentifiedEntity> event) { super.onBeforeConvert(event); UuidIdentifiedEntity entity = event.getSource(); if (entity.getId() == null) { entity.setId(UUID.randomUUID()); } } }
在这种情况下,我们使用事件,该事件在 Spring 将我们的 Java 对象转换为对象并将其发送到 MongoDB 驱动程序之前触发。OnBeforeConvert
Document
键入我们的事件以捕获类允许处理此抽象超类型的所有子类。 一旦使用 UUID 作为 ID 的对象被转换,Spring 就会调用我们的代码。UuidIdentifiedEntity
我们必须知道,Spring 将事件处理委托给可能是异步的TaskExecutor
。 Spring 不保证在对像被有效转换之前处理事件。 如果您的是异步的,则不建议使用此方法,因为 ID 可能在对象转换后生成,从而导致异常:TaskExecutor
InvalidDataAccessApiUsageException: Cannot autogenerate id of type java.util.UUID for entity
我们可以通过使用注释或在类中生成它来在中注册事件侦听器:@Component
@Configuration
ApplicationContext
@Bean public UuidIdentifiedEntityEventListener uuidIdentifiedEntityEventListener() { return new UuidIdentifiedEntityEventListener(); }
5. 使用实体回调
Spring 基础设施提供了在实体生命周期中的某些点执行自定义代码的钩子。 这些称为我们可以在我们的案例中使用它们在对像被持久化到数据库之前生成一个 UUID。EntityCallbacks,
与之前看到的事件侦听器方法不同,回调保证它们的执行是同步的,并且代码将在对像生命周期中的预期点运行。
Spring Data MongoDB 提供了一组我们可以在应用程序中使用的回调。 在我们的例子中,我们将使用与之前相同的事件。 回调可以直接在@Configuration
类中提供:
@Bean public BeforeConvertCallback<UuidIdentifiedEntity> beforeSaveCallback() { return (entity, collection) -> { if (entity.getId() == null) { entity.setId(UUID.randomUUID()); } return entity; }; }
我们还可以使用实现BeforeConvertCallback
接口的 。Component
6. 使用自定义存储库
Spring Data MongoDB 提供了第三种方法来实现我们的目标:使用自定义存储库实现。 通常,我们只需要声明一个继承自然后 Spring 处理与存储库相关的代码。MongoRepository,
如果我们想改变 Spring Data 处理对象的方式,我们可以定义 Spring 将在存储库级别执行的自定义代码。 为此,我们必须首先定义一个扩展MongoRepository
的接口:
@NoRepositoryBean public interface CustomMongoRepository<T extends UuidIdentifiedEntity> extends MongoRepository<T, UUID> { }
@NoRepositoryBean
注解防止 Spring 生成与关联的通常代码段。 此接口强制使用 UUID 作为对象中 ID 的类型。MongoRepository
然后,我们必须创建一个存储库类来定义处理 UUID 所需的行为:
public class CustomMongoRepositoryImpl<T extends UuidIdentifiedEntity> extends SimpleMongoRepository<T, UUID> implements CustomMongoRepository<T>
在这个存储库中,我们必须通过覆盖的相关方法来捕获需要生成 ID 的所有方法调用。 在我们的例子中,这些方法是和 :SimpleMongoRepository
save()
insert()
@Override public <S extends T> S save(S entity) { generateId(entity); return super.save(entity); }
最后,我们需要告诉 Spring 使用我们的自定义类作为存储库的实现,而不是默认实现。 我们在类中这样做:@Configuration
@EnableMongoRepositories(basePackages = "com.baeldung.repository", repositoryBaseClass = CustomMongoRepositoryImpl.class)
然后,我们可以像往常一样声明我们的存储库,无需更改:
public interface BookRepository extends MongoRepository<Book, UUID> { }
7.结论
在本文中,我们看到了三种使用Spring Data MongoDB将 UUID 实现为 MongoDB 对象 ID 的方法。
0 评论