El paquete org.springframework.jdbc.datasource.init
proporciona soporte para inicializar un DataSource
existente. Las herramientas de soporte de bases de datos integradas brindan una opción para crear e inicializar un
DataSource
para una aplicación. Sin embargo, a veces es posible que necesites inicializar una instancia
que se está ejecutando en un servidor.
Inicialización de base de datos usando Spring XML
Si necesita inicializar una base de datos y es posible especificar un enlace al bean DataSource
, puede
usar la etiqueta initialize-database
en el archivo spring-jdbc
espacio de nombres >:
<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>
El ejemplo anterior ejecuta los dos scripts especificados en la base de datos. El primer script crea el esquema y el
segundo completa las tablas con el conjunto de datos de control. Las ubicaciones de los scripts también pueden tener
comodines en el estilo Ant habitual utilizado para los recursos en Spring (por ejemplo, classpath*:/com/foo/**/sql/*-data.sql
).
Si utiliza una plantilla, los scripts se ejecutan en el orden léxico de su URL o nombre de archivo.
La lógica predeterminada del inicializador de la base de datos es ejecutar incondicionalmente los scripts especificados. Esto no siempre es lo que se requiere; por ejemplo, si los scripts se ejecutan en una base de datos que ya tiene datos de auditoría. La probabilidad de eliminar datos accidentalmente se reduce siguiendo el patrón común (mostrado anteriormente): primero crear tablas y luego insertar datos. El primer paso fallará si las tablas ya existen.
Sin embargo, para brindarle más control sobre la creación y eliminación de datos existentes, el espacio de nombres XML proporciona varias capacidades adicionales. La primera es una bandera para activar y desactivar la inicialización. Puede configurarlo según su entorno (por ejemplo, extraer un valor booleano de las propiedades del sistema o de un bean de entorno). En el siguiente ejemplo, el valor se obtiene de una propiedad del sistema:
<jdbc:initialize-database data-source="dataSource"
enabled="#{systemProperties.INITIALIZE_DATABASE}">
<jdbc:script location="..."/>
</jdbc:initialize-database>
- Obtenga el valor de
enabled
de la propiedad del sistemaINITIALIZE_DATABASE
.
La segunda opción para controlar lo que sucede con los datos existentes es ser más resiliente ante los fallos. Para hacer esto, puede controlar la capacidad del inicializador para ignorar ciertos errores en el SQL que ejecuta desde los scripts, como se muestra en el siguiente ejemplo:
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
<jdbc:script location="..."/>
</jdbc:initialize-database>
En el ejemplo anterior, decimos que esperamos que a veces los scripts se ejecuten en una base de datos vacía, y esos
scripts tienen algunas declaraciones DROP
que, por lo tanto, no se ejecutarán. Por lo tanto, las
consultas SQL DROP
con errores se ignorarán, pero otras fallas generarán una excepción. Esto es útil si
el dialecto SQL no admite DROP ... IF EXISTS
(o similar), pero necesita eliminar incondicionalmente
todos los datos de control antes de volver a crear. En este caso, el primer script suele ser un conjunto de
declaraciones DROP
, seguido de un conjunto de declaraciones CREATE
.
El parámetro ignore-failures
se puede establecer en NONE
(predeterminado),
DROPS
(ignora DROP
erróneos). declaraciones) o ALL
(ignorar todos los
errores).
Cada instrucción debe estar separada por un carácter ;
o una nueva línea si el carácter ;
no está presente en el script. Puedes controlar esto globalmente o mediante script, como se muestra en el siguiente
ejemplo:
<jdbc:initialize-database data-source="dataSource" separator="@@">
<jdbc:script location="classpath:com/myapp/sql/db-schema.sql" separator=";"/>
<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>
- Instalar scripts separadores en
@@
. - Establezca el separador para
db-schema.sql
en;
.
En este ejemplo, dos scripts test-data
usan @@
como delimitadores de declaraciones, y solo
db-schema.sql
usa ;
. Esta configuración establece que el delimitador predeterminado sea
@@
y anula este valor para el script db-schema
.
Si desea tener más control que usar un espacio de nombres XML, puede usar DataSourceInitializer
directamente y definirlo como un componente en su aplicación.
Inicialización de otros componentes dependientes de la base de datos
Una gran clase de aplicaciones (aquellas que no usan una base de datos antes de iniciar el contexto en Spring) pueden usar el inicializador de la base de datos sin obstáculos adicionales. Si su aplicación no es una de estas, es posible que deba leer el resto de esta sección.
El inicializador de la base de datos depende de la instancia DataSource
y ejecuta los scripts
proporcionados en la devolución de llamada de inicialización (similar al init-method
en la definición
del bean XML, un método con la anotación @PostConstruct
en un componente o el método afterPropertiesSet()
en un componente que implementa InitializingBean
). Si otros beans dependen de la misma fuente de datos
y utilizan la fuente de datos en la devolución de llamada de inicialización, puede ocurrir un problema porque los
datos aún no se han inicializado. Un ejemplo común es un caché que se inicializa sin demora y carga datos de la base
de datos cuando se inicia la aplicación.
Para solucionar este problema, hay dos formas: cambiar la estrategia de inicialización de la caché a una etapa posterior o asegurarse de que el inicializador de la base de datos se inicialice primero.
Cambiar la estrategia de inicialización de la caché puede ser fácil si la aplicación está bajo su control y no de otra manera. Algunas sugerencias sobre cómo lograr esto:
-
Haga que el caché se inicialice más tarde en el primer uso, lo que mejorará el tiempo de inicio de la aplicación.
-
Deje que su caché, o un componente separado que inicialice el caché, implemente
Lifecycle
oSmartLifecycle
. Cuando se inicia un contexto de aplicación, puede iniciarSmartLifecycle
automáticamente configurando su indicadorautoStartup
y puede iniciarLifecycle
manualmente llamando aConfigurableApplicationContext.start()
para el contexto adjunto. -
Utilice
ApplicationEvent
de Spring o un mecanismo de observador personalizado similar para activar la inicialización de la caché.ContextRefreshedEvent
siempre lo publica el contexto cuando está listo para usarse (después de que se hayan inicializado todos los beans), por lo que este suele ser un método útil (así es como funcionaSmartLifecycle
por defecto).
También es fácil asegurarse de que el inicializador de la base de datos se inicialice primero. Algunas ideas sobre cómo hacer esto:
-
Utilizará la lógica
BeanFactory
predeterminada de Spring, que consiste en que los beans se inicializan en el orden en que se registran. Esto se puede hacer fácilmente adoptando la práctica común de utilizar un conjunto de elementos<import/>
en la configuración XML que organizan los módulos de su aplicación y garantizan que la base de datos y la inicialización de la base de datos aparezcan en primer lugar. -
Separe el
DataSource
de los componentes empresariales que lo utilizan y controle el orden en el que se ejecutan colocándolos en instanciasApplicationContext
separadas (por ejemplo, el contexto principal contiene elDataSource
, y el hijo son los componentes comerciales). Esta estructura es común en las aplicaciones web Spring, pero se puede utilizar más ampliamente.
GO TO FULL VERSION