2018年7月29日 星期日

MySQL DBA的資料安全課題


資料庫是大多數應用系統的核心,因此,資料庫安全常是各種場合一再被拿出來探討的議題.但是您知道嗎?要為大部份資料庫安全問題可歸責於資料的擁有者或管理者而且當管理者或架構設計者有採取適當的防護措施時這些問題都是可以避免或補會造成資料丟失或露的人有兩大類:
1.      自己人,這包括:
甲、在操作系統上幹活的系統工程師:
和任何跑在作業系統上的應用程式一樣,MySQL資料庫管理系統佔用伺服器的記憶體空間資料也有會長久存於磁碟中.系統工程師可能對資料庫幹的事包括:
                            i.                mysqld程序.
                          ii.                誤刪某些資料庫檔案,如mycnf之類的設定檔或表空間檔或者binlog之類的日誌檔,甚至是整個資料目
l   由於系統工程師會擁有作業系統的root帳戶,這類的誤刪是沒法完要減少這種狀發生的機會可以在目錄層的權限不給privilege mask 750(擁有者有全部的權限,同一組的用戶可看可執行但不能寫,其他作業系統的用戶什麼都不能做)以上的權限,以防制這類的失誤
l   另外 MySQL的高可用架構(例如group replication或半同步複製等)在多台伺服器上執行由多個資料庫所構成的不會掉資料的同步因此,當有人對一個資料庫做些蠢事把整個資料庫都殺了時,還有其他的資料庫存有一份一樣的資料可以將它由別台伺服器全部抄回來
l   當然,資料庫的備份是救回資料的最後手段不過,想要不掉資料的把資料庫整個都救回來,除了完整的備份外binlog一定要全整的保留下來.所以如果資料庫伺服器有多個磁碟機,建binlog存放於和MySQL的資料目不同的磁機上以免刪資料目binlog會一併刪除
乙、擁有root或資料庫管理權限的資料庫管理師或某些schema管理權限的資料操作者,一般所指的DBA就是這類人,廣義來講,也包括某些應用程式開發者,他們能登入資料庫管理系統,對存資料的表或整個資料庫層級的物(如帳號權限等)件做各種操作,他們可能對資料庫造成的問題有:
l   刪庫跑路是DBA所可能做的最的事別以為老手不會幹這種事,越是老長越可能陰溝裏翻,這包括刪掉整個schema、整個表、或動到是某些不該刪或改的資料.比較好的做法是事先防範.MySQL企業版的用戶可以用資料庫防火牆,SQL命令執行前檢查SQL命令檔下由未經允許的前端所下的刪除整個表或schema,或是沒有where條件的deleteupdate之類的SQL命令全都由防火檔下(在最佳實務中這類的命令不可以隨意下,必需在特定機器、特定時間、以一個事先包裝好的程式去執行)如果要做到更精細的檢查,可在使用者介面之上加一個審核機制,在SQL命令送到資料庫前先檢查SQL的內容,不合規定的SQL命令都被審核系統擋下或發出警告.今年COSCUP的開源資料庫系列的第四場(第一天下午一點開始)中周彥偉介紹他所開Inception開源審計軟體就是一個具體的實踐,有興趣進一步了解的朋友請把握這個機會到開源資料庫系列的研討會和MySQL的技術大牛們聊聊.
2.      居心不良的駭客:
這是大部份安全防護系統想要防備的對象,這些人入侵的手段包括網路攻擊、密碼力試密碼、掛在網路上竊取傳輸的資料、入侵作業系統將整個目錄或表空間檔案抄走、或者自備份出來的資料中讀取資料等等手法.
新版MySQL大幅加強了安控能力,再配MySQL企業版的各種安控插件,例如加密插件、透明表空間加密插件、核插件、和可利用LDAP之類登入機制的安控插件等,使我們有機會打造出一套乎滴水不漏的資訊系統.當然,再強的堡壘經長時間的攻擊總有漏出破綻的時候,此時MySQL企業監控就能發揮預防重於治療的效果,隨時監看系統找出在管理及配置上可能有安全漏的地方,在這些漏洞還沒光前,讓我們能及時將漏洞堵住.另外,Oraclesupport服務會在MySQL軟體上的漏洞被發現時及時推出修正版解決這些問題,MySQL企業版的用戶可以將企業監控和Oracle support連線,在安全漏發佈的第一時間收到通知,並以一鍵式更新的方式更新資料庫版本,及時將資料庫軟體的安全漏洞補上.
有興趣了解MySQL安控機制的朋友,請把握我在COSCUP第二天下午240IB201如何善用MySQL打造固若金湯的系統研討會.

2017年2月6日 星期一

MySQL支援JSON文件面面觀(之二)

這篇文章是MySQL支援JSON文件系列的第二章,承接上一篇 - 詳解新世代MySQL如何支持NoSQL應用開發 ,它的重點放在MySQL前端的應用層如何使用資料庫中的JSON文件,您如果需要了解MySQL在5.7版中有那些功能支援JSON,可回到上一篇文章中找答案.

新增mysqlx插件讓資料庫能使用X Protocol

MySQL自第一個正式發行版(5.7.9)就加上了新的新的JSON資料型別和JSON涵式,往支援NoSQL的路上邁了一大步。但是如果只能透過SQL介面開發NoSQL應用,還是顯得有些削足適履,我們要的是能完全脫離SQL的影子,直接以NoSQL的方式和資料庫互動。所以MySQLng專案在原有的(預設使用3306端口)SQL介面之外(如下圖2.的部份)再開發了一個X Plugin,使應用端能透過X Plugin預設的33060端口使用X Dav API,直接對MySQL資料庫的JSON文件做增刪改查等操作。所以,現在的MySQL不僅是說SQL語言的關聯式資料庫,也是一個自前端到後端完整支援NoSQL的資料庫。事實上,在MySQL 5.6以後,它就能透過Memcached的介面以key-value查詢的方式和資料庫互動(MySQL memcache的預設端口為11211),當查詢方式不涉及複雜的JOIN和子查詢時,藉由這個介面繞過SQL層,少了處理SQL的解析和優化的工作負荷,能使性能大輻提升,這也是以一個NoSQL的方式和資料庫互動。現在又支援了JSON文件介面,使我們的NoSQL應用能有更高的可攜性。

MySQL X Plugin的安裝

MySQL 5.7一開始並不具備處理X Protocol的能力,要讓MySQL能支援X Protocol必需先裝MySQL X 插件,在安裝X插件之前MySQL就只能使用(聽3306)SQL介面,和您熟悉的傳統MySQL沒什麼差異(之所以必需設定插件才能帶出X Protocol應該主要是基於降低複雜度和bug出現的機會的考量)。
MySQL自 5.7.12版以後以,可在軟體包的lib/plugin目錄中,找到一個名為mysqlx.so(Windows版是mysqlx.dll)的檔案,這就是X插件的程式庫。透過mysql客戶端程式,或MSQL Shell均可以安裝mysqlx插件:
  • 以MySQL客戶端程式安裝MySQL X插件的命令如下(不一定要用root帳戶,以任何對mysql.plugin表有插入權的用戶都可以):

  • 以MySQL Shell安裝MySQL X插件,在安裝好MySQL Shell的環境中:


  • 您可以在mysql客戶端程式下以下命令,在回應的清單中找mysqlx插件是否在其中,以確認MySQL的X插件是否己裝好:


當X插件安裝好了,您就可以準備X protocol的客戶端,正式將MySQL當成一個全然的文件型資料庫。

MySQL Shell - 操作MySQL文件資料的好幫手

正如同mysql客戶端程式為SQL介面(默認3306端口)提供了方便操作的工具一樣,MySQL Shell也為各類使用者(DBA,開發者…)提供一個好用的工具,以NoSQL的方式對資料庫直接操作資料,管理資料庫或做臨時性的查詢。 

 

  • 取得及安裝MySQL Shell
MySQL Shell不在MySQL軟體包內,需要單獨自http://dev.mysql.com/downloads下載其軟體包,
如下圖所示,在MySQL的下載網頁的左邊的導航列中可選到MySQL Shell的選項。有一點先請讀者們注意的是,目前(2016年底),MySQL Shell還是處於第三個beta(DMR)版,在它正式發行之前或許以後會有一些變動或者會加上更多功能。



進入下載網頁後可依MySQL Shell的執行環境選擇合適的版本


 如果您選擇ZIP Archive或 tar 包,解開壓縮檔,不需安裝就可以使用mysqlsh程式,但要設定環境的路徑變數,將MySQL Shell目錄下的bin子目錄的路徑加到PATH變量中以方便執行MySQL shell。依操作系統的不同,您也可以選擇rpm,deb或msi安裝包,這些安裝包在執行時可以解開其軟體,並且加上路徑環境變數或將文件放到適當的位置(例如/user/bin),以方便執行。
  • 執行MySQL Shell
在操作系統選單中選擇MSQL Shell或終端機命令模式下執行msqlsh進入MySQL Shell。



$ mysqlsh

Welcome to MySQL Shell 1.0.4 Development Preview

Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type '\help' '\h' or '\?' for help

Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
mysql-js>

  • 和mysql客戶端程式一樣,mysqlsh命令也可以加上參數。例如指定以什麼帳戶連入那個資料庫、對話的模式(X session, node session,或classic session)、語法(Javacript,Python,或SQL)、或內含批量作業命令的文件,如果要了解有那些選項,可以用--help或-h選項列示mysqlsh所選項和它們的說明:

$ mysqlsh –u -h -p

看起來是不是很熟悉?或是以下列命令指定URI同樣能登入資料庫:


$ mysqlsh –uri root:<pasword>@localhost:33060/<database>

  • MySQL Shell有三種對話(Session)模式:

    – X session,這是預設的對話模式,這個模式無法執行SQL命令,只能下JavaScript或Python的命令,MySQL的X Session以後可以發展成同時支援多個資料庫連線和資料庫分片
    – Node session, 能執行SQL, JavaScript或Python的命令,但是Node Session只能和一個資料庫連線,以後也不會擴充成同時連多個資料庫。
    – Classic session,不和使用x protocol,能用 SQL命令,和傳統的mysql介面類似,但開發者能用的介面有限,不支援NoSQL 的CRUD操作,也不能對collection操作。 
    • MySQL shell 可以有三種命令模式供您選擇:
    – JavaScript : 默認的命令模式,也可以在mysqlsh命令加上--js選項進入JavaScript模式,提示符為mysql-js> ,能接受JavaScript的命令。
    – Python : 命令加上--py選項進入Python模式,提示符為mysql-py>,能使mysqlsh接受Python命令,MySQL Shell的指令如下:

    $ mysqlsh –u -h -p --py

    – SQL:要能在MySQL Shell下SQL命令對話模式必需在MySQL Shell指定classic 或node session,再於命令行加上--sql選項,可進入SQL模式,這個模式的介面和傳統的mysql客戶端的操作方式機乎完全相同,一樣是SQL命令,進入此模式的MySQL  Shell命令為:

    $ mysqlsh –u –p –h --classic --sql;

    –    如同在mysql客戶端程式下鍵入help一樣,查mysql客戶端程式的命令,進入MySQL Shell後可以\?或\help查mysqlsh的操作命令,它所有的mysqlsh命令都以\開頭,例如\c是建立資料庫連線。

    在MySQL Shell操作JSON文件

     MySQL Shell為JSON文件的操作提供所需要的命令集,這些命令都是實施了X Dav API的介面而開發出來的,MySQL Shell的X Dav API的詳情請參考http://dev.mysql.com/doc/dev/mysqlsh-api-javascript/
    在此以JavaScript命令模式為例,說明以mysqlsh 在JSON文件生命週期中的各種操作:

    – 建立Schema和更換Schema:
    MySQL Shell有幾個預設的物件,例如session, db…,您可在進入以後鍵入session查 看目前連線對話的內容,下例顯示目前的對話模式為X Session,以root帳戶連線位於127.0.0.1,使用33060端口:


    mysql-js> session
    <XSession:root@localhost:33060>

    在session物件上建立schema的函式,以下範例建一個名為”mydemo的Schema:


    mysql-js> session.createSchema('mydemo')
    <Schema:mydemo>
     
    上列命令相當於在mysql命令程式下達CREATE DATABASE mydemo。
    查查看我們之前建立的mydemo schema是否存在?目前資料庫有那些schema?


    [
        <Schema:information_schema>,
        <Schema:acmug>,
        <Schema:chtl>,
        <Schema:ci17h1>,
        <Schema:my_test>,
        <Schema:mydemo>,
        <Schema:mysql>,
        <Schema:mysqlnews>,
        <Schema:performance_schema>,
        <Schema:sakila>,
        <Schema:sys>,
        <Schema:test_schema>,
        <Schema:wordpress>,
        <Schema:world>,
        <Schema:world_x>
    ]
     
    更換使用中的schema,則以mysqlsh命令\use(或者\u)就行了,例如:


    mysql-js> \u mydemo

    Schema `mydemo` accessible through db.
     
    當然,進入mysqlsh時所指定的參數中也可以指定建立連線後要用那一個database(schema),例如:



    $ mysqlsh --uri root@127.0.0.133060/mydemo
    Creating an X Session to root@127.0.0.133060/mydemo
    Enter password********
    Default schema `mydemo` accessible through db.

    Welcome to MySQL Shell 1.0.4 Development Preview

    Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.

    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.

    Type '\help' '\h' or '\?' for help.

    Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
    mysql-js>

     

    上例中登入MySQL Shell的參數中,URI的最後一段指定用mydemo為連線的預設schema,進入mysqlsh後回應的內容中有一段"default schema `mydemo` accessible through db"說明了這一點,進入了mysqlsh後還可以鍵入db查證一下mysqlsh的默認物件db是否放在mydemo上:


    mysql-js> db
    <Schema:mydemo>

    – 在當前schema下操作Collection和Document:
    在說明mysqlsh對collection的操作前,先簡單的說明Document資料庫的基本觀念:
    一個collection是一堆JSON文件的集,相當於關聯式資料庫的表,JSON Document代表(或描述)一個事情或是一筆記錄,相當於關聯式資料庫在表中的一個row。
    • 建立Collection:
    - 透過預設的db物件之createCollection函式,在目前所在的schema之下可以建立collection,而db物件代表當下的session所位在的schema,下例為建一個名為collection1的Collection


    mysql-js> db.createCollection('collection1');
    <Collection:collection1>

    - 也可以在參數中加上schema名稱,這個功能使用戶可以在任何schema下為mydmo建collection:


    mysql-js> db.createCollection('mydemo.mycollection');

    只要有權限在指定的schema下加表的帳戶,都可以在位於任何資料庫時執行createCollection以參數 的方式為其他的schema.加上collection。
    • 加上Document:
    - 有了collection以後,可調用該colleciton 物件的add函式將JSON文件加入collection中:


    mysql-js> db.collection1.add({"name": {"lastname":"Tu","firstname":"Ivan"},"height": 180,"weight": 68,"talents" ["swimming","dancing","programming"]});

    Query OK 1 item affected (0.02 sec)

      - 再加一個文件:


    mysql-js> db.collection1.add({"name" {"lastname" "Wang""firstname" "James"}"height" 170"weight" 80"date of birth""1990-12-30""talents" ["make money""dancing"]});

    Query OK 1 item affected (0.00 sec)
     
    • 現在查現在己加了多少文件到collection1:


    mysql-js> db.collection1.find();

    [
        {
            "_id" "64b87d23a162d211645db86b2339c6c8"
            "date of birth" "1990-12-30"
            "height" 170
            "name" {
                "firstname" "James"
                "lastname" "Wang"
            }
            "talents" [
                "make money"
                "dancing"
            ]
            "weight" 80
        }
        {
            "_id" "b85d1476a062d211645db86b2339c6c8"
            "height" 180
            "name" {
                "firstname" "Ivan"
                "lastname" "Tu"
            }
            "talents" [
                "swimming"
                "dancing"
                "programming"
            ]
            "weight" 68
        }
    ]
    1     documents in set (0.00 sec)

    – 如果仔細看上列的輸出您可以發現幾個有趣的現象:
      •  雖然前面加Document時,並未在文件中加上”_id”物件,所有的文件都自動加上一個名為”_id”的物件,存放自動產生的uuid值。
      •  文件的結構能自由定義不像關聯式資料庫需事先定一個固定的文件結構,上例中第二個文件比第一個文件多了一個”data of birth”物件,”talents”陣列的數目也比第一個少了一個,這代表JSON文件不需事先定義資料結構,物件名稱(identifier)就能表達JSON文件內各物件的含義。
    – 另一邊,由mysql客戶端程式查看看資料庫在引擎層面發生了什麼事?


    mysql> show create table collection1\G

    *************************** 1. row ***************************
           Table collection1
    Create Table CREATE TABLE `collection1` (
      `doc` json DEFAULT NULL
      `_id` varchar(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`'$._id'))) STORED NOT NULL
      PRIMARY KEY (`_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    1 row in set (0.00 sec)
     
    顯示每一個collection都對應一個InnoDB的表,表有兩個欄位 – doc欄位的資料型別是json,另一個_id欄位是由json_extract函式生成的STORED(自函式算出值實際存放於表中,以後查詢時不需再算一次)欄位,它的值是在doc欄位中找名為_id的物件之值,並且將主鍵加在這個_id欄位上。
      – 我們也能為collection的weight加上(非唯一)次要索引:


    mysql-js> db.collection1.createIndex("weightIdx").field("weight""INTEGER"false).execute();

    Query OK (0.06 sec)
     
      – 另一方面,加上索引後在InnoDB表結構如下所示:

    mysql> show create table collection1\G

    *************************** 1. row ***************************
           Table collection1
    Create Table CREATE TABLE `collection1` (
      `doc` json DEFAULT NULL,
      `_id` varchar(32) GENERATED ALWAYS AS (json_unquote(json_extract(`doc`,'$._id'))) STORED NOT NULL,
      `$ix_i_2D8FA3E83FC26B3A572C94D67A6F56CAC0CA1EAB` int(11) GENERATED ALWAYS AS (json_extract(`doc`'$.weight')) VIRTUAL,
      PRIMARY KEY (`_id`),
      KEY `weightIdx` (`$ix_i_2D8FA3E83FC26B3A572C94D67A6F56CAC0CA1EAB`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
    1 row in set (0.00 sec) 


    由此證明X Dav API會因為這個collection1.createIndex函式會在資料庫的collection1表上多加了一個名為$ix_i_ 的虛擬欄位,其值是由json_extract文件中的weight物件取出的值所構成的,並且在其上加了索引-weightIdx
      – 您也可以對collection進行條件查詢,甚至動能挷定值於條件中,下例為自Collection找出weight > 70的文件

    mysql-js> db.collection1.find("weight > kg").bind("kg"70);

    [
        {
            "_id" "64b87d23a162d211645db86b2339c6c8"
            "date of birth" "1990-12-30"
            "height" 170
            "name" {
                "firstname" "James"
                "lastname" "Wang"
            }
            "talents" [
                "make money"
                "dancing"
            ]
            "weight" 80
        }
    ]
    1 document in set (0.00 sec)

    由於查詢條件裡有weight物件,執行計畫可能會用到前一段所建weightIdx的索引。
      – 也可以指定要由查詢的結果中只傳回指定的物件,下例顯示不需要看整份JSON文件,只要傳回name和height物件


    mysql-js> db.collection1.find("weight > 70").fields(["name","height"]);

    [
        {
            "height" 170,
            "name" {
                "firstname": "James",
                "lastname": "Wang"
            }
        }

    1 document in set (0.00 sec)

      – 最後,不需要這個collection時,可以刪除這個collection,drop collection得用session物件的dropCollection函式,它的必要參數有兩個 – schema名稱和collection名稱,刪除後該schema就查不到該collection了
     
    mysql-js> session.dropCollection("mydemo","collection1");

    Query OK (0.02 sec)

    mysql-js> db.getCollections()
    [
    ]
        一如mysql客戶端程式可執行SQL脚本以進行批次作業,我們也可以編一套JavaScript或Python脚本在MySQL Shell 執行批次作業,範例如下:

    建立一個名為Transaction-sample.js 的脚本, 這個脚本會執行1000次迴圈,每個迴圈插入5個JSON文件,每個迴圈都是一個交易,也就是一個易交提交5個JSON文件
     


    //匯入mysqlx模組,組區域變數-mysqlx指向mysqlx物件,mysqlxgetSession函式建立資料庫連線
    var mysqlx = require('mysqlx').mysqlx;
    // 建立資料庫連線
    var session = mysqlx.getSession( {
      host: 'localhost', port: 33060,
      dbUser: 'root', dbPassword: '>password<' } );
    // 移到my_test schema
    var db = session.getSchema('my_test');
    // my_test schema之下建立一個新的 collection – mycollection,
    //如果該collection在此之前己存在則先drop
    session.dropCollection('my_test','mycollection');
    db.createCollection('mycollection');
    //取一個collection物件 – myColl,JSON文件均以其add函式加入collection該中
    var myColl = db.getCollection('mycollection');
    var iter;
    // 迴圈運行1000,每次先以session.startTransaction()定事務的起始點
    // 迴圈插入5個文件,如果運行中間有錯誤或被強制中斷,
    //之前提交的交易會存在資料庫中,做到中間的交易會回滾
    //所以collection中存在的文件數會是5的倍數(實現易交易的資料完整性),
    //由此證明X Dav API是支持交易和數據完整性的
    // 最後以session.commit()結束並提交交易
    try {
      for (iter = 0; iter < 1000; iter++) {
        session.startTransaction();
        myColl.add({name: 'Sunny', age: 23, height: 1.3, weight: 73.3}).execute();
        myColl.add({name: 'Albert', age: 24, height: 1.4, weight: 74.3}).execute();
        myColl.add({name: 'Bred', age: 25, height: 1.5, weight: 75.3}).execute();
        myColl.add({name: 'Connie', age: 26, height: 1.6, weight: 76.3}).execute();
        myColl.add({name: 'David', age: 27, height: 1.7, weight: 77.3}).execute();
      // Commit the transaction if everything went well
        session.commit();
        print('Data inserted successfully.\n');
      }
    }
    catch (err) {
      // 如果有錯誤,則回滾未完成的交易
      session.rollback();
      // Printing the error message
      print('Data could not be inserted: ' + err.message);
    }

    將上列脚本送到MySQL Shell執行,結果如下:


    $ mysqlsh -f transaction-sample.js

    Data inserted successfully.
    Data inserted successfully.
    Data inserted successfully.

      最後會出現1000次Data inserted successfully。
    登入查看執行的結果:


    mysql-js> db.mycollection.find()

    [
        {
            "_id": "ffe5ac80c362d2114072b86b2339c6c8",
            "age": 24,
            "height": 1.4,
            "name": "Albert",
            "weight": 74.3
        },
        {
            "_id": "fffaab7ec362d2114072b86b2339c6c8",
            "age": 27,
            "height": 1.7,
            "name": "David",
            "weight": 77.3
        }
    ]
    5000 documents in set (0.00 sec)
      

    上列範例中建資料庫連線不是用Connection物件,而是Session物件,在Connection之上引進Session的概念,這也透露著X Dav API將朝向支援一個Session可能包含多個Connection,每個Connection分別連到不同的資料庫,而能支援資料庫分片(data shard)的方向發展



    Connector實施X Dav API支援多種應用程式以JSON和MySQL互動

    文行到此,整份MySQL as a Document Store的技術拼圖只剩最後一片- 應用層能透過X Protocol,執行CRUD的函式,直接操作位於資料庫內的JSON文件。如下圖4.所示,MySQL在各種新版本的應用程式連結器(包括Connector/J, Connectior/NET, Connectior/C++等)加上了新的支援X protocol的模組,以,讓應用程式能直接調用這些模組中實現X Dav API的介面的函式,透過X protocol直接使用和更新資料庫的JSON文件。這些連結器還在持續完善中,目前支援X Protocol的連結器有Connector/J,Connector/Python,Connector/NET,Connector/C++ 和Connector/Nodejs.

     


    本文的範例以一個Java應用程式 - MySQLStore.java(該Java程式會插入三個JSON文件到mycollection中,並找出name為”Sakila”,age小於20的犬文件,並列示出來)為您演示如何使用Connector/J的X Dav API接口。以下列範例說明這個Java程式的開發和執行環境的準備步驟,供您參考。
    • 準備JSON文件資料庫的Java開發環境
    要開發及執行MySQLStore Java程式除了要有JDK,還要在合適的Java驅動器,Connector/J 6.0以後的版本才能支援JSON文件資料庫,能要到MySQL的軟體下載網頁(網址是dev.mysql.com/downloads/Connector/J/),點選”Development Releases”頁籤,才能找到Connector/J 6.0.x版的.jar包。下載這裡的壓縮檔後做這三個動作後,基本上就完成了開發環境的準備了。
       - 解壓縮該檔案
       - 找到mysql-connector-java-6.0.x-bin.jar
       - 並將這個Java .jar文件的位置加到操作系統環境變量 – CLASSPATH,或在Java IDE中加上一個程式庫給這個.jar上檔
    • MySQL 文件資料應用的Java程式


    package mysqldocstore;

    import com.mysql.cj.api.x.*;
    import com.mysql.cj.x.MysqlxSessionFactory;
    import com.mysql.cj.x.json.*;
    //以上import的三個package/class都是MySQL Connetor/J 6.0.x 所新增的
    public class MySQLdocStore {
    public static void main(String[] args) {
    String url = "mysqlx://localhost:33060/my_test?user=itu&password=";
    //通過mysqlx建立資料庫對話(Session)物件,資料庫主機位於localhost
    //資料庫聽33060端口,用戶名為itu,schemamy_test(可不在URI指定Schema)
    XSession mySession = new MysqlxSessionFactory().getSession(url);
    //開啟一個交易
    mySession.startTransaction();
    //將位置移到your_test schema
    Schema myDb = mySession.getSchema("your_test");
    //找一個名為mycollection Collection,並以myColl變易數指向該物件
    Collection myColl = myDb.getCollection("mycollection");
    //插入三個JSON文件
    myColl.add("{\"name\":\"Sakila\", \"age\":15}").execute();
    myColl.add("{\"name\":\"Susanne\", \"age\":24}").execute();
    myColl.add("{\"name\":\"Mike\", \"age\":39}").execute();
    //提交交易
    mySession.commit();
    //mycolleciton中找文件,條件是name’Sakila’字串,age小於20
    DocResult docs = myColl.find(name like :name AND age < :age").bind("name", "Sakila").bind("age", 20).execute();
    //取出查出的文件以doc變數指向該物件,如果找不到符合條件的文件,則返回NULL
    DbDoc doc = docs.fetchOne();
    //列示查到的JSON文件
    System.out.println("Age below 20 is "+doc);
    }
    }
     
    • 執行結果,由於我將MySQLdocStore.class和msql-connector-java-6.0.x-bin.jar包在jar包中以方便佈署,所以執行時要指定MySQLdocStore.jar。執行後,在資料庫會插入三個JSON文件,最後列示一個JSON文件,其age物件的值小於20。


    $ java –jar MySQLdocStore.jar

    Age below 20 is {
    "_id" : "bb8c3bf0242a44a0a49767e3dcee7cc9",
    "age" : 15,
    "name" : "Sakila"
    }
    • 在MySQL Shell查看mycollection Collection,可看到在mycollection中有三個JSON文件,都是在MySQLdocStore.class程式插入的。
     
    mysql-js> db.mycollection.find();
    [
    {
    "_id": "2f5a69049e0744f4b1f3abd9bbbbd2dd",
    "age": 39,
    "name": "Mike"
    },
    {
    "_id": "bb8c3bf0242a44a0a49767e3dcee7cc9",
    "age": 15,
    "name": "Sakila"
    },
    {
    "_id": "d9d3e1c86a3643be93e65ac1981c659f",
    "age": 24,
    "name": "Susanne"
    }
    ]
    3   documents in set (0.00 sec)


    •  由SQL介面查mycollection表,也可在mycollection表中看到含有個JSON文件的行。


    mysql> select * from mycollection\G

    *************************** 1. row ***************************
    doc: {"_id": "2f5a69049e0744f4b1f3abd9bbbbd2dd", "age": 39, "name": "Mike"}
    _id: 2f5a69049e0744f4b1f3abd9bbbbd2dd
    *************************** 2. row ***************************
    doc: {"_id": "bb8c3bf0242a44a0a49767e3dcee7cc9", "age": 15, "name": "Sakila"}
    _id: bb8c3bf0242a44a0a49767e3dcee7cc9
    *************************** 3. row ***************************
    doc: {"_id": "d9d3e1c86a3643be93e65ac1981c659f", "age": 24, "name": "Susanne"}
    _id: d9d3e1c86a3643be93e65ac1981c659f
    3 rows in set (0.00 sec)

    結論

    我認為MySQL成為JSON文件資料庫是MySQL近年來最重要的創新之一,這套技術促成了MySQL將NoSQL和關聯資料庫的優勢融於一爐,讓廣大的MySQL用戶不需要引另外一套資料庫就能在擁抱新的NoSQL技術,因而也不需磨合陌生的新技術。用戶可在他們己經熟悉的MySQL上以Schema less資料結搆支援Dev/Ops的開發方法,以加速應用面市的速度,滿足應用業務上占得市場先機同時,又能享有關聯式資料庫己經很成熟的資料完整性、支援交易、MVCC(多版本并行控制)和崩潰回復的優點。另一方面DBA們也能使用和原來MySQL同樣的工具為資料庫做備份、調優、監控和安控管制。MySQL這項與時俱進的發展使得MySQL所有的從業人員都能輕鬆因應IT大環境的改變。讓MySQL應用開發者、DBA和應用業務擁有者都能同蒙其利。
    事實上,MySQL除了上述由資料庫核心到MySQL Shell工具和各種應用的Connector上推出支援JSON的功外,我們還需要在應用開發環境上提供更豐富的Framework,以進一步使MySQL的開發者能快速而方便的開發應用。由於許多Connector的技術(例如Java, Node.js等)己經有很多現成的Framework支援JSON,使得我們在這方面的發展有了扎實的基礎。例如使用Node.js的開發者或許知道(或用過)MEAN Framework (MongoDB, Express, Angular.js, Node.js),它能使開發者以更有效率、更容易的開發網頁應用。經過Connector/Node.js開發人員的努力, 現在MySQL也支援MEAN Framework,只是這是組合是MySQL, Ecpress, Angular.js, Node.js了(相關訊息和實作範例可參考http://insidemysql.com/develop-by-example-document-store-working-with-express-js-angularjs-and-node-js/),相信隨著MySQL as a document store的功能持續的完善,將有更多的Framework和IDE(整合開發環境)會支援這個技術堆疊,或許我們會LAMP風潮之后為IT界來另一波高潮。