Spring JPA + Azure Cosmos DB 연결 (라이브러리 변경관련 트러블슈팅)
가장 많이 사용하고 있는 Spring Boot + JPA 로 Azure Cosmos DB를 연결하는 작업을 진행해보았다.
1. maven pom.xml에 아래와 같이 추가하고.
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-documentdb-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
2. JPA에서 제공하는 CRUD Repository를 이용해서 다음과 같이 작업했다.
public interface DeviceTelemetryRepository extends DocumentDbRepository<DeviceTelemetry, String>{
List<DeviceTelemetry> findAll();
@Query(value="SELECT * FROM DeviceTelemetry where deviceId= ?1 and date >= ?2 and date <= ?3", nativeQuery = true)
List<DeviceTelemetry> findDeviceTelemetryByDeviceIdAndDateGreaterThanAndDateLessThan(@Param("deviceId") int deviceId,
@Param("from") long from,
@Param("to") long to );
}
3. Entity클래스의 경우 테이블에 따라서 잦은 변경이 일어나기 때문에 Controller, Service Layer에서는 DTO클래스를 별도 로 사용하는 것을 권장한다. (디자인 패턴 참고)
@Service
public class DeviceTelemetryService {
@Autowired
private DeviceTelemetryRepository deviceTelemetryRepository;
@Autowired
private ModelMapper modelMapper;
public List<DeviceTelemetryDto> getDeviceTelemetry(int deviceId, long from, long to){
return deviceTelemetryRepository.findDeviceTelemetryByDeviceIdAndDateBetween(deviceId, from, to).stream()
.map(deviceTelemetry -> modelMapper.map(deviceTelemetry, DeviceTelemetryDto.class))
.collect(Collectors.toList());
}
}
4. Controller 까지 완성하여. 테스트하였는데 아래와 같은 오류가 발생한다.
@RequestMapping(path="/api/")
public class DeviceTelemetryController {
@Autowired
private DeviceTelemetryService deviceTelemetryService;
@RequestMapping(value="/{serviceId}/{deviceId}/telemetry", method= RequestMethod.GET)
public @ResponseBody
List<DeviceTelemetryDto> getAllDeviceTelemetry(@PathVariable("deviceId") int deviceId,
@RequestParam("from") long from,
@RequestParam("to") long to) {
return deviceTelemetryService.getDeviceTelemetry(deviceId,from,to);
}
}
java.lang.IllegalArgumentException: unsupported keyword: GREATER_THAN (1): [IsGreaterThan, GreaterThan]
at com.microsoft.azure.spring.data.documentdb.repository.query.DocumentDbQueryCreator.from(DocumentDbQueryCreator.java:82) ~[spring-data-cosmosdb-2.0.3.jar:na]
at com.microsoft.azure.spring.data.documentdb.repository.query.DocumentDbQueryCreator.and(DocumentDbQueryCreator.java:56) ~[spring-data-cosmosdb-2.0.3.jar:na]
at com.microsoft.azure.spring.data.documentdb.repository.query.DocumentDbQueryCreator.and(DocumentDbQueryCreator.java:25) ~[spring-data-cosmosdb-2.0.3.jar:na]
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createCriteria(AbstractQueryCreator.java:122) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:95) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:81) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
at com.microsoft.azure.spring.data.documentdb.repository.query.PartTreeDocumentDbQuery.createQuery(PartTreeDocumentDbQuery.java:38) ~[spring-data-cosmosdb-2.0.3.jar:na]
at com.microsoft.azure.spring.data.documentdb.repository.query.AbstractDocumentDbQuery.execute(AbstractDocumentDbQuery.java:25) ~[spring-data-cosmosdb-2.0.3.jar:na]
5. Azure Cosmos DB에 문의하니 다음과 같은 답변을 받았다.
spring-data-cosmosdb 2.0.6을 사용해야 하는데 아무리 찾아도 azure-documentdb-spring-boot-starter에 포함된 최신버전은 2.0.4가 최신버전이다!
다시 문의를 했다. 수동으로 업데이트해야하는가?
결론은 "azure-documentdb는 구 네이빙 버전입니다. 신버전을 사용하세요."
Thanks for filing issue, according to your stack trace, seems you are using version 2.0.3
, if you are using Spring Boot 2.0.x, try upgrading to 2.0.6
.
You can use the azure-cosmosdb-spring-boot-starter
(not azure-documentdb-spring-boot-starter) version 2.0.13, which uses spring-data-cosmosdb 2.0.6. Between
should have been supported in 2.0.6, check this issue. Also you can reference the integration tests in this repo for the usage.
6. pom.xml에서 azure-cosmosdb-spring-boot-starter 최신버전으로 변경하였다.
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-cosmosdb-spring-boot-starter</artifactId>
<version>2.0.13</version>
</dependency>
7. 하지만 Spring JPA의 naming rule에 같은컬럼을 중복해서 사용하면 에러가 발생한다.
BETWEEN 쿼리로 변경!
(GREATER_THAN, BETWEEN등은 위에서 언급한 2.0.6 버전에서 정상지원한다.)
8. Repository 소스 변경(@Query는 없어도 쿼리를 자동으로 생성하여 동작한다)
public interface DeviceTelemetryRepository extends DocumentDbRepository<DeviceTelemetry, String> {
List<DeviceTelemetry> findAll();
// @Query(value="SELECT * FROM DeviceTelemetry where deviceId= ?1 and date >= ?2 and date <= ?3", nativeQuery = true)
List<DeviceTelemetry> findDeviceTelemetryByDeviceIdAndDateBetween(@Param("deviceId") int deviceId,
@Param("from") long from,
@Param("to") long to );
}
9. Azure Cosmos DB에서 정상적으로 데이터를 조회하는 것을 확인할 수 있다.
[
{ "id": "3ebd07c0-0740-466f-acb4-1e04a58cdf1a", "serviceId": 1, "deviceId": 1, "contents": "{\"temperature\":34.797642257199705,\"humidity\":79.18982439419167,\"illuminance\":100}", "date": 1552376519931 }, { "id": "9424f15a-e452-4dcc-8ff6-bc3707b7ec3a", "serviceId": 1, "deviceId": 1, "contents": "{\"temperature\":25.964463142640522,\"humidity\":73.64654000868197,\"illuminance\":100}", "date": 1552376579937 }, { "id": "c72aed1b-b4d0-4338-a21f-ae8b7e5b4eba", "serviceId": 1, "deviceId": 1, "contents": "{\"temperature\":28.32913263660401,\"humidity\":73.40374660917695,\"illuminance\":100}", "date": 1552376639938 }, { "id": "c1571a80-7eb6-49dc-be9f-32457e41f69a", "serviceId": 1, "deviceId": 1, "contents": "{\"temperature\":30.035071643495087,\"humidity\":70.52682127516005,\"illuminance\":100}", "date": 1552376699940 } ]
참고사이트)
1. 위 내용 관련하여 MS Github에서 주고 받은 내용들
https://github.com/Microsoft/spring-data-cosmosdb/issues/347
2. 현재 google 에서 조회하면 가장 상단에 Azure SDK for Java Stable 나오는 페이지