gpt4 book ai didi

spring - Spring Boot with JOOQ 和 Spring Data JPA 之间的技术差异

转载 作者:行者123 更新时间:2023-12-03 14:36:26 28 4
gpt4 key购买 nike

您何时将 Spring Data JPA 与 Spring Boot 与 JOOQ 一起使用,反之亦然?

我知道 Spring Data JPA 可用于完成基本的 CRUD 查询,但不能真正用于复杂的连接查询,而使用 JOOQ 使其更容易?

编辑:您可以将 Spring 数据 jpa 与 jooq 一起使用吗?

最佳答案

你的问题没有简单的答案。我已经就该主题进行了几次会谈。有时有充分的理由在一个项目中同时拥有这两者。

编辑:恕我直言,关于方言和数据类型的数据库抽象不是这里的重点!! jOOQ 在为给定的目标方言生成 SQL 方面做得非常好——JPA/Hibernate 也是如此。我什至会说 jOOQ 在模拟没有像 Postgres 或 Oracle 这样的所有花里胡哨的数据库的功能方面付出了更多努力。
这里的问题是“我是否希望能够用 SQL 必须提供的所有内容自己表达查询,还是我对 JPA 可以表达的内容感到满意?”

这是一个同时运行两者的示例。我在这里有一个 Spring Data JPA 提供的存储库,带有一个自定义扩展(接口(interface)和实现是必要的)。我让 Spring 上下文同时注入(inject) JPA EntityManager以及 jOOQ 上下文。然后我使用 jOOQ 创建查询并通过 JPA 运行它们。
为什么?因为用 JPA 表达有问题的查询是不可能的(“给我听的最多的东西”,这不是计数最多的,但可能是几个)。

我通过 JPA 运行查询的原因很简单:下游用例可能需要我将 JPA 实体传递给它。 jOOQ 当然可以自己运行这个查询,你可以处理记录或映射任何你喜欢的东西。但正如您特别询问可能使用这两种技术时,我认为这是一个很好的例子:

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.SelectQuery;
import org.jooq.conf.ParamType;
import org.jooq.impl.DSL;
import org.springframework.data.repository.CrudRepository;

import static ac.simons.bootiful_databases.db.tables.Genres.GENRES;
import static ac.simons.bootiful_databases.db.tables.Plays.PLAYS;
import static ac.simons.bootiful_databases.db.tables.Tracks.TRACKS;
import static org.jooq.impl.DSL.count;
import static org.jooq.impl.DSL.rank;
import static org.jooq.impl.DSL.select;

public interface GenreRepository extends
CrudRepository<GenreEntity, Integer>, GenreRepositoryExt {

List<GenreEntity> findAllByOrderByName();
}

interface GenreRepositoryExt {
List<GenreWithPlaycount> findAllWithPlaycount();

List<GenreEntity> findWithHighestPlaycount();
}

class GenreRepositoryImpl implements GenreRepositoryExt {

private final EntityManager entityManager;

private final DSLContext create;

public GenreRepositoryImpl(EntityManager entityManager, DSLContext create) {
this.entityManager = entityManager;
this.create = create;
}

@Override
public List<GenreWithPlaycount> findAllWithPlaycount() {
final Field<Integer> cnt = count().as("cnt");
return this.create
.select(GENRES.GENRE, cnt)
.from(PLAYS)
.join(TRACKS).onKey()
.join(GENRES).onKey()
.groupBy(GENRES.GENRE)
.orderBy(cnt)
.fetchInto(GenreWithPlaycount.class);
}

@Override
public List<GenreEntity> findWithHighestPlaycount() {
/*
select id, genre
from (
select g.id, g.genre, rank() over (order by count(*) desc) rnk
from plays p
join tracks t on p.track_id = t.id
join genres g on t.genre_id = g.id
group by g.id, g.genre
) src
where src.rnk = 1;
*/
final SelectQuery<Record> sqlGenerator =
this.create.select()
.from(
select(
GENRES.ID, GENRES.GENRE,
rank().over().orderBy(count().desc()).as("rnk")
).from(PLAYS)
.join(TRACKS).onKey()
.join(GENRES).onKey()
.groupBy(GENRES.ID, GENRES.GENRE)
).where(DSL.field("rnk").eq(1)).getQuery();

// Retrieve sql with named parameter
final String sql = sqlGenerator.getSQL(ParamType.NAMED);
// and create actual hibernate query
final Query query = this.entityManager.createNativeQuery(sql, GenreEntity.class);
// fill in parameter
sqlGenerator.getParams().forEach((n, v) -> query.setParameter(n, v.getValue()));
// execute query
return query.getResultList();
}
}

我曾多次谈到这一点。这些技术中没有 Elixir ,有时这是一个非常薄弱的​​判断:

完整的演讲在这里: https://speakerdeck.com/michaelsimons/live-with-your-sql-fetish-and-choose-the-right-tool-for-the-job

以及它的录制版本: https://www.youtube.com/watch?v=NJ9ZJstVL9E

完整的工作示例在这里 https://github.com/michael-simons/bootiful-databases .

关于spring - Spring Boot with JOOQ 和 Spring Data JPA 之间的技术差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62055237/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com