mvc example aprender and java hibernate spring web-applications jpa

java - example - spring hibernate maven



Cómo llenar una aplicación Java(web) con datos iniciales usando Spring/JPA/Hibernate (10)

Depende de su db. Es mejor tener script para configurar DB

Quiero configurar mi base de datos con los datos iniciales mediante programación. Quiero llenar mi base de datos para ejecuciones de desarrollo, no para pruebas de ejecución (es fácil). El producto está construido sobre Spring y JPA / Hibernate.

  • El desarrollador revisa el proyecto
  • Desarrollador ejecuta comando / script para configurar la base de datos con datos iniciales
  • El desarrollador inicia la aplicación (servidor) y comienza a desarrollar / probar

entonces:

  • El desarrollador ejecuta el comando / script para vaciar la base de datos y configurarla con nuevos datos iniciales porque las estructuras de la base de datos o el paquete de datos inicial se cambiaron

Lo que quiero es configurar mi entorno mediante las partes necesarias para llamar a mis DAO e insertar nuevos objetos en la base de datos. No quiero crear conjuntos de datos iniciales en SQL crudo, XML, tomar volcados de bases de datos o lo que sea. Quiero crear objetos mediante programación y persistirlos en la base de datos como lo haría en la lógica de la aplicación normal.

Una forma de lograr esto sería iniciar mi aplicación normalmente y ejecutar un servlet especial que realice la inicialización. ¿Pero es realmente el camino a seguir? Me encantaría ejecutar la configuración de datos inicial como tarea de Maven y no sé cómo hacerlo si tomo el enfoque de servlet.

Hay una pregunta algo similar . Eché un vistazo rápido a los DBUnit y Unitils sugeridos. Pero parecen estar muy centrados en la configuración de entornos de prueba, que no es lo que quiero aquí. DBUnit muestra la población de datos inicial, pero solo usa los accesorios xml / csv, que no es lo que busco aquí. Entonces, Maven tiene un plugin de SQL, pero no quiero manejar el SQL en bruto. Maven también tiene el complemento Hibernate, pero parece ayudar solo en la configuración de Hibernate y la creación de esquemas de tablas (no en llenar db con datos).

¿Como hacer esto?

Solución parcial 2010-03-19

Las alternativas sugeridas son:

  • Usando pruebas unitarias para poblar la base de datos # 2423663
  • Usar ServletContextListener para obtener control sobre el inicio del contexto web # 2424943 y # 2423874
  • Uso de Spring ApplicationListener y Spring''s Standard and Custom Events # 2423874

Implementé esto usando Spring ApplicationListener:

Clase:

public class ApplicationContextListener implements ApplicationListener { public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { ...check if database is already populated, if not, populate it... } } }

applicationContext.xml:

<bean id="applicationContextListener" class="my.namespaces.ApplicationContextListener" />

Por algún motivo, no pude lanzar ContextStartedEvent, así que elegí ContextRefreshedEvent, que se inicia también en el inicio (aún no se ha topado con otras situaciones).

¿Cómo descargo la base de datos? Actualmente, simplemente elimino los artefactos HSQLDB y Hibernate genera un nuevo esquema al inicio. Como el DB también está vacío.


La forma habitual de hacerlo es utilizar un script SQL. A continuación, ejecuta un archivo bash específico que llena el archivo db con su .sql
Si desea configurar su base de datos de forma programada durante el inicio de aplicación web, puede utilizar un escucha de contexto web .
Durante la inicialización de su webContext puede usar un Listener de Contexto de Servlet para obtener acceso a su DAO (Capa de Servicio ... lo que sea) crear sus entidades y persistirlas como lo hace en su código java

ps como referencia Servlet Life Cycle

Si usa Spring, debería echar un vistazo a la sección de Eventos Estándar y Personalizados de la Referencia. Esa es una mejor manera de implementar un ''Oyente de primavera'' que conozca el contexto de Spring (en caso de que necesite recuperar su formulario de Servicios)


No estoy seguro de si puede evitar el uso de algún SQL. Esto dependería si tus desarrolladores están mirando con una base de datos vacía sin un esquema definido o si las tablas están ahí pero están vacías.

Si comienza con tablas vacías, entonces podría usar un enfoque Java para generar los datos. No estoy tan familiarizado con Maven pero supongo que puedes crear alguna tarea que use tus clases DAO para generar los datos. Incluso podría escribirlo usando un lenguaje de scripts basado en JVM como Groovy que podría usar sus clases DAO directamente. Tendría una tarea similar que borraría los datos de las tablas. Entonces sus desarrolladores simplemente ejecutarían estas tareas en la línea de comando o a través de su IDE como un paso manual después de finalizar la compra.

Si tiene una nueva instancia de base de datos, creo que necesitará ejecutar algún SQL solo para crear el esquema. Técnicamente podrías hacerlo con la ejecución de llamadas SQL con hibernación, pero eso realmente no parece valer la pena.


Puede crear entidades JPA en una clase Java pura y persistirlas. Esta clase podría ser invocada por un servlet pero también tener un método main e invocarse en la línea de comando, por maven (con el complemento Exec Maven) o incluso envuelto como un plugin Maven.

Pero su flujo de trabajo final no está claro (¿quiere que init sea parte del inicio de la aplicación o finalice durante la compilación?) Y requiere alguna aclaración.


Puede escribir una prueba unitaria para llenar la base de datos, usando JPA y Java simple. Maven llamará esta prueba como parte del ciclo de vida de construcción estándar. Como resultado, obtendría una base de datos completamente inicializada, utilizando Maven, JPA y Java según lo solicitado.


  1. En el ServletContextListener mencionado anteriormente o en un lugar de inicio común ponga todo el código siguiente
  2. Defina sus datos en un formato agradable: XML, JSON o incluso serialización java.
  3. Compruebe si los datos iniciales existen (o un indicador que indica una importación inicial exitosa)
  4. Si existe, omita. Si no existe, obtenga un nuevo DAO (utilizando WebApplicationContextUtils.getRequiredWebApplicationContext().getBean(..) ), itere todos los objetos predefinidos y persistirlos a través del EntityManager en la base de datos.

Estoy teniendo el mismo problema. He intentado usar un método init en el bean, pero eso se ejecuta en el bean crudo sin AOP y por lo tanto no puede usar @Transactional. Lo mismo parece ir para @PostConstruct y el otro mecanismo de ciclo de vida de bean.

Dado eso, cambié a ApplicationListener con ContextRefreshedEvent; sin embargo, en este caso, @PersistenceContext no puede obtener un administrador de entidades

javax.persistence.PersistenceException: org.hibernate.SessionException: Session is closed! at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:630) at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:108)

Usando spring 2.0.8, jpa1, hibernate 3.0.5.

Tengo la tentación de crear una entidad gestionada de gestión no primaveral y hacer todo directamente, pero tengo miedo de que interfiera con el resto de la entidad gestionada de Spring y el administrador de transacciones.


Encontré este ejemplo de ServletContextListener por mkyong . Citando el artículo:

¿Desea inicializar el grupo de conexiones de la base de datos antes de que se inicie la aplicación web, existe un método "principal ()" en toda la aplicación web?

Esto me suena como el lugar correcto donde tener código para insertar datos iniciales de DB.

Probé este enfoque para insertar algunos datos iniciales para mi aplicación web; funciona.


Yo sería un frijol Singleton para eso:

import javax.annotation.PostConstruct; import javax.ejb.Startup; import javax.ejb.Singleton; @Singleton @Startup public class InitData { @PostConstruct public void load() { // Load your data here. } }


Encontré un código interesante en este repositorio: https://github.com/resilient-data-systems/fast-stateless-api-authentication

Esto funciona bastante bien en mi proyecto:

@Component @DependsOn({ "dataSource" }) public class SampleDataPopulator { private final static Logger log = LoggerFactory.getLogger(SampleDataPopulator.class); @Inject MyRepository myRepository @PostConstruct public void populateSampleData() { MyItem item = new ResourceDatabasePopulator(); myRepository.save(item); log.info("Populated DB with sample data"); } }