JPA:如何通过字符串UUID选择一个二进制(16)UUID?

3

我有以下实体:

@Data
@Entity
public class Comment implements Serializable {

    @Id
    @GeneratedValue(generator = "uuid4")
    @GenericGenerator(name = "UUID", strategy = "uuid4")
    @Column(columnDefinition = "BINARY(16)")
    private UUID id;

    @Column(columnDefinition = "BINARY(16)")
    private UUID imageId;

    private Instant creationTime;

    private String text;
}

以及一个CRUD存储库:

public interface CommentsRepository extends CrudRepository<Comment, UUID> {

    List<Comment> findAllByImageId(final UUID imageId);
}

我添加了一些示例数据:

@Component
@Slf4j
public class CommentsSampleData implements CommandLineRunner {

    private final CommentsRepository repository;

    @Autowired
    public CommentsSampleData(final CommentsRepository repository) {
        this.repository = repository;
    }

    @Override
    public void run(String... args) {
        createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment1");
        createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment2");
        createComment("617220ff-1642-4490-b589-869e7978c5e0", Instant.now(), "comment3");
        createComment("e3a8aa57-6937-4f9e-b117-78bafe61b718", Instant.now(), "comment1");
    }

    private void createComment(
            final String imageId,
            final Instant creationTime,
            final String text) {
        final Comment comment = new Comment();
        comment.setImageId(UUID.fromString(imageId));
        comment.setCreationTime(creationTime);
        comment.setText(text);

        log.info("save comment: {}", comment);

        repository.save(comment);
    }
}

我的表格中的数据如下所示:

enter image description here

那么现在选择这些二进制UUID的最佳方法是什么?我将从前端获取字符串UUID,因此我想我需要将这些字符串转换为二进制。最好的方法是什么,以便它也可以与id和主键一起使用。

示例终端点:

@Slf4j
@RestController
public class CommentsController {

    private final CommentsService service;

    public CommentsController(final CommentsService service) {
        this.service = service;
    }

    @GetMapping(value = "/comments", produces = MediaType.APPLICATION_JSON_VALUE)
    public List<Comment> getComments(@RequestParam("imageId") final UUID imageId) {
        log.info("get comments by imageId: {}", imageId);

        String existingIds = service.findAll().stream()
                .map(Comment::getImageId)
                .map(UUID::toString)
                .collect(Collectors.joining(","));

        log.info("Image Id Passed: {}", imageId);
        log.info("Existing image ids: {}", existingIds);

        String resultIds = service.findAllByImageId(imageId).stream()
                .map(Comment::getImageId)
                .map(UUID::toString)
                .collect(Collectors.joining(","));

        log.info("Result image ids: {}", resultIds);

        return service.findAllByImageId(imageId);
    }
}

当我现在发送请求时:
localhost:8080/comments?imageId=617220ff-1642-4490-b589-869e7978c5e0

尽管UUID作为二进制(16)存在于数据库中,但我并没有得到结果:

d.f.a.c.service.CommentsController       : Image Id Passed: 617220ff-1642-4490-b589-869e7978c5e0
d.f.a.c.service.CommentsController       : Existing image ids: 617220ff-1642-4490-b589-869e7978c5e0,617220ff-1642-4490-b589-869e7978c5e0,617220ff-1642-4490-b589-869e7978c5e0,e3a8aa57-6937-4f9e-b117-78bafe61b718
d.f.a.c.service.CommentsController       : Result image ids:


如果您现在只是将实体保存为带有UUID的形式,会发生什么?它不会自动转换为二进制并存储吗? - Kavithakaran Kanapathippillai
是的。UUID被存储为二进制16位,如截图所示。问题是我无法查询它们。我在帖子中更新了一个示例端点和GET请求。 - Mulgard
你为什么要一开始就将它们存储为二进制呢?这基本上是对UUID类进行序列化。现在如果有些事情发生了变化,这样反序列化就行不通了。为什么不直接将其存储为UUID(如果您的数据库支持)或char(36)呢? - M. Deinum
因为将其存储为二进制16更加高效:https://devforth.io/blog/why-your-software-should-use-uuids - Mulgard
2个回答

1
  • 它正常工作,没有任何问题,并且可以在UUID和二进制之间自动转换。

  • 我建议尝试以下方法,以确保id确实存在于数据库中。

    @GetMapping(value = "/comments", produces = MediaType.APPLICATION_JSON_VALUE)
    public Iterable<Comment> getComments(@RequestParam("imageId") 
                                          final UUID imageId) {
        log.info("get comments by imageId: {}", imageId);

        String existingIds = service.findAll()
                .map(Comment::getImageId)
                .map(UUID::toString)
                .collect(Collectors.joining(","));
        
        log.info("Image Id Passed : {}", imageId);
        log.info("Existing image ids : {}", existingIds);

        return service.findAllByImageId(imageId);
    }

嗨,我更新了我的帖子并放入了日志结果。但是我没有得到任何结果。 - Mulgard
我明白了。我使用H2数据库,并将其创建为二进制16进制表,且能正确检索。你使用的是哪个数据库? - Kavithakaran Kanapathippillai
我之前一直在使用mysql。我尝试了H2,你说得对,它和H2完美地配合。 - Mulgard

0
另一种方法是
@Query(value = "select BIN_TO_UUID(id), comment from comments", nativeQuery = true)
List<String> findIdAndComments();

BIN_TO_UUID 将把二进制(16)转换为UUID。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接