QuerydslRepositorySupport
를 상속받아 사용했다.JPAQueryFactory
만 있다면 Querydsl을 사용하는 데에 문제가 없다.@RequiredArgsConstructor
@Repository
public class UserRepository {
private final JPAQueryFactory queryFactory;
}
BooleanBuilder
사용해서 동적쿼리를 만들게 되는데 쿼리를 예상하기 어렵다.BooleanExpression
을 이용하면 함수로 만들어 null 반환 시 자동으로 조건절에서 제거되며 좀 더 알아보기 쉽다.// BooleanBuilder
public List<Academy> findDynamicQuery(...) {
BooleanBuilder bulider = new BooleanBuilder();
if (!StringUtils.isEmpty(name)) {
builder.and(academy.name.eq(name));
}
if (!StringUtils.isEmpty(address)) {
builder.and(academy.address.eq(address));
}
if (!StringUtils.isEmpty(phoneNumber)) {
builder.and(academy.phoneNumber.eq(phoneNumber));
}
queryFacotry.selectFrom(academy)
.where(builder)
.fetch();
}
// BooleanExpression
public List<Academy> findDynamicQuery(...) {
queryFacotry.selectFrom(academy)
.where(
eqName(name),
eqAddress(address),
eqPhoneNumber(phoneNumber))
.fetch();
private BooleanExpression eqName(String name) {
if (StringUtils.isEmpty(name)) return null;
return academy.name.eq(name);
}
private BooleanExpression eqAddress(String address) {
if (StringUtils.isEmpty(address)) return null;
return academy.address.eq(address);
}
private BooleanExpression eqPhoneNumber(String phoneNumber) {
if (StringUtils.isEmpty(phoneNumber)) return null;
return academy.phoneNumber.eq(phoneNumber);
}
}
// exists
select exists(
select 1
from ad_item_sum
where created_date > '2020-01-01'
)
// count
select count(1) from ad_item_sum where created_date > '2020-01-01'
public Boolean exist(Long bookId) {
Integer fetchOne = queryFactory
.selectOne()
.from(book)
.where(book.id.eq(bookId))
.fetchFirst();
return fetchOne != null;
}
// fetchFirst == limit(1).fetchOne()
// Querydsl
public List<Customer> crossJoin() {
return queryFactory
.selectFrom(customer)
.where(customer.customerNo.gt(customer.shop.shopNo))
.fetch();
}
// JPQL
@Query("SELECT c FROM Customer c WHERE c.customerNo > c.shop.shopNo")
List<Customer> crossJoin();
public List<Customer> crossJoin() {
return queryFactory
.selectFrom(customer)
.innerJoin(customer.shop, shop)
.where(customer.customerNo.gt(shop.shopNo))
.fetch();
}
// Entity
queryFactory
.selectFrom(book)
.where(book.bookNo.eq(bookNo))
.offset(pageNo)
.limit(10)
.fetch();
// Dto
queryFactory
.select(Projections.fields(BookPageDto.class,
book.name,
book.bookNo,
book.id
))
.from(book)
...
// before
public List<BookPageDto> getBooks(int bookNo, int pageNo) {
queryFactory
.select(Projections.fields(BookPageDto.class,
book.name,
book.bookNo,
book.id
))
.from(book)
...
}
// after
public List<BookPageDto> getBooks(int bookNo, int pageNo) {
queryFactory
.select(Projections.fields(BookPageDto.class,
book.name,
Expressions.asNumber(bookNo).as("bookNo"),
book.id
))
.from(book)
...
}
queryFactory
.select(Projections.fields(AdBond.class,
...
adItem.customer
)
)
queryFactory
.select(Projections.fields(AdBond.class,
adItem.txDate,
...
adItem.customer.id.as("customerId")
)
)
public AdBond toEntity() {
return AbBond.builder()
.txDate(txDate)
...
.customer(new Customer(cusomerId))
.build();
}
explain select 1
from ad_offset
group by customer_no;
order by null
을 하게 되면 Filesort가 제거된다.explain select 1
from ad_offset
group by customer_no
order by null asc;
public class OrderByNull extends OrderSpecifier {
public static final OrderByNull DEFAULT = new OrderByNull();
private OrderByNull() {
super(Order.ASC, NullExpression.DEFAULT, Default);
}
}
queryFactory
.select(...)
...
.orderBy(OrderByNull.DEFAULT)
.fetch();
select *
from academy a
join (select id
from academy
order by id
limit 10000, 10) as temp
on temp.id = a.id;
List<Long> ids = queryFactory
.select(book.id)
.from(book)
.where(book.name.like(name + "%"))
.orderBy(book.id.desc())
.limit(pageSize)
.offset(pageNo * pageSize)
.fetch();
if (CollectionsUtils.isEmpty(ids)) {
return new ArrayList<>();
}
return queryFactory
.select(...)
.from(book)
.where(book.id.in(ids))
.orderBy(book.id.desc())
.fetch();
// DirtyChecking
List<Student> students = queryFactory
.selectFrom(student)
.where(student.id.loe(studentId))
.fetch();
for (Student student : students) {
students.updateName(name);
}
// Querydsl.update
queryFactory.update(student)
.where(student.id.loe(studentId))
.set(student.name, name)
.execute();
// 단일 Entity
SQLInsertClause insert = sqlQueryFactory.insert(qAcademy);
for (int j = 1; j <= 1000; j++) {
insert.populate(new Academy("address", "name", EntityMapper.DEFAULT))
.addBatch();
}
insert.execute();
// OneToMany
SQLInsertClause insert = sqlQueryFactory.insert(qAcademy);
for (int j = 1; j < 1000; j++) {
Academy academy = academyRepository.save(new Academy("address", "name"));
insert.populate(new Student("student", 1, academy), EntityMapper.DEFAULT).addBatch();
insert.populate(new Student("student", 2, academy), EntityMapper.DEFAULT).addBatch();
}
insert.execute();