目錄
[toc]
背景
由于SaaS項(xiàng)目需要提供多租戶之間物理隔離的數(shù)據(jù)庫(kù)實(shí)現(xiàn)方案, 為了標(biāo)準(zhǔn)化操作, 所以采用了Liquibase這樣一款數(shù)據(jù)庫(kù)同步備份工具, 從一個(gè)模板文件中動(dòng)態(tài)的在一個(gè)新schema中創(chuàng)建與模板庫(kù)中相同的表結(jié)構(gòu)以及數(shù)據(jù)的初始化操作
思考
- 如何有效的管理schema與數(shù)據(jù)庫(kù)賬戶, 特別是防止數(shù)據(jù)泄露?
- 如何在服務(wù)運(yùn)行期間卸載和裝載數(shù)據(jù)源?
- 如何在項(xiàng)目中有效的完成動(dòng)態(tài)數(shù)據(jù)源功能, 數(shù)據(jù)源加載太多是否有坑?
實(shí)踐
前言: 我也是首次使用Liquibase, 如果有使用不對(duì)的地方還請(qǐng)留言指正, 網(wǎng)絡(luò)上能參考的文章實(shí)在有限, 我也是問(wèn)了之前實(shí)踐過(guò)的同事, 才慢慢整理出一個(gè)使用實(shí)踐. 記錄一下為了以防自己在將來(lái)忘記的時(shí)候可以回過(guò)來(lái)看看, 另外也希望能幫助到新入坑的小伙伴
官方文檔
官方文檔
在看官方文檔的時(shí)候也有很多不明白的地方, 都是一點(diǎn)一點(diǎn)慢慢摸索過(guò)來(lái)的
項(xiàng)目選型
- JDK8
- SpringBoot
- Bootstrap
- mysql
Maven依賴與pom配置
由于我的目標(biāo)是完成一個(gè)web項(xiàng)目, 所以我的pom文件里面至少會(huì)引入如下幾個(gè)依賴 (由于直接貼全部pom內(nèi)容太長(zhǎng). 為了不影響閱讀, 我只貼出關(guān)鍵的幾個(gè)依賴):
- druid
- mysql-connector-java
- spring-boot-starter-web
- mybatis-plus
- guava
<liquibase.version>3.6.3</liquibase.version>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>${liquibase.version}</version>
<configuration>
<!--引用配置文件-->
<propertyFile>${basedir}/src/main/resources/liquibase.properties</propertyFile>
</configuration>
</plugin>
上面配置文件的屬性在哪里看呢? 請(qǐng)看下面
官方文檔 -> documentation -> maven
傳送門, 懶
雖然很有創(chuàng)造力. 但是告訴你進(jìn)入路徑也許比直接給你要更好
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
配置文件編寫
屬性編寫來(lái)源:
官方文檔 -> documentation -> maven -> liquibase:generateChangeLog
傳送門
outputChangeLogFile=src/main/resources/changeLog.xml
url=jdbc:mysql://host:port/schema?useUnicode=true&characterEncoding=UTF-8&useSSL=true
driver=com.mysql.jdbc.Driver
username=root
password=root
# 默認(rèn)沒(méi)有最后的data, 看需求, 我們需要導(dǎo)出默認(rèn)數(shù)據(jù), 如果僅僅要表結(jié)構(gòu), 注釋掉即可
diffTypes=tables,views,columns,indexes,foreignkeys,primarykeys,uniqueconstraints,data
# 輸出默認(rèn)的schema名稱關(guān)閉掉
outputDefaultCatalog=false
mvn命令生成changeLog
一般我們都是用IDEA, 所以我就直接從idea中執(zhí)行mvn命令了:
結(jié)果:
在代碼中完成changeLog.xml的使用
如果不是必要, 改一下配置文件, 使用update命令即可. 但是為了演示一下項(xiàng)目中的使用方法. 所以在寫一個(gè)簡(jiǎn)單的Demo參考:
public static void main(String[] args) throws Exception {
ClassLoaderResourceAccessor classLoaderResourceAccessor = new ClassLoaderResourceAccessor(MainClass.class.getClassLoader());
String changeLogFilePath = "changeLog.xml";
String username = "root";
String password = "root";
String url = "jdbc:mysql://host:port/schema?useUnicode=true&characterEncoding=UTF-8&useSSL=true";
Properties properties = new Properties();
properties.setProperty("username", username);
properties.setProperty("password", password);
properties.setProperty("url", url);
Connection connection = DruidDataSourceFactory.createDataSource(properties).getConnection();
JdbcConnection jdbcConnection = new JdbcConnection(connection);
Liquibase liquibase = new Liquibase(changeLogFilePath, classLoaderResourceAccessor, jdbcConnection);
liquibase.update(new Contexts());
}
執(zhí)行結(jié)果:
...
02:20:30.747 [main] INFO liquibase.executor.jvm.JdbcExecutor - INSERT INTO pw_test.DATABASECHANGELOG (ID, AUTHOR, FILENAME, DATEEXECUTED, ORDEREXECUTED, MD5SUM, `DESCRIPTION`, COMMENTS, EXECTYPE, CONTEXTS, LABELS, LIQUIBASE, DEPLOYMENT_ID) VALUES ('1573236305687-36', 'wuyujia (generated)', 'changeLog.xml', NOW(), 36, '8:c810b4f042f26f841b90130d43f54642', 'createIndex indexName=idx_user_id, tableName=t_task', '', 'EXECUTED', NULL, NULL, '3.6.3', '3237223574')
02:20:30.765 [main] DEBUG liquibase.executor.jvm.JdbcExecutor - 1 row(s) affected
02:20:30.785 [main] DEBUG liquibase.executor.jvm.JdbcExecutor - Release Database Lock
02:20:30.791 [main] DEBUG liquibase.executor.jvm.JdbcExecutor - UPDATE pw_test.DATABASECHANGELOGLOCK SET `LOCKED` = 0, LOCKEDBY = NULL, LOCKGRANTED = NULL WHERE ID = 1
02:20:30.823 [main] INFO liquibase.lockservice.StandardLockService - Successfully released change log lock
...
到數(shù)據(jù)庫(kù)中查看, 可以看到數(shù)據(jù)表以及數(shù)據(jù)已經(jīng)被完整的遷移完成
后續(xù)待完善設(shè)計(jì)思考
- 后續(xù)會(huì)和SpringBoot項(xiàng)目進(jìn)行完整的的結(jié)合, 預(yù)計(jì)為通過(guò)接口傳入?yún)?shù)即可完成schema的創(chuàng)建. 并維護(hù)數(shù)據(jù)庫(kù)連接信息.
- 業(yè)務(wù)項(xiàng)目初始化時(shí)通過(guò)接口來(lái)獲取數(shù)據(jù)庫(kù)連接信息
- 在業(yè)務(wù)項(xiàng)目中集成動(dòng)態(tài)數(shù)據(jù)源模塊. 由此來(lái)完成動(dòng)態(tài)數(shù)據(jù)源的加載, 卸載, 以及訪問(wèn)數(shù)據(jù)庫(kù)時(shí)的動(dòng)態(tài)路由
-
給一張大致的設(shè)計(jì)圖.
image.png
結(jié)語(yǔ)
目前項(xiàng)目剛開始, 我也是剛剛接到要做的任務(wù). 所以先自己實(shí)踐一下. 為后面的項(xiàng)目開發(fā)做好準(zhǔn)備.
希望本文能簡(jiǎn)單的幫助到入坑同學(xué). 若本文有誤請(qǐng)幫忙指正.
愿我們?cè)絹?lái)越棒
本文為原創(chuàng), 轉(zhuǎn)贊請(qǐng)注明出處.