Spring Boot - İlk Verilerin Yüklenmesi


180

Uygulama başlamadan önce ilk veritabanı verilerini yüklemek için en iyi yolu merak ediyorum? Aradığım şey H2 veritabanımı verilerle dolduracak bir şey.

Örneğin, "Kullanıcı" bir etki alanı modelim var / kullanıcılara giderek kullanıcılara erişebilirim ama başlangıçta veritabanında herhangi bir kullanıcı olmayacak, bu yüzden onları oluşturmak zorundayım. Veritabanını otomatik olarak verilerle doldurmak için yine de var mı?

Şu anda konteynır tarafından başlatılan ve benim için kullanıcılar oluşturan bir Bean var.

Misal:

@Component
public class DataLoader {

    private UserRepository userRepository;

    @Autowired
    public DataLoader(UserRepository userRepository) {
        this.userRepository = userRepository;
        LoadUsers();
    }

    private void LoadUsers() {
        userRepository.save(new User("lala", "lala", "lala"));
    }
}

Ama bunu yapmanın en iyi yolu olduğundan şüpheliyim. Yoksa öyle mi?


4
Bu işe yarayacak ya da sadece veri eklemek data.sqlve / veya schema.sqlveri başlatmak için .. Tüm bunlar referans kılavuzunda (okumayı öneririm) belgelenmiştir .
M.Deinum

Size yardımcı olduysa lütfen doğru cevabı işaretleyin.
Reborn

Bunu çalıştıran var mı? Bunu bir araya getiremiyorum ve burada neyi özlediğimden emin değilim. git.io/v5SWx
srini

Yanıtlar:


295

Src / main / resources klasörünüzde bir data.sql dosyası oluşturabilirsiniz ve başlangıçta otomatik olarak yürütülür. Bu dosyaya sadece bazı ekleme ifadeleri ekleyin, örn .:

INSERT INTO users (username, firstname, lastname) VALUES
  ('lala', 'lala', 'lala'),
  ('lolo', 'lolo', 'lolo');

Benzer şekilde, şemanızı oluşturmak için de bir schema.sql dosyası (veya schema-h2.sql) oluşturabilirsiniz:

CREATE TABLE task (
  id          INTEGER PRIMARY KEY,
  description VARCHAR(64) NOT NULL,
  completed   BIT NOT NULL);

Normalde bunu yapmak zorunda olmamalısınız çünkü Spring önyükleme, hazırda bekletme modunu, bir bellek içi veritabanının varlıklarına göre şemanızı oluşturacak şekilde yapılandırır. Schema.sql dosyasını gerçekten kullanmak istiyorsanız, bunu uygulamanıza ekleyerek bu özelliği devre dışı bırakmanız gerekir.

spring.jpa.hibernate.ddl-auto=none

Daha fazla bilgi Veritabanı başlatma hakkındaki belgelerde bulunabilir .


Spring boot 2 kullanıyorsanız , veritabanı başlatma yalnızca gömülü veritabanları (H2, HSQLDB, ...) için çalışır. Diğer veritabanları için de kullanmak istiyorsanız, spring.datasource.initialization-modeözelliği değiştirmeniz gerekir :

spring.datasource.initialization-mode=always

Birden çok veritabanı satıcısı kullanıyorsanız, kullanmak istediğiniz veritabanı platformuna bağlı olarak data-h2.sql veya data-mysql.sql dosyalarınızı adlandırabilirsiniz .

Bunu yapmak için spring.datasource.platformözelliği şu şekilde yapılandırmanız gerekir :

spring.datasource.platform=h2

Temizlediğiniz için @ g00glen00b'a teşekkür ederiz: "ve başlangıçta otomatik olarak yürütülür". AddScript (ler) seçeneğini kullanarak benim fasulye yapılandırmasına data.sql dosyasını dahil gibi hataları alıyordum. Bu noktada olduğu gibi, şema henüz oluşturulmamıştır.
Benjamin Slabbert

5
@nespapu Yanlış olsa var schema.sql/ data.sqlne zaman dosyaları çalıştırılacaktır spring.datasource.initializeolan true(varsayılan olan). spring.jpa.hibernate.ddl-autoSQL dosyası kullanmak yerine varlık yapılandırmanıza göre tablolarınızı oluşturmak için kullanılabilir. Bu, bellek içi veritabanlarında varsayılan olarak etkindir. Bu yüzden cevabımda notu ekledim, eğer bir bellek içi veritabanı kullanıyorsanız ve kullanmak istiyorsanız schema.sql, devre dışı bırakmanız gerekir, spring.jpa.hibernate.ddl-autoaksi takdirde her ikisi de tablonuzu oluşturmaya çalışır.
g00glen00b

7
data-h2.sqlİlk verileriniz için dosya adını kullanmak istiyorsanız spring.datasource.platform=h2, uygulama özelliklerinizde de ayarlamanız gerekir .
Jason Evans

1
İlkbahar önyükleme uygulaması her başlatıldığında data.sql dosyası yürütülür . Bu , veritabanında zaten mevcutorg.h2.jdbc.JdbcSQLException olduğu için insert deyimleriniz varsa, bir istisnaya neden olabileceği anlamına gelir . Gömülü bir H2 veritabanı kullanıyorum, ancak sorun aynı kalıyor.
Igor

1
@ g00glen00b ne yazık ki hepsi bu kadar kolay, çünkü H2 veritabanında sorun var MERGE INTO. Bir kullanarak bu sorunu çözecek bir yol olduğunu, anladım import.sql dosyası yerine bir data.sql . Bu gerektiriyor spring.jpa.hibernate.ddl-autoiçin oluşturmak veya oluşturmak bırak . Şema dosyası (ve / veya oluşturulduğunda Sonra schema.sql yürütüldüğünde), import.sql sıra yürütülür. Yine de, init veri yaratmanın temiz bir uygulaması değil, geçici bir çözüm gibi geliyor.
Igor

82

Sadece basit test verileri eklemek istersem genellikle bir ApplicationRunner. Bu arabirimin uygulamaları uygulama başlangıcında çalıştırılır ve örneğin bazı test verilerini eklemek için otomatik kablolu bir depo kullanabilir.

Arayüz uygulamanızın doğrudan uygulamanız hazır olduktan sonra yapmak istediğiniz bir şey içerdiğini ima ettiğinden, böyle bir uygulamanın sizden biraz daha açık olacağını düşünüyorum.

Uygulamanız sth görünecektir. bunun gibi:

@Component
public class DataLoader implements ApplicationRunner {

    private UserRepository userRepository;

    @Autowired
    public DataLoader(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void run(ApplicationArguments args) {
        userRepository.save(new User("lala", "lala", "lala"));
    }
}

32

Öneri olarak şunu deneyin:

@Bean
public CommandLineRunner loadData(CustomerRepository repository) {
    return (args) -> {
        // save a couple of customers
        repository.save(new Customer("Jack", "Bauer"));
        repository.save(new Customer("Chloe", "O'Brian"));
        repository.save(new Customer("Kim", "Bauer"));
        repository.save(new Customer("David", "Palmer"));
        repository.save(new Customer("Michelle", "Dessler"));

        // fetch all customers
        log.info("Customers found with findAll():");
        log.info("-------------------------------");
        for (Customer customer : repository.findAll()) {
            log.info(customer.toString());
        }
        log.info("");

        // fetch an individual customer by ID
        Customer customer = repository.findOne(1L);
        log.info("Customer found with findOne(1L):");
        log.info("--------------------------------");
        log.info(customer.toString());
        log.info("");

        // fetch customers by last name
        log.info("Customer found with findByLastNameStartsWithIgnoreCase('Bauer'):");
        log.info("--------------------------------------------");
        for (Customer bauer : repository
                .findByLastNameStartsWithIgnoreCase("Bauer")) {
            log.info(bauer.toString());
        }
        log.info("");
    }
}

2. Seçenek: Şema ve veri komut dosyalarıyla başlatma

Önkoşullar: içinde şunu application.propertiesbelirtmelisiniz:

spring.jpa.hibernate.ddl-auto=none(aksi takdirde komut dosyaları hazırda bekletme tarafından yoksayılır ve projeyi @Entityve / veya @Tableek açıklamalı sınıfları tarar )

Ardından, MyApplicationsınıfınıza şunu yapıştırın:

@Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("org.h2.Driver");
    dataSource.setUrl("jdbc:h2:~/myDB;MV_STORE=false");
    dataSource.setUsername("sa");
    dataSource.setPassword("");

    // schema init
    Resource initSchema = new ClassPathResource("scripts/schema-h2.sql");
    Resource initData = new ClassPathResource("scripts/data-h2.sql");
    DatabasePopulator databasePopulator = new ResourceDatabasePopulator(initSchema, initData);
    DatabasePopulatorUtils.execute(databasePopulator, dataSource);

    return dataSource;
}

Nerede scriptsklasör altında bulunur resourcesklasöre (IntelliJ Fikir)

Umarım birine yardımcı olur


3
Seçenek 2, olup bitenler hakkında açık bir kanıt sağladığı için harikadır. Birden çok veri kaynağı ile özellikle Spring'in DataSourceAutoConfiguration.class işlevini devre dışı bırakmak gerekebilir, bu durumda burada sağlanan diğer tüm data.sql ve schema.sql çözümleri çalışmayı durdurur.
kaicarno

1
İlk verileri yüklemek istiyorsanız, ancak Hazırda Bekletme'nin DDL'yi oluşturmasını istiyorsanız, ancak birden çok veri kaynağınız varsa ve bunları el ile ayarladıysanız, bu durumda daha iyi bir seçenek, Spring'in DataSourceInitializer fasulyesini stackoverflow.com/a/23036217/3092830 olarak bildirmektir. Sizin için @PostConstruct sorununu alacağı için.
kaicarno

32

Çalıştırmak istediğiniz sql dosyalarını listelemek için bir spring.datasource.dataözellik ekleyebilirsiniz application.properties. Bunun gibi:

spring.datasource.data=classpath:accounts.sql, classpath:books.sql, classpath:reviews.sql

Bu dosyaların her birindeki sql insert deyimleri çalıştırılarak işleri düzenli tutmanıza olanak tanır.

Dosyaları sınıf yoluna koyarsanız, örneğin src/main/resourcesbunlar uygulanır. Veya yerine classpath:sahip file:ve dosyaya mutlak bir yol kullanmak


5
harici bir dosya istiyorsanız file:yerine koymak unutmayın classpath:.
Aleksander Lech

dosyalar (accounts.sql, ...) nerede bulunur?
dpelisek

1
@dpelisek src / main / resources çalışmalıdır. Yanıt güncellendi.
robjwilkins

14

Bunun gibi bir şey kullanabilirsiniz:

@SpringBootApplication  
public class Application {

@Autowired
private UserRepository userRepository;

public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
}

@Bean
InitializingBean sendDatabase() {
    return () -> {
        userRepository.save(new User("John"));
        userRepository.save(new User("Rambo"));
      };
   }
}

11

Spring Boot, Spring Batch kullanarak veritabanınızı başlatmak için basit bir komut dosyası kullanmanızı sağlar .

Yine de, DB sürümlerini yönetmek için biraz daha ayrıntılı bir şey kullanmak istiyorsanız, Spring Boot Flyway ile iyi bütünleşir .

Ayrıca bakınız:


6
Burada bahar partisinin aşırıya kaçması gibi görünüyor.
Nick

@Nick, OP veri miktarından bahsetmiyor. Her neyse, cevap tamamen bahar partisiyle ilgili değil.
Xtreme Biker

Bence Flyway veya Liquibase doğru yol. Nick'in yorumundan ve / src / main / resources upvotes hakkında emin değilim. Evet, ikincisi küçük projeler için işe yarar. Xtreme Biker'ın cevabı çok az çaba ile çok daha fazla işlevsellik kazandırır.
Alexandros

10

Spring Boot 2'de data.sql, Spring Boot 1.5'teki gibi benimle çalışmıyordu

import.sql

Ayrıca, import.sqlHazırda Bekletme şemayı sıfırdan oluşturursa (yani, ddl-auto özelliği oluşturma veya oluşturma-bırakma olarak ayarlanmışsa) sınıfyolunun kökünde adlı bir dosya başlangıçta yürütülür.

Anahtarları çoğaltamazsanız çok önemli bir not kullanmayın ddl-auto özelliğini kullanmayın güncelleme her güncelleme ile aynı verileri tekrar ekleyecektir

Daha fazla bilgi için bahar web sitesini ziyaret edin

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html


Bahar 2'de veritabanı başlatma yalnızca katıştırılmış veritabanları için çalışır Başka veritabanları için kullanmak istiyorsanız, spring.datasource.initialization-mode = her zaman
Edu Costa

6

İşte bunu elde etmenin yolu:

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {

    /**
     * This event is executed as late as conceivably possible to indicate that
     * the application is ready to service requests.
     */

    @Autowired
    private MovieRepositoryImpl movieRepository;

    @Override
    public void onApplicationEvent(final ApplicationReadyEvent event) {
        seedData();
    }

    private void seedData() {
        movieRepository.save(new Movie("Example"));

        // ... add more code
    }

}

Bu makalenin yazarı sayesinde:

http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/


Hizmeti kullanıyorsanız ve otomatik kablolama deposunda hizmet varsa bu çalışmaz
silentsudo

5

Basitçe import.sqliçinde bir dosya oluşturabilirsiniz src/main/resourcesve Hazırda Beklet seçeneği şema oluşturulduğunda yürütür.


4

Benzer sorunu şu şekilde çözdüm:

@Component
public class DataLoader {

    @Autowired
    private UserRepository userRepository;

    //method invoked during the startup
    @PostConstruct
    public void loadData() {
        userRepository.save(new User("user"));
    }

    //method invoked during the shutdown
    @PreDestroy
    public void removeData() {
        userRepository.deleteAll();
    }
}

1

Birisi kabul edilen cevabın ardından bile bunu yapmak için uğraşıyorsa , benim için sadece src/test/resources/application.ymlH2 datasourceayrıntılarını ekleyerek çalışıyorum :

spring:
  datasource:
    platform: h2
    url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password:

1

kayıt ve olay dinleyicisi aşağıdaki gibi ulaşmak için:

@EventListener
public void seed(ContextRefreshedEvent event) {
    userRepository.save(new User("lala", "lala", "lala"));
}

ContextRefreshEvent tetiklendiğinde, modeller ve depolar da dahil olmak üzere uygulamadaki tüm otomatik kablolu fasülyelere erişiriz.


1

Yalnızca birkaç satır eklemek istiyorsanız ve JPA Kurulumunuz varsa. Aşağıda kullanabilirsiniz

    @SpringBootApplication
        @Slf4j
        public class HospitalManagementApplication {

            public static void main(String[] args) {
                SpringApplication.run(HospitalManagementApplication.class, args);
            }            

            @Bean
            ApplicationRunner init(PatientRepository repository) {
                return (ApplicationArguments args) ->  dataSetup(repository);
            } 

            public void dataSetup(PatientRepository repository){
            //inserts

     }

1
Uzun zamandır kullanıyordum, hatırlayamadım. Budur. Teşekkürler.
Freelancer

0

Bu da işe yarayacaktır.

    @Bean
    CommandLineRunner init (StudentRepo studentRepo){
        return args -> {
            // Adding two students objects
            List<String> names = Arrays.asList("udara", "sampath");
            names.forEach(name -> studentRepo.save(new Student(name)));
        };
    }

0

MainApp içine (mathok ile) @ mathias-dpunkt çözümü koymak en kompakt (dinamik veri için @AllArgsConstructor):

@SpringBootApplication
@AllArgsConstructor
public class RestaurantVotingApplication implements ApplicationRunner {
  private final VoteRepository voteRepository;
  private final UserRepository userRepository;

  public static void main(String[] args) {
    SpringApplication.run(RestaurantVotingApplication.class, args);
  }

  @Override
  public void run(ApplicationArguments args) {
    voteRepository.save(new Vote(userRepository.getOne(1), LocalDate.now(), LocalTime.now()));
  }
}

0

Neredeyse bitti!

@Component
public class DataLoader implements CommandLineRunner {

    private UserRepository userRepository;

    public DataLoader(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public void run(String... args) throws Exception {
         LoadUsers()
    }

    private void LoadUsers() {
        userRepository.save(new User("lala", "lala", "lala"));
    }
}

0

Aşağıdaki kodu kullanabilirsiniz. Aşağıdaki kodda, yay önyükleme uygulamasının başlatılması sırasında bir veritabanı ekleme işlemi gerçekleşir.

@SpringBootApplication
public class Application implements CommandLineRunner {
    
    @Autowired
    private IService<Car> service;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        for(int i=1; i<=1000; i++) {
            Car car = new Car();
            car.setName("Car Name "+i);
            book.setPrice(50 + i);
            service.saveOrUpdate(car);
        }
    }

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.