جاوا و تکنولوژی های آن

java programming language

در این وبلاگ به بررسی نکات موجود در جاوا و تکنولوژی های آن می پردازیم

طبقه بندی موضوعی


Liquibase یک Version Control  برای دیتابیس است که تغییرات اسکیمای دیتابیس را براحتی قابل رصد، نسخه گذاری و توسعه پذیر می کند


ابتدا کتابخانه آنرا اضافه میکنیم :


<dependency>
    <groupId>org.liquibase</groupId>
     <artifactId>liquibase-core</artifactId>
      <version>3.4.1</version>
</dependency>


برای نسخه های جدیدتر به این لینک مراجعه کنید




قسمت اصلی که Liquibase از آن استفاده میکند فایل ChangeLog است که ساختار xml ای دارد و کلیه تغییرات را با جزییات در آن نگهداری میکند که نگاهی به ساختار آن می اندازیم :


<databaseChangeLog 
  xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
  xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext
   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd 
   http://www.liquibase.org/xml/ns/dbchangelog 
   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
     
    <changeSet author="John" id="someUniqueId">
        <addColumn tableName="users">
            <column name="address" type="varchar(255)" />
        </addColumn>
    </changeSet>
     
</databaseChangeLog>


نمونه بالا نشان میدهد که یک Column با نام address به جدول users توسط john و Id مشخصش اضافه شده است 





اجرای Liquibase بوسیله Spring Bean :


نخستین راه برای اجرا کردن تغییرات Liquibase در Spring استفاده از Bean است البته راه های دیگری وجود دارد ولی در Spring ساده ترین راه استفاده در قالب Bean است 

@Bean
public SpringLiquibase liquibase() {
    SpringLiquibase liquibase = new SpringLiquibase();
    liquibase.setChangeLog("classpath:liquibase-changeLog.xml");
    liquibase.setDataSource(dataSource());
    return liquibase;
}

* باید توجه داشته باشیم که فایل changelog.xml در مسیر معرفی شده وجود داشته باشد




استفاده از Liquibase با Spring Boot :


اگر Liquibase را با Spring Boot استفاده کنیم نیازی نداریم که Bean تعریف کنیم فقط باید کتابخانه آنرا اضافه کنیم و فایل changelog را در مسیر db/changelog/db.changelog-master.yaml قرار دهیم و بصورت اتوماتیک شناسایی میشود


مسیر فایل changelog را میتوان در فایل تنظیمات Properties تغییر داد:


liquibase.change-log=classpath:liquibase-changeLog.xml




غیر فعال سازی Liquibase در Spring Boot :


گاهی نیاز داریم Liquibase را غیر فعال کنیم راحتترین راه ست کردن آن در Properties است 


در Spring 2 :

spring.liquibase.enabled=false


در Spring 1 :

liquibase.enabled=false




ساخت فایل changelog با کمک Maven Plugin :


بجای اینکه فایل changelog را بصورت دستی بنویسیم میتوانیم از پلاگین Maven برای ایجاد این فایل کمک بگیریم و در زمان صرفه جویی کنیم 


اضافه کردن وابستگی برای plugin :


<dependency>
    <groupId>org.liquibase</groupId>
    <artifactId>liquibase-maven-plugin</artifactId>
    <version>3.4.1</version>
</dependency> 
...
<plugins>
    <plugin>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.4.1</version>
        <configuration>                  
            <propertyFile>src/main/resources/liquibase.properties</propertyFile>
        </configuration>                
    </plugin> 
</plugins>



و بعد برای ساخت changelog از دیتابیس موجود از این پلاگین استفاده کنیم :


mvn liquibase:generateChangeLog


محتویات فایل property :

url=jdbc:mysql://localhost:3306/oauth_reddit
username=tutorialuser
password=tutorialmy5ql
driver=com.mysql.jdbc.Driver
outputChangeLogFile=src/main/resources/liquibase-outputChangeLog.xml


فایل changelog ساخته شده بعد از اجرا دستور بالا :


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog ...>
     
    <changeSet author="John (generated)" id="1439225004329-1">
        <createTable tableName="APP_USER">
            <column autoIncrement="true" name="id" type="BIGINT">
                <constraints primaryKey="true"/>
            </column>
            <column name="accessToken" type="VARCHAR(255)"/>
            <column name="needCaptcha" type="BIT(1)">
                <constraints nullable="false"/>
            </column>
            <column name="password" type="VARCHAR(255)"/>
            <column name="refreshToken" type="VARCHAR(255)"/>
            <column name="tokenExpiration" type="datetime"/>
            <column name="username" type="VARCHAR(255)">
                <constraints nullable="false"/>
            </column>
            <column name="preference_id" type="BIGINT"/>
            <column name="address" type="VARCHAR(255)"/>
        </createTable>
    </changeSet>
    ...
</databaseChangeLog>


حالا از این فایل برای ساخت دیتابیس یا ایجاد تغییرات میتوانیم استفاده کنیم 






استفاده از Plugin برای ساخت changeLog بین تفاوت دو دیتابیس :


فرض کنید میخواهیم فایل changelog ای داشته باشیم که در آن تفاوت های دو دیتابیس (مثلا development و production) :


mvn liquibase:diff


فایل تنظیمات properties :


changeLogFile=src/main/resources/liquibase-changeLog.xml
url=jdbc:mysql://localhost:3306/oauth_reddit
username=tutorialuser
password=tutorialmy5ql
driver=com.mysql.jdbc.Driver
referenceUrl=jdbc:h2:mem:oauth_reddit
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml
referenceDriver=org.h2.Driver
referenceUsername=sa
referencePassword=



و در فایل changelog تغییرات پیدا شده را ثبت کرده ایم :


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog ...>
    <changeSet author="John" id="1439227853089-1">
        <dropColumn columnName="address" tableName="APP_USER"/>
    </changeSet>
</databaseChangeLog>


این امکان قدرتمندی برای تکامل دیتابیس است مثلا به hibernate اجازه میدهد که اسکیمای جدیدی برای حالت development ایجاد کند و به عنوان یک مرجع در مقابل تغییرات استفاده کند 




استفاده از Hibernate Liquibase Plugin :


اگر برنامه از Hibernate استفاده میکنیم میتوانیم از Hibernate Liquibase Plugin استفاده کنیم 


ابتدا تنظیمات و وابستگی های انرا ست میکنیم :


<plugins>
    <plugin>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-maven-plugin</artifactId>
        <version>3.4.1</version>
        <configuration>                  
            <propertyFile>src/main/resources/liquibase.properties</propertyFile>
        </configuration> 
        <dependencies>
            <dependency>
                <groupId>org.liquibase.ext</groupId>
                <artifactId>liquibase-hibernate4</artifactId>
                <version>3.5</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>4.1.7.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-jpa</artifactId>
                <version>1.7.3.RELEASE</version>
            </dependency>
        </dependencies>               
    </plugin> 
</plugins>




تولید changelog بین تفاوت های Entity ها و Database :


هنگامی که یک Entity تغییری ایجاد شد میتوانیم با استفاده از این پلاگین تفاوت های انرا با دیتابیس log بگیریم :


changeLogFile=classpath:liquibase-changeLog.xml
url=jdbc:mysql://localhost:3306/oauth_reddit
username=tutorialuser
password=tutorialmy5ql
driver=com.mysql.jdbc.Driver
referenceUrl=hibernate:spring:org.baeldung.persistence.model
  ?dialect=org.hibernate.dialect.MySQLDialect
diffChangeLogFile=src/main/resources/liquibase-diff-changeLog.xml


دقت کنید که referenceUrl از package scan استفاده میکند و در ادامه باید نوع Dialect مورد استفاده را هم قید کنیم






ویژگی Rollback در Liquibase :


در شرایط بحرانی گاهی ما نیاز داریم عملیات انجام شده در Liquibase را به حالت قبل برگردانیم 


دو نوع عملیات در Liquibase وجود دارد که منجر به Rollback شدن میشود


- Automatic : هنگامی که مهاجرت به دیتابیس جدید نیاز به Rollback شدن پیدا کند 

- Manual : هنگامی که ما تصمیم به Rollback میگیریم چون عملیات مهاجرت به دیتابیس موفقیت آمیز نیست


مثلا rollback شدن دستور create table ممکن است table را drop کند و در اینجا rollback بصورت اتوماتیک رخ میدهد 


یا rollback شدن دستور drop table امکانپذیر نباشد چون آخرین وضعیت جدول مشخص نیست و در این حالت نیاز است rollback بصورت manual یا دستی انجام شود





نوشتن Rollback ساده :


با استفاده از تگ changeset  میتوانیم گروه تغییراتی که نیاز است در دیتابیس اعمال شود را مشخص کنیم 


که در اینجا تصمیم داریم عمل Rollback را انجام دهیم :


<changeSet id="testRollback" author="baeldung">
    <createTable tableName="baeldung_turorial">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
        <column name="author" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_test"/>
    </rollback>
</changeSet>


مثال بالا در گروه اول قرار میگیرد اگر موردی به آن اضافه نکنیم عمل rollback بصورت اتوماتیک انجام میشود اما ما میتوانیم حالت پیش فرض آنرا عوض کنیم 



برای اجرای دستور مهاجرت :


mvn liquibase:update


و بعد عمل rollback را انجام میدهیم :


mvn liquibase:rollback



طبق چیزی که تعریف کردیم این دستور تغییرات موجود در تگ changeset را rollback میکند و عملیاتی که طی update انجام شده را برمیگرداند اما rollback شدن با شکست روبرو خواهد شد چون ما نقطه rollback شدن را تعریف نکردیم و بازگشت به مراحل اولیه دیتابیس را کاملا پاک میکند تا به مرحله اولیه آن بازگردد پس باید برای Rollback شدن حد و نقطه آنرا تعیین کنیم که سه شرط زیر لازم است :


rollbackTag

rollbackCount

rollbackDate




شرایط rollbackTag :


ما میتوانیم وضعیت خاصی از دیتابیس را به عنوان یک tag تعیین کنیم و بعدا به آن تگ که نماینده وضعیت خاص مد نظر ماست که قبلا تعیین کردیم Rollback کنیم

mvn liquibase:rollback -Dliquibase.rollbackTag=1.0

تگ تعریف شده "1.0" بوده که با اجرای دستور بالا تمامی changeset ها به حالتی که در "1.0" وجود داشت برمیگردد 





شرایط rollbackCount :


در این حالت تعداد changeset هایی که نیاز است به عقب برگردد را تعیین میکنیم و اگر تعداد را 1 در نظر بگیریم به changeset آخر برمیگردد :


mvn liquibase:rollback -Dliquibase.rollbackCount=1




شرایط rollbackDate :


در این حالت میتوانیم به تغییرات تاریخ خاصی Rollback کنیم 


mvn liquibase:rollback "-Dliquibase.rollbackDate=Jun 03, 2017"


* فرمت تاریخ وارد شده ISO است و باید با شرایطی که ()DateFormat.getDateInstance آنرا قبول میکند مطابقت داشته باشد






option های قابل استفاده در Changeset Rollback :


multi statement rollback :

ممکن است بیش از یک دستورالعمل را بخواهیم اجرا کنیم :


<changeSet id="multiStatementRollback" author="baeldung">
    <createTable tableName="baeldung_tutorial2">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <createTable tableName="baeldung_tutorial3">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_tutorial2"/>
        <dropTable tableName="baeldung_tutorial3"/>
    </rollback>
</changeSet>





Multiple Rollback Tags :


در هر changeset ما میتوانیم بیش از یک تگ rollback داشته باشیم که به ترتیب قرارگیری اجرا میشوند :


<changeSet id="multipleRollbackTags" author="baeldung">
    <createTable tableName="baeldung_tutorial4">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <createTable tableName="baeldung_tutorial5">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
    </createTable>
    <rollback>
        <dropTable tableName="baeldung_tutorial4"/>
    </rollback>
    <rollback>
        <dropTable tableName="baeldung_tutorial5"/>
    </rollback>
</changeSet>






Refer Another Changeset for Rollback :

ما میتوانیم به changeset دیگر برای rollback شدن ارجاع دهیم. امکان دارد در changeset اصلی بخواهیم جزییاتی از دیتابیس را تغییر دهیم و با اینکار میتوانیم در زمان صرفه جویی کنیم :

<changeSet id="referChangeSetForRollback" author="baeldung">
    <dropTable tableName="baeldung_tutorial2"/>
    <dropTable tableName="baeldung_tutorial3"/>
    <rollback changeSetId="multiStatementRollback" changeSetAuthor="baeldung"/>
</changeSet>




Empty Rollback Tag :

بصورت پیش فرض Liquibase کدی جهت rollback سعی میکند ایجاد کند و اگر بخواهیم Rollback نداشته باشیم میتوانیم یک تگ خالی بگذاریم و عملیاتی برای Rollback اتفاق نخواهد افتاد 


<changeSet id="emptyRollback" author="baeldung">
    <createTable tableName="baeldung_tutorial">
        <column name="id" type="int"/>
        <column name="heading" type="varchar(36)"/>
        <column name="author" type="varchar(36)"/>
    </createTable>
    <rollback/>
</changeSet>





Option های دستورات Rollback :


به غیر از Rollback کردن دیتابیس به وضعیت قبلی، با استفاده از این دستور میتوانیم کارهای نظیر ایجاد Rollback SQL ، ایجاد Rollback Script به وضعیت جلوتر ، تست کردن وضعیت مهاجرت به دیتابیس و Rollback کردن باهم 




Generate Rollback Script :


سه گزینه برای ساخت Rollback SQL داریم :


<rollbackSQL <tag : ساخت یک اسکریپت SQL برای Rollback کردن به تگ خاصی

<rollbackToDateSQL <date/time : ساخت یک اسکریپت SQL برای Rollback کردن به تاریخ معینی

<rollbackCountSQL <value : ساخت یک اسکریپت SQL برای Rollback کردن به تعداد مشخصی به قبل


و نحوه اجرای آن :

mvn liquibase:rollbackCountSQL 2




Generate Future Rollback Script :


این حالت به ما اجازه میدهد که همزمان با ایجاد اسکریپت مهاجرت اسکریپت Rollback را هم ایجاد کنیم که بیشتر برای DBA ها مفید خواهد بود ولی برای اطلاعات بیشتر به این لینک مراجعه کنید 


mvn liquibase:futureRollbackSQL




Run Update Testing Rollback:


این دستور دیتابیس را آپدیت میکند و بعد تغییرات را به عقب برمیگرداند تا به وضعیت کنونی برسد 


mvn liquibase:updateTestingRollback








نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی