Как заполнить Java (веб) приложение начальными данными, используя Spring / JPA / Hibernate - PullRequest
17 голосов
/ 11 марта 2010

Я хочу настроить мою базу данных с начальными данными программно. Я хочу заполнить свою базу данных для прогонов разработки, а не для тестов (это легко). Продукт построен на основе Spring и JPA / Hibernate.

  • Разработчик проверяет проект
  • Разработчик запускает команду / скрипт для настройки базы данных с исходными данными
  • Разработчик запускает приложение (сервер) и начинает разработку / тестирование

тогда:

  • Разработчик запускает команду / скрипт для очистки базы данных и установки новых исходных данных, поскольку структуры базы данных или начальный комплект данных были изменены

То, что я хочу, это настроить мою среду по необходимым частям, чтобы вызывать мои DAO и вставлять новые объекты в базу данных. Я не хочу создавать исходные наборы данных в сыром SQL, XML, делать дампы базы данных или что-то еще. Я хочу программно создавать объекты и сохранять их в базе данных, как в обычной логике приложения.

Один из способов сделать это - нормально запустить мое приложение и запустить специальный сервлет, который выполняет инициализацию. Но так ли это на самом деле? Я хотел бы выполнить первоначальную настройку данных как задачу Maven, и я не знаю, как это сделать, если я использую сервлетный подход.

Есть несколько похожий вопрос . Я бросил быстрый взгляд на предлагаемые DBUnit и Unitils. Но они, кажется, сильно сосредоточены на настройке сред тестирования, а это не то, что я хочу здесь. DBUnit выполняет начальную загрузку данных, но только с использованием фикстур xml / csv, а это не то, что мне нужно. Затем у Maven есть плагин SQL, но я не хочу обрабатывать сырой SQL. В Maven также есть плагин Hibernate, но, похоже, он помогает только в настройке Hibernate и создании схем таблиц (не в заполнении БД данными).

Как это сделать?

Частичное решение 2010-03-19

Предлагаемые альтернативы:

  • Использование модульных тестов для заполнения базы данных # 2423663
  • Использование ServletContextListener для получения контроля при запуске веб-контекста # 2424943 и # 2423874
  • Использование Spring ApplicationListener и стандартных и пользовательских событий Spring # 2423874

Я реализовал это с помощью SpringL ApplicationListener:

Класс:

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" />

По какой-то причине я не смог запустить ContextStartedEvent, поэтому я выбрал ContextRefreshedEvent, который также запускается при запуске (пока не сталкивался с другими ситуациями).

Как очистить базу данных? В настоящее время я просто удаляю артефакты HSQLDB, и при запуске Hibernate генерирует новую схему. Поскольку БД тогда тоже пустая.

Ответы [ 11 ]

5 голосов
/ 11 марта 2010

Вы можете написать модульный тест для заполнения базы данных, используя JPA и обычную Java. Этот тест будет вызван Maven как часть стандартного жизненного цикла сборки. В результате вы получите полностью инициализированную базу данных, используя Maven, JPA и Java в соответствии с запросом.

2 голосов
/ 25 февраля 2015

Я бы нам за это синглтон:

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.
    }

}
2 голосов
/ 11 марта 2010

Вы можете создавать объекты JPA в чистом классе Java и сохранять их. Этот класс может вызываться сервлетом, но также иметь метод main и вызываться из командной строки, maven (с плагином Exec Maven) или даже оборачиваться как плагин Maven.

Но ваш окончательный рабочий процесс неясен (хотите, чтобы init был частью запуска приложения или выполнялся во время сборки?) И требует некоторого пояснения.

2 голосов
/ 11 марта 2010

Обычный способ сделать это - использовать скрипт SQL. Затем вы запускаете определенный файл bash, который заполняет базу данных, используя ваш .sql
Если вы хотите иметь возможность программно устанавливать свою БД во время запуска WebApp, вы можете использовать Web Context Listener .
Во время инициализации вашего webContext вы можете использовать Servlet Context Listener, чтобы получить доступ к вашему DAO (Service Layer ... что угодно), создать ваши сущности и сохранить их, как вы используете, чтобы сделать в своем коде Java

p.s. в качестве ссылки Жизненный цикл сервлета

Если вы используете Spring, вам следует взглянуть на раздел Стандартные и пользовательские события Справочника. Это лучший способ реализовать «Spring Listener», который знает контекст Spring (в случае, если вам нужно получить его из служб)

1 голос
/ 06 января 2012

У меня такая же проблема. Я попытался использовать метод init для bean-компонента, но он работает на необработанном bean-компоненте без AOP и поэтому не может использовать @Transactional. То же самое относится и к @PostConstruct и другому механизму жизненного цикла бина.

Учитывая это, я переключился на ApplicationListener w / ContextRefreshedEvent; однако в этом случае @PersistenceContext не удается получить менеджер сущностей

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)

Использование пружин 2.0.8, jpa1, hibernate 3.0.5.

Я испытываю желание создать неуправляемый управляемый объект управления объектами и делать все напрямую, но боюсь, что это может помешать остальным управляемым объектам Spring и менеджеру транзакций.

1 голос
/ 11 марта 2010
  1. В вышеупомянутом ServletContextListener или в общем месте запуска поместите весь следующий код
  2. Определите ваши данные в удобном формате - XML, JSON или даже Java-сериализация.
  3. Проверить, существуют ли исходные данные (или флаг, указывающий на успешный первоначальный импорт)
  4. Если он существует, пропустите. Если он не существует, получите новый DAO (используя WebApplicationContextUtils.getRequiredWebApplicationContext().getBean(..)), выполните итерации всех предопределенных объектов и сохраните их с помощью EntityManager в базе данных.
1 голос
/ 11 марта 2010

Зависит от вашей базы данных. Лучше иметь скрипт для настройки db

0 голосов
/ 15 июня 2019

Вы можете поместить файл с именем data.sql в src / main / resources, он будет прочитан и автоматически выполнен при запуске См. этот урок .

Другие ответы у меня не сработали.

0 голосов
/ 12 февраля 2016

Я нашел интересный код в этом хранилище: https://github.com/resilient-data-systems/fast-stateless-api-authentication

Это работает довольно аккуратно в моем проекте:

@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");
    }
}
0 голосов
/ 31 января 2013

Найден Пример ServletContextListener от mkyong . Цитирую статью:

Вы хотите инициализировать пул соединений с базой данных до Интернета приложение запускается, есть ли метод main () во всей сети приложение?

Для меня это звучит как правильное место, где есть код для вставки исходных данных БД.

Я протестировал этот подход, чтобы вставить некоторые исходные данные для моего веб-приложения; это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...