DBMS 포트
DBMS 포트는 직접 쓴 SQL(보고서, 일괄 문장, 다른 데이터소스)을 리포지터리나 엔티티 없이 생성된 인터페이스 뒤에서 실행합니다.
model/port.yml
port:
OrderDbService:
meta: dbms @datasource("order")
methods:
findOrders:
params:
input: OrderSearchDTO
return: List<OrderDTO>
query: |
SELECT * FROM orders WHERE status = :status
| 옵션 | 기본값 | 뜻 |
|---|---|---|
@datasource("name") | 기본 데이터소스 | 쓸 EntityManagerFactory |
nativeQuery | true | 네이티브 SQL(true) 또는 JPQL(false) |
pageable | false | 페이징 |
ref | - | 다른 메서드의 SQL 참조 |
반환 타입
| 반환 | 실행 | 용도 |
|---|---|---|
List<DTO> | inqueryList | 전체 결과 |
Page<DTO> | inqueryPage | 페이지 (pageable 필요) |
DTO | inqueryFirst | 한 건 |
int + 이름에 update / delete / insert | executeUpdate | DML - 영향 행 수 |
int + 그런 이름 + list<DTO> 파라미터 | executeBatchUpdate | 요소마다 한 트랜잭션 안에서 반복 - 영향 행 수 합계 |
int(다른 이름), long, double, float, string, boolean | inqueryFirst | 값 하나 |
updateStatus:
params:
id: string
newStatus: string
return: int
query: |
UPDATE orders SET status = :newStatus WHERE id = :id
insertOrderBatch:
params:
items: list<OrderInputDTO> # 요소마다 한 번 실행
return: int
query: |
INSERT INTO orders (order_no, product_code, quantity, price)
VALUES (:orderNo, :productCode, :quantity, :price)
빈 목록은 아무것도 실행하지 않고 0 을 돌려줍니다. 단순 값 목록(list<long>)은 배치가 아니라 IN (:ids) 바인딩입니다.
동적 SQL
AND status = :status /* if:status */ -- status 가 null 이거나 비면 빠짐
/* if:input.searchCriteria != null */
AND criteria = :searchCriteria
/* if-end */
AND min_age >= :minAge /* if:input.getMinAge() > 0 */
조건은 JEXL 식이고, input 이 입력 객체입니다.
${name} 은 SQL 문자열에 그대로 치환되고(서버가 정하는 테이블·컬럼 이름), :name 은 바인딩되는 파라미터입니다.
사용자 입력을 ${...} 로 넘기지 마세요 - SQL 인젝션에 열립니다.
헥사고날 프로젝트에서
인터페이스는 namespace.port(application.port.out)에 놓이고, 어댑터는 @EnableElastiCore 가 등록하는 런타임
프록시입니다(포트). DDD 예제의 보고서 포트 - 애그리거트가 답하지 않는 읽기 모델:
@DbmsService(id="shop.ShopReportService", sqlSource="blueprint/shop/port/report_port.yml")
public interface ShopReportService {
List<CustomerRevenueDTO> revenueByCustomer(RevenueSearchInput input);
}
sortCode, SQL 파일 핫리로드, 다중 데이터소스, 결과 매핑은 blueprint/elasticore-dsl-port-guide.md 에 있습니다.