JOOQ와 함께 Spring Boot를 통해 Spring Data JPA를 언제 사용하고 그 반대의 경우도 마찬가지입니까?
Spring Data JPA는 기본 CRUD 쿼리를 완료하는 데 사용할 수 있지만 JOOQ를 사용하면 더 쉽게 만드는 동안 복잡한 조인 쿼리에는 실제로 사용할 수 없다는 것을 알고 있습니까?
편집: jooq와 함께 Spring 데이터 jpa를 모두 사용할 수 있습니까?
JOOQ와 함께 Spring Boot를 통해 Spring Data JPA를 언제 사용하고 그 반대의 경우도 마찬가지입니까?
Spring Data JPA는 기본 CRUD 쿼리를 완료하는 데 사용할 수 있지만 JOOQ를 사용하면 더 쉽게 만드는 동안 복잡한 조인 쿼리에는 실제로 사용할 수 없다는 것을 알고 있습니까?
편집: jooq와 함께 Spring 데이터 jpa를 모두 사용할 수 있습니까?
귀하의 질문에 쉬운 대답은 없습니다. 나는 그 주제에 대해 몇 가지 연설을 했습니다. 때로는 프로젝트에 둘 다 있어야 하는 합당한 이유가 있습니다.
편집: 방언 및 데이터 유형과 관련하여 데이터베이스에 대한 IMHO 추상화는 여기서 요점이 아닙니다!! jOOQ는 주어진 대상 언어에 대해 SQL을 생성하는 데 꽤 좋은 일을 합니다. JPA/Hibernate도 마찬가지입니다. jOOQ는 Postgres 또는 Oracle과 같은 모든 기능이 없는 데이터베이스의 기능을 에뮬레이트하기 위해 추가 마일을 사용한다고 말할 수 있습니다. 여기서 질문은 " SQL 이 제공하는 모든 것으로 쿼리를 직접 표현할 수 있기를 원합니까, 아니면 JPA가 표현할 수 있는 것에 만족합니까?"입니다.
다음은 둘 다 함께 실행하는 예입니다. 여기에 사용자 정의 확장이 있는 Spring Data JPA 제공 저장소가 있습니다(인터페이스와 구현이 필요함). Spring 컨텍스트가 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();
}
}
나는 이것에 대해 두 번 말했습니다. 이러한 기술에는 은색 총알이 없으며 때로는 매우 얇은 판단입니다.
전체 이야기는 여기: 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 입니다.
'MongoMappingContext#setAutoIndexCreation(boolean)'을 사용하거나 'MongoConfigurationSupport#autoIndexCreation()'을 명시적으로 재정의하세요. 물어보다 (0) | 2022.11.03 |
---|---|
@javax.validation.Valid를 사용할 때 적절한 방식으로 사용자 정의 예외를 발생시키는 방법은 무엇입니까? 물어보다 (0) | 2022.11.03 |
Java에서 문자열을 char로 변환 (0) | 2022.11.02 |
자바에서 제네릭으로 팩토리 패턴 구현하기 (0) | 2022.11.02 |
Mockito @Mock, @Spy, @Captor 및 @InjectMocks 시작하기 (0) | 2022.11.02 |