Initializing a `DataSource`

Dev.Hammy·2024년 3월 6일

org.springframework.jdbc.datasource.init 패키지는 기존 DataSource 초기화를 지원합니다. 내장된 데이터베이스 지원은 애플리케이션에 대한 DataSource를 생성하고 초기화하기 위한 하나의 옵션을 제공합니다. 그러나 때로는 서버 어딘가에서 실행되는 인스턴스를 초기화해야 할 수도 있습니다.

Initializing Database by Using Spring XML

데이터베이스를 초기화하고 DataSource 빈에 대한 참조를 제공할 수 있는 경우 spring-jdbc 네임스페이스에서 initialize-database 태그를 사용할 수 있습니다.

<jdbc:initialize-database data-source="dataSource">
	<jdbc:script location="classpath:com/foo/sql/db-schema.sql"/>
	<jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/>
</jdbc:initialize-database>

앞의 예에서는 데이터베이스에 대해 지정된 두 스크립트를 실행합니다. 첫 번째 스크립트는 스키마를 생성하고, 두 번째 스크립트는 테스트 데이터 세트로 테이블을 채웁니다. 스크립트 위치는 Spring의 리소스에 사용되는 일반적인 Ant 스타일의 와일드카드가 있는 패턴일 수도 있습니다(예: classpath*:/com/foo/**/sql/*-data.sql). 패턴을 사용하는 경우 스크립트는 URL 또는 파일 이름의 어휘 순서로 실행됩니다.

데이터베이스 이니셜라이저의 기본 동작은 제공된 스크립트를 무조건 실행하는 것입니다. 이는 항상 원하는 결과가 아닐 수도 있습니다. 예를 들어 이미 테스트 데이터가 있는 데이터베이스에 대해 스크립트를 실행하는 경우입니다. 테이블을 먼저 생성한 다음 데이터를 삽입하는 일반적인 패턴(앞서 설명)을 따르면 실수로 데이터를 삭제할 가능성이 줄어듭니다. 테이블이 이미 있으면 첫 번째 단계가 실패합니다.

그러나 기존 데이터의 생성 및 삭제를 더 효과적으로 제어하기 위해 XML 네임스페이스는 몇 가지 추가 옵션을 제공합니다. 첫 번째는 초기화를 켜고 끄는 플래그입니다. 환경에 따라 이를 설정할 수 있습니다(예: 시스템 속성(properties) 또는 환경 Bean에서 부울 값 가져오기). 다음 예에서는 시스템 속성에서 값을 가져옵니다.

<jdbc:initialize-database data-source="dataSource"
	enabled="#{systemProperties.INITIALIZE_DATABASE}"> <!-- (1) -->
	<jdbc:script location="..."/>
</jdbc:initialize-database>

(1)INITIALIZE_DATABASE라는 시스템 속성에서 활성화된 값을 가져옵니다.

기존 데이터에 발생하는 상황을 제어하는 두 번째 옵션은 오류에 대한 내성을 높이는 것입니다. 이를 위해 다음 예제와 같이 스크립트에서 실행되는 SQL의 특정 오류를 무시하도록 초기화 프로그램의 기능을 제어할 수 있습니다.

<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
	<jdbc:script location="..."/>
</jdbc:initialize-database>

앞의 예에서는 때때로 스크립트가 빈 데이터베이스에 대해 실행되고 스크립트에 일부 DROP 문이 있어서 실패할 것으로 예상한다는 의미입니다. 따라서 실패한 SQL DROP 문은 무시되지만 다른 실패로 인해 예외가 발생합니다. 이는 SQL 언어가 DROP IF EXISTS(또는 유사한)을 지원하지 않는 경우, 하지만 다시 만들기 전에 모든 테스트 데이터를 무조건 제거하려는 경우에 유용합니다. 이 경우 첫 번째 스크립트는 일반적으로 DROP 문 집합이고 그 뒤에 CREATE 문 집합이 옵니다.

ignore-failures 옵션은 NONE(기본값), DROPS(실패한 삭제 무시) 또는 ALL(모든 실패 무시)로 설정할 수 있습니다.

각 명령문은 ;로 구분되어야 합니다. 또는 ; 문자가 스크립트에 전혀 존재하지 않는 경우 새로운 행으로 분리합니다. 다음 예제와 같이 전역적으로 제어하거나 스크립트별로 제어할 수 있습니다.

<jdbc:initialize-database data-source="dataSource" separator="@@"> <!-- (1) --> 
	<jdbc:script location="classpath:com/myapp/sql/db-schema.sql" separator=";"/> <!-- (2) -->
	<jdbc:script location="classpath:com/myapp/sql/db-test-data-1.sql"/>
	<jdbc:script location="classpath:com/myapp/sql/db-test-data-2.sql"/>
</jdbc:initialize-database>

(1) 구분 기호 스크립트를 @@으로 설정합니다.
(2) db-schema.sql의 구분 기호를 ;로 설정합니다.

이 예에서 두 개의 test-data 스크립트는 @@를 statement 구분 기호로 사용하고 db-schema.sql;을 사용합니다. 이 구성은 기본 구분 기호가 @@임을 지정하고 db-schema 스크립트의 해당 기본값을 재정의합니다.

XML 네임스페이스에서 얻는 것보다 더 많은 제어가 필요한 경우 DataSourceInitializer를 직접 사용하고 이를 애플리케이션의 구성 요소로 정의할 수 있습니다.

Initialization of Other Components that Depend on the Database

대규모 애플리케이션(Spring 컨텍스트가 시작될 때까지 데이터베이스를 사용하지 않는 애플리케이션)은 더 이상 복잡하지 않게 데이터베이스 초기화 프로그램을 사용할 수 있습니다. 귀하의 애플리케이션이 이에 속하지 않는 경우 이 섹션의 나머지 부분을 읽어야 할 수도 있습니다.

데이터베이스 이니셜라이저는 DataSource 인스턴스에 의존하며 초기화 콜백에 제공된 스크립트를 실행합니다(XML Bean 정의의 init-method, 구성 요소의 @PostConstruct 메서드 또는 InitializingBean을 구현하는 구성 요소의 afterPropertiesSet() 메서드와 유사). 다른 Bean이 동일한 데이터 소스에 의존하고 초기화 콜백에서 해당 데이터 소스를 사용하는 경우 데이터가 아직 초기화되지 않았기 때문에 문제가 발생할 수 있습니다. 이에 대한 일반적인 예는 애플리케이션 시작 시 데이터베이스에서 데이터를 즉시(eagerly) 초기화하고 로드하는 캐시입니다.

이 문제를 해결하려면 캐시 초기화 전략을 이후 단계로 변경하거나 데이터베이스 초기화 프로그램이 먼저 초기화되도록 하는 두 가지 옵션이 있습니다.

애플리케이션을 제어할 수 있으면 캐시 초기화 전략을 변경하는 것이 쉬울 수 있지만 그렇지 않은 경우에는 그렇지 않습니다. 이를 구현하는 방법에 대한 몇 가지 제안 사항은 다음과 같습니다.

  • 처음 사용할 때 캐시가 지연(lazily) 초기화되도록 하여 애플리케이션 시작 시간을 향상시킵니다.

  • 캐시 또는 캐시를 초기화하는 별도의 구성 요소가 Lifecycle 또는 SmartLifecycle을 구현하도록 하세요. 애플리케이션 컨텍스트가 시작되면 autoStartup 플래그를 설정하여 SmartLifecycle을 자동으로 시작할 수 있고, 포함(enclosing) 컨텍스트에서 ConfigurableApplicationContext.start()를 호출하여 Lifecycle을 수동으로 시작할 수 있습니다.

  • Spring ApplicationEvent 또는 유사한 사용자 정의 관찰자(observer) 메커니즘을 사용하여 캐시 초기화를 트리거합니다. ContextRefreshedEvent는 사용할 준비가 되면(모든 Bean이 초기화된 후) 컨텍스트에 의해 항상 게시(published)되므로 유용한 후크(hook)인 경우가 많습니다(이것이 SmartLifecycle이 기본적으로 작동하는 방식입니다).

데이터베이스 이니셜라이저가 먼저 초기화되는지 확인하는 것도 쉬울 수 있습니다. 이를 구현하는 방법에 대한 몇 가지 제안 사항은 다음과 같습니다.

  • Bean이 등록 순서대로 초기화되는 Spring BeanFactory의 기본 동작을 사용합니다. 애플리케이션 모듈을 정렬하고 데이터베이스 및 데이터베이스 초기화가 먼저 나열되도록 하는 XML 구성의 <import/> 요소 집합의 일반적인 관행을 채택하면 쉽게 정렬할 수 있습니다.

  • DataSource와 이를 사용하는 비즈니스 구성 요소를 분리하고 별도의 ApplicationContext 인스턴스에 배치하여 시작 순서를 제어합니다(예를 들어 상위 컨텍스트에는 DataSource가 포함되고 하위 컨텍스트에는 비즈니스 구성 요소가 포함됩니다). 이 구조는 Spring 웹 애플리케이션에서 일반적이지만 더 일반적으로 적용될 수 있습니다.

0개의 댓글