DBMS 포트
DBMS 포트는 직접 쓴 SQL(보고서, 일괄 문장, 다른 데이터소스)을 리포지터리나 엔티티 없이 생성된 인터페이스 뒤에서 실행합니다.
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 | 값 하나 |
decimal | inqueryFirst | 숫자 하나, java.math.BigDecimal (합계·금액) |
값 하나를 돌려주는 메서드는 결과 행의 첫 열을 그 타입으로 바꿔 돌려줍니다. 열 값이 NULL 이거나(SUM 이 빈 집합) 행이
없으면 null 입니다. return: decimal 과 List<decimal> 은 java.math.BigDecimal 로 생성됩니다. 파라미터가 값 하나
(long, string, 날짜, enum)이면 SQL 의 :이름 에 파라미터 이름으로 묶이고, DTO 하나이면 그 getter 로 묶입니다. 이름으로
묶으려면 컴파일된 클래스에 파라미터 이름이 남아 있어야 합니다(-parameters) - Spring Boot 의 Gradle·Maven 플러그인이 켭니다.
3.0.261023 전(3.0.261022-rc1 까지)에는 이것들이 동작하지 않았습니다: 숫자는 Failed to map tuple to DTO 로 실패하고,
string 은 빈 문자열로 돌아오고, long 파라미터 하나는 묶이지 않았고, return: decimal 은 컴파일되지 않는 타입 decimal 로
생성되었습니다.
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)에 놓이고, 어댑터는 런타임 프록시입니다. 3.0.261023 부터
런타임의 자동 구성이 등록합니다(3.0.261022-rc1 까지는 @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 에 있습니다.