स्प्रिंग बूट - आरंभिक डेटा लोड हो रहा है


180

मैं सोच रहा हूं कि आवेदन शुरू होने से पहले प्रारंभिक डेटाबेस डेटा को लोड करने का सबसे अच्छा तरीका क्या है? मैं जिस चीज की तलाश कर रहा हूं वह कुछ है जो मेरे एच 2 डेटाबेस को डेटा से भर देगी।

उदाहरण के लिए, मेरे पास एक डोमेन मॉडल "उपयोगकर्ता" है मैं उपयोगकर्ताओं को / उपयोगकर्ताओं पर जाकर एक्सेस कर सकता हूं लेकिन शुरू में डेटाबेस में कोई उपयोगकर्ता नहीं होगा इसलिए मुझे उन्हें बनाना होगा। वैसे भी डेटाबेस को डेटा के साथ स्वचालित रूप से भरना है?

फिलहाल मेरे पास एक बीन है जो कंटेनर द्वारा त्वरित हो जाता है और मेरे लिए उपयोगकर्ता बनाता है।

उदाहरण:

@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"));
    }
}

लेकिन मुझे बहुत संदेह है कि यह करने का सबसे अच्छा तरीका है। या यह है?


4
यह काम करेगा, या बस जोड़ data.sqlऔर / या schema.sqlinit डेटा .. यह सब संदर्भ गाइड में प्रलेखित है (जो मैं पढ़ने का सुझाव देता हूं)।
एम। दीनुम

अगर आपने मदद की तो कृपया सही उत्तर दें।
पुनर्जन्म

क्या किसी को यह काम करने के लिए मिला है? मैं अभी भी इसे एक साथ रखने में असमर्थ हूं और यह सुनिश्चित नहीं कर पा रहा हूं कि मैं यहां क्या कर रहा हूं। git.io/v5SWx
srini

जवाबों:


295

आप बस अपने src / main / resource फोल्डर में एक data.sql फ़ाइल बना सकते हैं और यह स्वतः ही स्टार्टअप पर निष्पादित हो जाएगा। इस फ़ाइल में आप कुछ सम्मिलित कथन जोड़ते हैं, उदा .:

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

इसी तरह, आप एक स्कीमा बनाने के लिए एक स्कीमा। एसक्यूएल फ़ाइल (या स्कीमा-एच 2. एसक्यूएल) बना सकते हैं:

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

हालाँकि, आमतौर पर आपको ऐसा नहीं करना चाहिए क्योंकि स्प्रिंग बूट पहले से ही मेमोरी डेटाबेस में आपकी संस्थाओं के आधार पर आपके स्कीमा बनाने के लिए हाइबरनेट को कॉन्फ़िगर करता है। यदि आप वास्तव में schema.sql का उपयोग करना चाहते हैं, तो आपको इस सुविधा को अपने Application.properties में जोड़कर अक्षम करना होगा:

spring.jpa.hibernate.ddl-auto=none

डेटाबेस आरंभीकरण के बारे में प्रलेखन में अधिक जानकारी प्राप्त की जा सकती है


यदि आप स्प्रिंग बूट 2 का उपयोग कर रहे हैं , तो डेटाबेस इनिशियलाइज़ेशन केवल एम्बेडेड डेटाबेस (H2, HSQLDB, ...) के लिए काम करता है। यदि आप इसे अन्य डेटाबेस के लिए भी उपयोग करना चाहते हैं, तो आपको spring.datasource.initialization-modeसंपत्ति बदलने की आवश्यकता है :

spring.datasource.initialization-mode=always

आप एक से अधिक डेटाबेस विक्रेताओं का उपयोग कर रहे हैं, तो आप अपनी फ़ाइल के नाम कर सकते हैं डेटा-h2.sql या डेटा-mysql.sql आप उपयोग करना चाहते हैं जो डेटाबेस मंच पर निर्भर करता है।

उस काम को करने के लिए, आपको spring.datasource.platformसंपत्ति को कॉन्फ़िगर करना होगा :

spring.datasource.platform=h2

@ G00glen00b को साफ़ करने के लिए धन्यवाद: "और यह स्वतः ही स्टार्टअप पर क्रियान्वित हो जाएगा"। मुझे त्रुटि मिल रही थी क्योंकि मैंने AddScript (s) विकल्प का उपयोग करके अपने बीन के कॉन्फ़िगरेशन में data.sql फ़ाइल शामिल की थी। इस बिंदु पर स्कीमा अभी तक नहीं बनाया गया था।
बेंजामिन स्लबर्ट

5
@nespapu आपके पास गलत है, हालांकि, schema.sql/ data.sqlजब निष्पादित किया spring.datasource.initializeजाता है , तो फ़ाइलों को निष्पादित किया जाएगा true(जो कि डिफ़ॉल्ट है)। spring.jpa.hibernate.ddl-autoSQL फ़ाइल का उपयोग करने के बजाय अपनी इकाई कॉन्फ़िगरेशन के आधार पर अपनी तालिकाएँ बनाने के लिए उपयोग किया जा सकता है। यह डिफ़ॉल्ट रूप से इन-मेमोरी डेटाबेस पर सक्षम होता है। इसलिए मैंने अपने उत्तर में नोट को जोड़ा, यह समझाते हुए कि यदि आप इन-मेमोरी डेटाबेस का उपयोग करते हैं और आप इसका उपयोग करना चाहते हैं schema.sql, तो आपको अक्षम करने की आवश्यकता है spring.jpa.hibernate.ddl-autoअन्यथा दोनों आपकी तालिका बनाने का प्रयास करेंगे।
g00glen00b

7
यदि आप data-h2.sqlअपने प्रारंभिक डेटा के लिए फ़ाइल नाम का उपयोग करना चाहते हैं , तो आपको spring.datasource.platform=h2अपने आवेदन गुणों में भी सेट करना चाहिए ।
जेसन इवांस

1
Data.sql फ़ाइल को हर बार स्प्रिंग-बूट एप्लिकेशन को निकाल दिया जाता है। इसका मतलब यह है कि यदि आपके पास स्टेटमेंट्स हैं, तो वे एक- org.h2.jdbc.JdbcSQLExceptionअपवाद का कारण बन सकते हैं , क्योंकि डेटा पहले से ही डेटाबेस में मौजूद है। मैं एक एम्बेडेड H2 डेटाबेस का उपयोग कर रहा हूं, लेकिन समस्या समान है।
इगोर

1
@ g00glen00b दुख की बात है कि सभी आसान है, क्योंकि उदाहरण के लिए H2 डेटाबेस के साथ परेशानी है MERGE INTO। मुझे पता चला, कि डेटा के बजाय import.sql फ़ाइल का उपयोग करके इसे दरकिनार करने का एक तरीका है । इसे बनाने या बनाने-छोड़ने की आवश्यकता होती spring.jpa.hibernate.ddl-autoहै । फिर जब भी स्कीमा फ़ाइल बनाई जाती है (और / या एक स्कीमा। एससीएल निष्पादित होता है), तो आयातएससीएल को भी निष्पादित किया जाता है। फिर भी: यह इनटैट डेटा बनाने के एक साफ-सुथरे क्रियान्वयन की तरह लगता है, न कि एक स्वच्छ कार्यान्वयन के रूप में।
इगोर

82

अगर मैं केवल सरल परीक्षण डेटा सम्मिलित करना चाहता हूं तो मैं अक्सर लागू करता हूं ApplicationRunner। इस इंटरफ़ेस के कार्यान्वयन एप्लिकेशन स्टार्टअप पर चलाए जाते हैं और उदाहरण के लिए कुछ परीक्षण डेटा सम्मिलित करने के लिए स्वत: संग्रहित भंडार का उपयोग कर सकते हैं।

मुझे लगता है कि इस तरह का कार्यान्वयन आपके मुकाबले थोड़ा अधिक स्पष्ट होगा क्योंकि इंटरफ़ेस का अर्थ है कि आपके कार्यान्वयन में कुछ ऐसा है जो आप अपने आवेदन के तैयार होने के बाद सीधे करना चाहते हैं।

आपका कार्यान्वयन sth दिखेगा। इस तरह:

@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

सुझाव के रूप में यह कोशिश करें:

@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: स्कीमा और डेटा स्क्रिप्ट के साथ प्रारंभ करें

आवश्यक शर्तें: application.propertiesआपको इसका उल्लेख करना होगा:

spring.jpa.hibernate.ddl-auto=none(अन्यथा लिपियों को हाइबरनेट द्वारा अनदेखा किया जाएगा, और यह @Entity/ और @Tableएनोटेट कक्षाओं के लिए परियोजना को स्कैन करेगा )

फिर, अपनी MyApplicationकक्षा में यह पेस्ट करें:

@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;
}

scriptsफ़ोल्डर कहाँ स्थित है resources(IntelliJ Idea)

आशा है कि यह किसी की मदद करता है


3
विकल्प 2 बहुत अच्छा है क्योंकि यह क्या हो रहा है इसका स्पष्ट प्रमाण देता है। कई डेटा स्रोत के साथ विशेष रूप से यह आवश्यक हो सकता है कि स्प्रिंग के DataSourceAutoConfiguration.class को निष्क्रिय कर दें, जिस स्थिति में अन्य सभी data.sql और schema.sql समाधान उपलब्ध कराए जाते हैं।
काईकार्नो

1
आप प्रारंभिक डेटा लोड करना चाहते हैं, लेकिन अभी भी हाइबरनेट DDL बनाने के लिए चाहते हैं, लेकिन आप एक से अधिक datasources है और मैन्युअल रूप से सेट अप है, तो इस मामले में एक बेहतर विकल्प के अनुसार वसंत के DataSourceInitializer सेम घोषित करने के लिए है stackoverflow.com/a/23036217/3092830 क्योंकि यह आपके लिए @PostConstruct मुद्दे को ले जाएगा।
kaicarno

32

आप उन SQL फ़ाइलों spring.datasource.dataको application.propertiesसूचीबद्ध करने के लिए एक संपत्ति जोड़ सकते हैं जिन्हें आप चलाना चाहते हैं। ऐशे ही:

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

इन फ़ाइलों में से प्रत्येक में sql इंसर्ट स्टेटमेंट को चलाया जाएगा, जिससे आप चीजों को व्यवस्थित रख पाएंगे।

यदि आप फ़ाइलों को क्लासपाथ में रखते हैं, उदाहरण के लिए src/main/resourcesउन्हें लागू किया जाएगा। या के classpath:साथ बदलें file:और फ़ाइल के लिए एक निरपेक्ष पथ का उपयोग करें


5
यदि आप चाहते हैं कि एक बाहरी फ़ाइल file:इसके बजाय रखना न भूलें classpath:
अलेक्जेंडर लेच

फाइलें कहां स्थित होंगी (account.sql, ...)?
dpelisek

1
@dpelisek src / main / resource को काम करना चाहिए। उत्तर अपडेट किया गया।
रॉजविल्किन्स

14

आप इस तरह से कुछ का उपयोग कर सकते हैं:

@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

स्प्रिंग बूट आपको स्प्रिंग बैच का उपयोग करके अपने डेटाबेस को इनिशियलाइज़ करने के लिए एक सरल स्क्रिप्ट का उपयोग करने की अनुमति देता है ।

फिर भी, यदि आप DB संस्करणों को प्रबंधित करने के लिए कुछ अधिक विस्तृत रूप से उपयोग करना चाहते हैं, तो स्प्रिंग बूट फ्लाईवे के साथ अच्छी तरह से एकीकृत होता है

यह सभी देखें:


6
यहाँ पर स्प्रिंग बैच का सुझाव देना कठिन लगता है।
निक

@ क्लिक करें, ओपी डेटा की मात्रा का उल्लेख नहीं करता है .. वैसे भी उत्तर सभी वसंत बैच के बारे में नहीं है।
एक्सट्रीम बाइकर

मेरी राय में, फ्लाईवे या लिक्विबेस जाने का सही तरीका है। निक की टिप्पणी के बारे में सुनिश्चित नहीं है और आगे / src / मुख्य / संसाधनों के upvotes के बारे में। हां, बाद वाली छोटी परियोजनाओं के लिए काम करेगी। Xtreme बाइकर का जवाब बहुत छोटे प्रयास के माध्यम से इतना अधिक कार्यक्षमता देता है।
अलेक्जेंड्रोस

10

स्प्रिंग बूट 2 में डेटा। एसक्यूएल मेरे साथ वसंत बूट 1.5 में काम नहीं कर रहा था

import.sql

इसके अलावा, import.sqlअगर हाइबरनेट खरोंच से स्कीमा बनाता है (अगर, ddl- ऑटो संपत्ति बनाने या ड्रॉप करने के लिए सेट है) तो क्लासपाथ की जड़ में नामित एक फ़ाइल को स्टार्टअप पर निष्पादित किया जाता है।

यदि आप सम्मिलित करते हैं तो बहुत महत्वपूर्ण नोट करें डुप्लिकेट नहीं किया जा सकता डीडीएल-ऑटो संपत्ति का उपयोग करने के लिए अद्यतन करने के लिए सेट नहीं है क्योंकि प्रत्येक पुनरारंभ के साथ आपका डेटा फिर से डाला जाएगा

अधिक जानकारी के लिए आप वसंत वेब्सिट का उपयोग करें

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


वसंत में 2 डेटाबेस प्रारंभ केवल एम्बेडेड डेटाबेस के लिए काम करता है आप अन्य डेटाबेस के लिए उपयोग करने की जरूरत है spring.datasource.initialization मोड = हमेशा निर्दिष्ट करने के लिए चाहते हैं
शिक्षा कोस्टा

6

इस तरह से मुझे वह मिल गया है:

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

}

इस लेख के लेखक को धन्यवाद:

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


यदि आप सेवा का उपयोग कर रहे हैं तो यह काम नहीं करता है, और यदि सेवा को रिपॉजिटरी में
सीमित किया जाता


4

मैंने इस तरह की समस्या को हल किया:

@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

अगर कोई इसे स्वीकार करने के लिए काम कर रहा है, तो वह भी स्वीकृत उत्तर का पालन कर सकता है , मेरे लिए केवल मेरे src/test/resources/application.ymlH2 datasourceविवरण में काम करना है :

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

1

आप नीचे की तरह प्राप्त करने के लिए श्रोता को पंजीकृत और ईवेंट कर सकते हैं:

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

जब ContextRefreshEvent को निकाल दिया जाता है, तो हमें एप्लिकेशन और मॉडल और रिपॉजिटरी सहित - सभी स्वतः प्राप्त बीन्स तक पहुँच मिलती है।


1

यदि आप केवल कुछ पंक्तियाँ सम्मिलित करना चाहते हैं और आपके पास JPA सेटअप है। आप नीचे उपयोग कर सकते हैं

    @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
मैं इस लंबे समय का उपयोग कर रहा था, याद नहीं कर पा रहा था। यह बात है। धन्यवाद।
फ्रीलांसर

0

यह भी चलेगा।

    @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

सबसे कॉम्पैक्ट (डायनेमिक डेटा के लिए) @ Mathias-dpunkt solution को MainApp (लोम्बोक के साथ @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

तुम लगभग वहां थे!

@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

आप नीचे दिए गए कोड का उपयोग कर सकते हैं। निम्नलिखित कोड में स्प्रिंग बूट एप्लिकेशन के स्टार्टअप के दौरान एक डेटाबेस प्रविष्टि होती है।

@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);
        }
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.