1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Spring Boot 2.x基礎(chǔ)教程:使用Flyway管理數(shù)據(jù)庫(kù)版本

        共 6754字,需瀏覽 14分鐘

         ·

        2021-01-14 16:31

        之前已經(jīng)介紹了很多在Spring Boot中使用MySQL的案例,包含了Spring Boot最原始的 JdbcTemplate(https://blog.didispace.com/spring-boot-learning-21-3-1/)、Spring Data JPA(https://blog.didispace.com/spring-boot-learning-21-3-4/)以及我們國(guó)內(nèi)最常用的MyBatis。同時(shí),對(duì)于一些復(fù)雜場(chǎng)景比如:更換Druid數(shù)據(jù)源,或是多數(shù)據(jù)源的情況也都做了介紹。

        不論我們使用哪一個(gè)具體實(shí)現(xiàn)框架,都離不開(kāi)對(duì)數(shù)據(jù)庫(kù)表結(jié)構(gòu)的管理。而這一類(lèi)管理一直都存在一個(gè)問(wèn)題:由于數(shù)據(jù)庫(kù)表元數(shù)據(jù)存儲(chǔ)于數(shù)據(jù)庫(kù)中,而我們的訪問(wèn)邏輯都存在于Git或其他代碼倉(cāng)庫(kù)中。Git已經(jīng)幫助我們完成了代碼的多版本管理,那么數(shù)據(jù)庫(kù)中的表該如何做好版本控制呢?

        今天我們就來(lái)介紹在Spring Boot中使用Flyway來(lái)管理數(shù)據(jù)庫(kù)版本的方法。

        Flyway簡(jiǎn)介

        Flyway是一個(gè)簡(jiǎn)單開(kāi)源數(shù)據(jù)庫(kù)版本控制器(約定大于配置),主要提供migrate、clean、info、validate、baseline、repair等命令。它支持SQL(PL/SQL、T-SQL)方式和Java方式,支持命令行客戶端等,還提供一系列的插件支持(Maven、Gradle、SBT、ANT等)。

        官方網(wǎng)站:https://flywaydb.org/

        本文對(duì)于Flyway的自身功能不做過(guò)多的介紹,讀者可以通過(guò)閱讀官方文檔或利用搜索引擎獲得更多資料。下面我們具體說(shuō)說(shuō)在Spring Boot應(yīng)用中的應(yīng)用,如何使用Flyway來(lái)創(chuàng)建數(shù)據(jù)庫(kù)以及結(jié)構(gòu)不一致的檢查。

        動(dòng)手試試

        下面我們先預(yù)設(shè)一個(gè)開(kāi)發(fā)目標(biāo):

        1. 假設(shè)我們需要開(kāi)發(fā)一個(gè)用戶管理系統(tǒng),那么我們勢(shì)必要設(shè)計(jì)一張用戶表,并實(shí)現(xiàn)對(duì)用戶表的增刪改查操作。
        2. 在任務(wù)1的功能完成之后,我們又有一個(gè)新需求,需要對(duì)用戶表增加了一個(gè)字段,看看如何實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)表結(jié)構(gòu)的更改。

        目標(biāo) 1 的實(shí)現(xiàn)

        第一步:創(chuàng)建一個(gè)基礎(chǔ)的Spring Boot項(xiàng)目,并在pom.xml中加入Flyway、MySQL連接和數(shù)據(jù)訪問(wèn)相關(guān)的必要依賴(這里選用spring-boot-starter-jdbc作為例子)

        <dependencies>
        ????<dependency>
        ????????<groupId>org.springframework.bootgroupId>
        ????????<artifactId>spring-boot-starter-webartifactId>
        ????dependency>

        ????<dependency>
        ????????<groupId>org.springframework.bootgroupId>
        ????????<artifactId>spring-boot-starter-jdbcartifactId>
        ????dependency>

        ????<dependency>
        ????????<groupId>mysqlgroupId>
        ????????<artifactId>mysql-connector-javaartifactId>
        ????dependency>

        ????<dependency>
        ????????<groupId>org.flywaydbgroupId>
        ????????<artifactId>flyway-coreartifactId>
        ????dependency>

        ????<dependency>
        ????????<groupId>org.projectlombokgroupId>
        ????????<artifactId>lombokartifactId>
        ????????<scope>providedscope>
        ????dependency>

        ????<dependency>
        ????????<groupId>org.springframework.bootgroupId>
        ????????<artifactId>spring-boot-starter-testartifactId>
        ????????<scope>testscope>
        ????dependency>dependencies>

        第二步:按Flyway的規(guī)范創(chuàng)建版本化的SQL腳本。

        • 在工程的src/main/resources目錄下創(chuàng)建db目錄,在db目錄下再創(chuàng)建migration目錄
        • 在migration目錄下創(chuàng)建版本化的SQL腳本V1__Base_version.sql

        DROP?TABLE?IF?EXISTS?user?;
        CREATE?TABLE?`user`?(
        ??`id`?bigint(20)?NOT?NULL?AUTO_INCREMENT?COMMENT?'主鍵',
        ??`name`?varchar(20)?NOT?NULL?COMMENT?'姓名',
        ??`age`?int(5)?DEFAULT?NULL?COMMENT?'年齡',
        ??PRIMARY?KEY?(`id`)
        )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;

        注意:如果你不想將SQL腳本放到其他目錄,可以用spring.flyway.locations參數(shù)來(lái)配置。這里不同于1.x版本的配置項(xiàng)flyway.locations

        第三步:根據(jù)User表的結(jié)構(gòu),編寫(xiě)對(duì)應(yīng)的實(shí)體定義


        @Data
        @NoArgsConstructor
        public?class?User?{

        ????private?Long?id;
        ????private?String?name;
        ????private?Integer?age;

        }

        第四步:編寫(xiě)用戶操作接口和實(shí)現(xiàn)


        public?interface?UserService?{

        ????/**
        ?????*?新增一個(gè)用戶
        ?????*
        ?????*?@param?name
        ?????*?@param?age
        ?????*/

        ????int?create(String?name,?Integer?age);

        ????/**
        ?????*?根據(jù)name查詢用戶
        ?????*
        ?????*?@param?name
        ?????*?@return
        ?????*/

        ????List?getByName(String?name);

        ????/**
        ?????*?根據(jù)name刪除用戶
        ?????*
        ?????*?@param?name
        ?????*/

        ????int?deleteByName(String?name);

        ????/**
        ?????*?獲取用戶總量
        ?????*/

        ????int?getAllUsers();

        ????/**
        ?????*?刪除所有用戶
        ?????*/

        ????int?deleteAllUsers();

        }

        @Service
        public?class?UserServiceImpl?implements?UserService?{

        ????private?JdbcTemplate?jdbcTemplate;

        ????UserServiceImpl(JdbcTemplate?jdbcTemplate)?{
        ????????this.jdbcTemplate?=?jdbcTemplate;
        ????}

        ????@Override
        ????public?int?create(String?name,?Integer?age)?{
        ????????return?jdbcTemplate.update("insert?into?USER(NAME,?AGE)?values(?,??)",?name,?age);
        ????}

        ????@Override
        ????public?List?getByName(String?name)?{
        ????????List?users?=?jdbcTemplate.query("select?*?from?USER?where?NAME?=??",?(resultSet,?i)?->?{
        ????????????User?user?=?new?User();
        ????????????user.setId(resultSet.getLong("ID"));
        ????????????user.setName(resultSet.getString("NAME"));
        ????????????user.setAge(resultSet.getInt("AGE"));
        ????????????return?user;
        ????????},?name);
        ????????return?users;
        ????}

        ????@Override
        ????public?int?deleteByName(String?name)?{
        ????????return?jdbcTemplate.update("delete?from?USER?where?NAME?=??",?name);
        ????}

        ????@Override
        ????public?int?getAllUsers()?{
        ????????return?jdbcTemplate.queryForObject("select?count(1)?from?USER",?Integer.class);
        ????}

        ????@Override
        ????public?int?deleteAllUsers()?{
        ????????return?jdbcTemplate.update("delete?from?USER");
        ????}

        }

        這里主要介紹Flyway的應(yīng)用,所以采用這種比較簡(jiǎn)單的編寫(xiě)方式,實(shí)際項(xiàng)目應(yīng)用中,還是推薦MyBatis的具體操作實(shí)現(xiàn)。

        第五步:編寫(xiě)測(cè)試用例


        @Slf4j
        @SpringBootTest
        public?class?Chapter311ApplicationTests?{

        ????@Autowired
        ????private?UserService?userSerivce;

        ????@Test
        ????public?void?test()?throws?Exception?{
        ????????userSerivce.deleteAllUsers();

        ????????//?插入5個(gè)用戶
        ????????userSerivce.create("Tom",?10);
        ????????userSerivce.create("Mike",?11);
        ????????userSerivce.create("Didispace",?30);
        ????????userSerivce.create("Oscar",?21);
        ????????userSerivce.create("Linda",?17);

        ????????//?查詢名為Oscar的用戶,判斷年齡是否匹配
        ????????List?userList?=?userSerivce.getByName("Oscar");
        ????????Assertions.assertEquals(21,?userList.get(0).getAge().intValue());

        ????????//?查數(shù)據(jù)庫(kù),應(yīng)該有5個(gè)用戶
        ????????Assertions.assertEquals(5,?userSerivce.getAllUsers());

        ????????//?刪除兩個(gè)用戶
        ????????userSerivce.deleteByName("Tom");
        ????????userSerivce.deleteByName("Mike");

        ????????//?查數(shù)據(jù)庫(kù),應(yīng)該有5個(gè)用戶
        ????????Assertions.assertEquals(3,?userSerivce.getAllUsers());
        ????}

        }

        注意由于Spring Boot 2.4應(yīng)用的junit版本與之前Spring Boot 1.x版本中的不同,因此單元測(cè)試的編寫(xiě)略有區(qū)別,有興趣的讀者可以分別查看之前介紹文章和這篇文章中的單元測(cè)試的區(qū)別,這里就不細(xì)說(shuō)了。

        第六步:運(yùn)行上面編寫(xiě)的單元測(cè)試,驗(yàn)證一下效果。

        不出意外,單元測(cè)試運(yùn)行ok的話

        連上數(shù)據(jù)庫(kù)看看。此時(shí)應(yīng)該多出了這兩張表:

        • user表就是我們維護(hù)在SQL腳本中要?jiǎng)?chuàng)建的表
        • flyway_schema_history表是flyway的管理表,用來(lái)記錄在這個(gè)數(shù)據(jù)庫(kù)上跑過(guò)的腳本,以及每個(gè)腳本的檢查依據(jù)。這樣每次應(yīng)用啟動(dòng)的時(shí)候,就可以知道哪個(gè)腳本需要運(yùn)行,或者哪個(gè)腳本發(fā)生了變動(dòng),運(yùn)行基礎(chǔ)可能不對(duì),造成數(shù)據(jù)結(jié)構(gòu)的混亂而阻止運(yùn)行。

        目標(biāo) 2 的實(shí)現(xiàn)

        有了上面的基礎(chǔ)之后,我們來(lái)說(shuō)說(shuō)后續(xù)要做表結(jié)構(gòu)的表變動(dòng)該怎么操作,這也是之前讀者出現(xiàn)問(wèn)題最多的情況,所以在2.x版本教程中特地講一講。

        首先,大家在開(kāi)始使用Flyway之后,對(duì)于數(shù)據(jù)庫(kù)表接口的變更就要關(guān)閉這幾個(gè)途徑:

        1. 直接通過(guò)工具登錄數(shù)據(jù)去修改表結(jié)構(gòu)
        2. 已經(jīng)發(fā)布的sql腳本不允許修改

        正確的表結(jié)構(gòu)調(diào)整途徑:在flyway腳本配置路徑下編寫(xiě)新的腳本,啟動(dòng)程序來(lái)執(zhí)行變更。這樣可以獲得幾個(gè)很大的好處:

        1. 腳本受Git版本管理控制,可以方便的找到過(guò)去的歷史
        2. 腳本在程序啟動(dòng)的時(shí)候先加載,再提供接口服務(wù),一起完成部署步驟
        3. 所有表結(jié)構(gòu)的歷史變遷,在管理目錄中根據(jù)版本號(hào)就能很好的追溯

        下面根據(jù)一個(gè)實(shí)際需求來(lái)具體操作下。假設(shè)我們現(xiàn)在想對(duì)User表增加一個(gè)字段:address,用來(lái)存儲(chǔ)用戶的通訊地址,那么我們就需要這樣操作實(shí)現(xiàn)。

        第一步:創(chuàng)建腳本文件V1_1__alter_table_user.sql,并寫(xiě)入增加address列的語(yǔ)句


        ALTER?TABLE?`user`?ADD?COLUMN?`address`?VARCHAR(20)?DEFAULT?NULL;

        對(duì)于腳本文件名的基本規(guī)則是:版本號(hào)__描述.sql。當(dāng)然如果你有更細(xì)致的要求,那么可以做更細(xì)致的文件名規(guī)劃,具體細(xì)節(jié)讀者可以查閱文末參考資料中的官方文檔獲取。

        第二步:再次執(zhí)行單元測(cè)試,在控制臺(tái)中可以看到如下日志:


        2021-01-11?16:58:12.025??INFO?37330?---?[???????????main]?o.f.c.i.database.base.DatabaseType???????:?Database:?jdbc:mysql://localhost:3306/test?(MySQL?8.0)
        2021-01-11?16:58:12.063??INFO?37330?---?[???????????main]?o.f.core.internal.command.DbValidate?????:?Successfully?validated?2?migrations?(execution?time?00:00.020s)
        2021-01-11?16:58:12.075??INFO?37330?---?[???????????main]?o.f.core.internal.command.DbMigrate??????:?Current?version?of?schema?`test`:?1
        2021-01-11?16:58:12.082??INFO?37330?---?[???????????main]?o.f.core.internal.command.DbMigrate??????:?Migrating?schema?`test`?to?version?"1.1?-?alter?table?user"
        2021-01-11?16:58:12.113??INFO?37330?---?[???????????main]?o.f.core.internal.command.DbMigrate??????:?Successfully?applied?1?migration?to?schema?`test`?(execution?time?00:00.045s)

        再查看一下數(shù)據(jù)中國(guó)的內(nèi)容:

        如果你還沒(méi)有體會(huì)到引入Flyway對(duì)給我們的表結(jié)構(gòu)帶來(lái)的好處的話,不妨也留言分享下你們的管理方式吧!

        更多本系列免費(fèi)教程連載「點(diǎn)擊進(jìn)入?yún)R總目錄」(https://blog.didispace.com/spring-boot-learning-2x/)

        代碼示例

        本文的相關(guān)例子可以查看下面?zhèn)}庫(kù)中的chapter3-11目錄:

        • Github:https://github.com/dyc87112/SpringBoot-Learning/
        • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

        如果您覺(jué)得本文不錯(cuò),歡迎Star支持,您的關(guān)注是我堅(jiān)持的動(dòng)力!

        參考資料

        • Spring Boot中使用Flyway來(lái)管理數(shù)據(jù)庫(kù)版本(https://blog.didispace.com/spring-boot-flyway-db-version/)
        • Flyway官方文檔

        往期推薦

        因脈脈上的匿名消息,拼多多員工被開(kāi)除了!

        你一定需要知道的高階JAVA枚舉特性!

        盤(pán)點(diǎn) IDEA2020.3 那些炫酷的插件,超級(jí)好用的那種

        不到 20 人的 IT 公司該去嗎?

        文件上傳的單元測(cè)試怎么寫(xiě)?

        Github上看到的4個(gè)好玩的開(kāi)源項(xiàng)目



        瀏覽 77
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            双乳奶水饱满少妇呻吟电影 | 国产精品一级淫荡精品录像 | 中文字幕人妻熟女一区二区三区电影 | 国产无码av | 色情ⅩXXX日本护士 | 免费看黄的网站在线观看 | 国产福利第一页 | 做爱在线观看免费观看高清 | 新超碰97 | 三级片网站大全 |