Pada bagian
sebelumnya, kami menemukan fitur dasar
Liquibase dan menulis contoh dasar aplikasi
boot Spring yang menggunakan Liquibase untuk menginisialisasi database. Kode aplikasi basis lengkap dapat dilihat di
sini di GitHub . Pada artikel ini kita akan berbicara tentang
liquibase-maven-plugin dan fitur-fitur tambahan yang diberikannya untuk versi struktur database. Mari kita mulai dengan cara membuat skrip secara otomatis menggunakan
fungsi perbandingan .
Misalkan kita perlu membuat beberapa perubahan pada struktur basis data kita. Misalnya, kami ingin
email tidak menjadi
nol . Tentu saja, untuk perubahan sekecil itu dimungkinkan untuk menyesuaikan kode dan skrip secara manual, tetapi bagaimana jika ada lebih banyak perubahan? Dalam hal ini, kemampuan untuk membandingkan basis data yang dibangun ke dalam Liquibase akan membantu kami. Fitur yang menarik dari itu adalah Anda dapat membandingkan tidak hanya dua database, tetapi juga database dengan seperangkat entitas JPA dalam aplikasi kami. Itulah tepatnya yang akan kita lakukan sekarang!
Buat skrip dengan perubahan menggunakan liquibase-diff
Di bagian
plugins dari file
pom.xml ,
kami menambahkan desain yang agak rumit ini. Ini adalah
liquibase-maven-plugin , di mana dependensi terhubung untuk menganalisis
entitas hibernate dan bekerja dengan file YAML. Plugin ini akan membantu kami secara otomatis membuat
skrip liquibase dengan membandingkan struktur dalam dua basis data atau bahkan dengan membandingkan struktur data dalam basis data dan satu set entitas hiberante dalam aplikasi kami (
liquibase-hibernate5 ditambahkan untuk ini).
<plugin> <groupId>org.liquibase</groupId> <artifactId>liquibase-maven-plugin</artifactId> <version>3.8.1</version> <configuration> <propertyFile>${project.build.outputDirectory}/liquibase-maven-plugin.properties</propertyFile> <systemProperties> <user.name>your_liquibase_username</user.name> </systemProperties> <logging>info</logging> </configuration> <dependencies> <dependency> <groupId>org.liquibase.ext</groupId> <artifactId>liquibase-hibernate5</artifactId> <version>3.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.2.0.RELEASE</version> </dependency> </dependencies> </plugin>
Perhatikan pengaturan
user.name . Ini opsional, tetapi tanpanya Liquibase akan menunjukkan dalam skrip yang dibuat nama pengguna OS saat ini di mana plugin diluncurkan.
Pengaturan untuk plugin dapat ditulis langsung ke pom.xml atau diteruskan sebagai parameter baris perintah saat memanggil pakar, tetapi saya lebih suka opsi dengan file
liquibase-maven-plugin.properties terpisah. Isinya akan terlihat seperti ini.
changeLogFile= @project.basedir@/src/main/resources/db/changelog/db.changelog-master.yaml url= jdbc:mysql://localhost:3306/geek_db?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username= dbusername password= dbpassword driver= com.mysql.cj.jdbc.Driver referenceUrl= hibernate:spring:ru.usharik.liquibase.demo.persist.model?dialect=org.hibernate.dialect.MySQLDialect diffChangeLogFile= @project.basedir@/src/main/resources/db/changelog/db.changelog-@timestamp@.yaml ignoreClasspathPrefix= true
Perlu memperhatikan parameter
url dan
referenceUrl . Skrip yang akan membuat liquibase setelah perbandingan akan menjadi perbedaan antara basis menggunakan tautan referenceUrl dan basis menggunakan tautan
url . Jika nanti Anda menjalankan skrip ini di pangkalan menggunakan tautan
url , maka skrip ini akan menjadi sama dengan skrip yang terletak di tautan ReferenceUrl. Perhatian khusus harus diberikan pada tautan referenceUrl. Seperti yang Anda lihat, ini merujuk bukan ke database, tetapi ke paket aplikasi kami di mana kelas entitas berada. Berkat ini, kita sekarang dapat menemukan skrip yang akan menambah ke database perubahan yang dibuat dalam kode.
Sekarang kita perlu mengkonfigurasi maven-resource-plugin untuk menggantikan placeholder di file pengaturan, seperti
@project.basedir@
dan
@timestamp@
. Untuk melakukan ini, tambahkan bagian
sumber daya dari formulir berikut ke bagian
membangun <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <includes> <include>*.properties</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> <includes> <include>**/*.*</include> </includes> </resource> </resources>
Omong-omong, boot Spring mengubah format standar untuk placeholder yang dihuni menggunakan
maven-resource-plugin dari
${smth}
ke
@smth@
. Faktanya adalah bahwa placeholder dari tipe
@smth@
di Spring Boot digunakan untuk menggantikan variabel lingkungan dan parameter dari aplikasi Spring Boot itu sendiri.
Juga, kami sedikit mengubah bagian
properti di
pom.xml untuk menetapkan nilai ke variabel
stempel waktu dalam format yang kami butuhkan. Sayangnya, format standar dapat berisi karakter yang dilarang dalam nama file untuk beberapa sistem operasi.
<properties> <java.version>1.8</java.version> <timestamp>${maven.build.timestamp}</timestamp> <maven.build.timestamp.format>yyyyMMdd-HHmmssSSS</maven.build.timestamp.format> </properties>
Sekarang mari kita ubah bidang email di kelas Pengguna
@Column(name = "email", nullable = false) private String email;
Terakhir, jalankan perintah build menggunakan
liquibase-maven-plugin untuk perbandingan.
mvn clean install liquibase:diff -DskipTests=true
Dalam hal ini, kita perlu membangun kembali proyek sepenuhnya, karena plugin (liquibase: diff) akan menggunakan bukan sumber yang dikompilasi, tetapi mengkompilasi file kelas entitas dari folder
target untuk analisis.
Jika semuanya dilakukan dengan benar, maka setelah eksekusi berhasil dari perintah di folder
resources / db / changelog , Anda akan melihat file dengan nama
db.changelog-20190723-100748666.yaml . Karena kami menggunakan tanggal dan waktu saat ini dalam nama file, dengan setiap peluncuran kami akan memiliki file baru, yang cukup nyaman. Jika Anda sudah membuat database dengan struktur tabel yang sesuai dengan pelajaran sebelumnya, maka isi file harus seperti ini.
databaseChangeLog: - changeSet: id: 1563876485764-1 author: your_liquibase_username (generated) changes: - addNotNullConstraint: columnDataType: varchar(255) columnName: email tableName: users
Seperti yang Anda lihat, skrip ini membuat perubahan persis yang dibuat dalam kode. Sebagai latihan, saya sarankan Anda menjalankan skrip ini terhadap database kosong dan lihat hasilnya.
Selanjutnya, kita cukup menyalin perubahan dari file ini ke
db.changelog-master.yaml atau kita bisa menghubungkan file ini ke sana dengan instruksi
- include: file: db.changelog-20190723-100748666.yaml relativeToChangelogFile: true
Juga dalam file ini Anda perlu menentukan
logicalFilePath: db/changelog/db.changelog-20190723-100748666.yaml
, mirip dengan bagaimana hal itu dilakukan di
db.changelog-master.yaml .
Ini akan membantu untuk mengatasi beberapa masalah yang mungkin terjadi ketika menggunakan kacang
liquibase bawaan dan
liquibase-maven-plugin dalam aplikasi. Setelah itu, restart aplikasi atau jalankan perintah:
mvn liquibase:update
Mari kita coba membuat perubahan yang lebih kompleks pada kode. Misalnya, tambahkan tabel peran yang akan memiliki hubungan banyak-ke-banyak dengan tabel pengguna.
@Entity @Table(name = "roles") public class Role implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @Column(name = "name", unique = true, nullable = false) private String name; @ManyToMany(mappedBy = "roles") private Set<User> users;
Dan di tabel Users kami tambahkan
@ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) private Set<Role> roles;
Setelah memulai perbandingan, kami mendapatkan file dengan konten berikut
databaseChangeLog: - changeSet: id: 1563877765929-1 author: your_liquibase_username (generated) changes: - createTable: columns: - column: autoIncrement: true constraints: primaryKey: true primaryKeyName: rolesPK name: id type: BIGINT - column: constraints: nullable: false name: name type: VARCHAR(255) tableName: roles - changeSet: id: 1563877765929-2 author: your_liquibase_username (generated) changes: - createTable: columns: - column: constraints: nullable: false name: user_id type: BIGINT - column: constraints: nullable: false name: role_id type: BIGINT tableName: users_roles - changeSet: id: 1563877765929-3 author: your_liquibase_username (generated) changes: - addPrimaryKey: columnNames: user_id, role_id tableName: users_roles - changeSet: id: 1563877765929-4 author: your_liquibase_username (generated) changes: - addUniqueConstraint: columnNames: name constraintName: UC_ROLESNAME_COL tableName: roles - changeSet: id: 1563877765929-5 author: your_liquibase_username (generated) changes: - addForeignKeyConstraint: baseColumnNames: user_id baseTableName: users_roles constraintName: FK2o0jvgh89lemvvo17cbqvdxaa deferrable: false initiallyDeferred: false referencedColumnNames: id referencedTableName: users - changeSet: id: 1563877765929-6 author: your_liquibase_username (generated) changes: - addForeignKeyConstraint: baseColumnNames: role_id baseTableName: users_roles constraintName: FKj6m8fwv7oqv74fcehir1a9ffy deferrable: false initiallyDeferred: false referencedColumnNames: id referencedTableName: roles
Kami juga dapat dengan mudah menambahkan file ini ke skrip yang berfungsi.
Kembalikan perubahan
Sekarang mari kita lihat bagaimana mengembalikan perubahan yang dilakukan. Untuk beberapa alasan, pengidentifikasi yang kami tentukan di setset tidak dapat digunakan untuk mengembalikannya. Ada tiga opsi, tentukan titik rollback
- melalui jumlah set perubahan yang dihitung dari saat ini
- setelah tanggal perubahan
- via tag (atur menggunakan changeSet dari jenis khusus)
Tag diatur sebagai berikut.
- changeSet: id: some_uniqui_id author: liquibase_user_name changes: - tagDatabase: tag: db_tag
Nah, perintah untuk tiga cara yang tercantum untuk melakukan rollback
mvn liquibase:rollback -Dliquibase.rollbackTag=db_tag mvn liquibase:rollback -Dliquibase.rollbackCount=1 mvn liquibase:rollback "-Dliquibase.rollbackDate=Jun 03, 2017"
Dan akhirnya, beberapa bahan tambahan
- Kode untuk artikel ini
- Tentang kemunduran di Liquibase
- Tentang Migrasi dengan Liquibase
- Liquibase di github
- Artikel yang sangat bagus tentang berbagai pendekatan untuk membuat versi database
Tentu saja, saya akan sangat senang dengan komentar, penambahan, klarifikasi, dll.