Migrasi data dengan mongoDB dan Spring Boot

Setiap pengembang cepat atau lambat menghadapi kebutuhan untuk memigrasikan data dalam database. Pada proyek kami, kami menggunakan mongoDB sebagai basis data. Kami mendekati migrasi data dengan berbagai cara:


  • menulis skrip js dan berlari langsung di database
  • Mongobee bekas - alat untuk migrasi otomatis


    Mongobee bekerja dengan baik sampai kami menemukan situasi di mana kami ingin menambahkan bidang baru dengan indeks yang unik. Katakanlah kita memiliki kelas:


    @Document @Data public class TestDocument { @Id private String id; private String text; } 

    Sekarang kami menambahkan bidang baru:


     @Document @Data public class TestDocument { @Id private String id; private String text; @Indexed(unique = true) private String text2; } 

    Kami menulis migrasi, yang harus mengisi bidang text2 di semua dokumen dengan nilai unik:


     @ChangeLog public class TestDocumentChangelog { @ChangeSet(order = 1, id = "change1", author = "Stepan") public void changeset(MongoTemplate template) { template.findAll(Document.class, "testDocument").forEach(document -> { document.put("text2", UUID.randomUUID().toString()); template.save(document, "testDocument"); }); } } 

    Tetapi ketika kami memulai aplikasi, kami melihat bahwa Spring meluncurkan komponen Data Mongo sebelum migrasi kami dimulai, dan karena itu terjadi kesalahan saat secara otomatis membuat indeks di atas bidang text2 , karena bidang ini belum diisi oleh dokumen apa pun.
    Setelah kejadian ini, kami memutuskan untuk meninggalkan Mongobee dan mencoba untuk menulis alat kami sendiri, yang juga akan memudahkan untuk menulis migrasi, tetapi selain itu akan memiliki fitur seperti:


  • Jalankan sebelum Data Mongo
  • Dukungan transaksi ditambahkan dalam MongoDB 4.0
  • Ketergantungan injeksi di kelas ChangeLog

Hasilnya adalah perpustakaan yang disebut Mongration, yang mendukung semua fungsi yang dijelaskan di atas.


Dukungan Siklus Hidup Boot Musim Semi


Fungsi pertama diimplementasikan menggunakan konfigurasi otomatis, yang dimulai setelah membuat MongoClient dan sebelum memindai repositori:


 @Configuration @AutoConfigureAfter(MongoAutoConfiguration.class) @AutoConfigureBefore(MongoDataAutoConfiguration.class) @Import(MongrationConfiguration.class) public class MongrationAutoConfiguration { } 

Tetapi masalah dengan konfigurasi otomatis adalah jika Anda menggunakan anotasi @EnableMongoRepositories untuk mengaktifkan repositori, maka komponen Data Mongo diinisialisasi sebelum konfigurasi otomatis kami. Untuk menghindari masalah ini, Anda harus menggunakan anotasi @EnableMongration bersama dengan @EnableMongoRepositories :


 @Configuration @EnableMongoRepositories @EnableMongration public class MongoRepositoriesConfiguration { } 

@EnableMongration tidak lebih dari meluncurkan konfigurasi yang sama, hanya memungkinkan Anda menjalankannya lebih awal:


 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(MongrationConfiguration.class) public @interface EnableMongration { } 

Dukungan transaksi


Untuk mendukung transaksi, Anda harus mengonfigurasi Replica Set MongoDB. Juga penting untuk mendeklarasikan kacang MongoTransationManager (jika Mongration tidak menemukan kacang ini dalam konteks, ia akan membuatnya dengan sendirinya). Mongration memungkinkan Anda untuk menggunakan transaksi dalam dua cara:


  • Menggunakan @Transactional
     @Transactional @ChangeSet(order = 1, id = "change1", author = "Stepan") public void changeset(MongoTemplate template) { template.findAll(Document.class, "testDocument").forEach(document -> { document.put("text2", UUID.randomUUID().toString()); template.save(document, "testDocument"); }); } 
  • Menggunakan TransactionTemplate
     @ChangeSet(order = 1, id = "change1", author = "Stepan") public void migration(MongoTemplate template, TransactionTemplate txTemplate) { template.createCollection("entity"); txTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { template.save(new Document("index", "1").append("text", "1"), "entity"); template.save(new Document("index", "2").append("text", "2"), "entity"); template.save(new Document("index", "3").append("text", "3"), "entity"); } }); } 


Metode kedua berguna karena memungkinkan Anda untuk menggunakan operasi DDL yang tidak dapat diluncurkan dalam transaksi dan operasi DML diluncurkan dalam transaksi dalam satu migrasi.


Ketergantungan injeksi di kelas ChangeLog


Fungsionalitas ini dimungkinkan karena setiap kelas ChangeLog sendiri adalah kacang biasa:


 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Component public @interface ChangeLog { } 

Perlu dicatat bahwa Anda tidak dapat menyuntikkan kacang yang memiliki ketergantungan pada komponen Data Mongo, karena pada saat migrasi selesai mereka belum diinisialisasi.


Kode sumber perpustakaan tersedia di Github .

Source: https://habr.com/ru/post/id451798/


All Articles