微信 WCDB 正式開源——高效易用的移動資料庫框架

codeGoogle發表於2017-07-26

前沿介紹

騰訊開源微信資料庫框架WCDB,他是一個高效、完整、易用的移動資料庫框架,基於SQLCipher,支援iOS, macOS和Android。

便捷地定義表、索引、約束,並進行增刪改查操作

專案演示效果如下:

Markdown
Markdown

微信 即時通訊軟體

  • 微信(英文名:wechat)是騰訊公司於2011年1月21日推出的一個為智慧終端提供即時通訊服務的免費應用程式

  • 微信支援跨通訊運營商、跨作業系統平臺通過網路快速傳送免費語音簡訊、視訊、圖片和文字

  • 同時,也可以使用通過共享流媒體內容的資料和基於位置的社交外掛“搖一搖”、“漂流瓶”、“朋友圈”、”公眾平臺“、”語音記事本“等服務外掛。

  • 騰訊於6月9日在 GMTC 全球移動技術大會上正式宣佈, WCDB(WeChat Database)作為微信的一個開源元件正式對外開源

基本功能

Markdown
Markdown

  • 基於SQLCipher的資料庫加密

  • 使用連線池實現併發讀寫

  • 內建 Repair Kit 可用於修復損壞資料庫

  • 針對佔用空間大小優化的資料庫備份/恢復功能

  • 日誌輸出重定向以及效能跟蹤介面

  • 內建用於全文搜尋的 mmicu FTS3/4 分詞器
    入門

官方介紹如下:

WCDB 是一個高效、完整、易用的移動資料庫框架,基於 SQLCipher,支援 iOS、macOS 和 Android。

WCDB的好處

  • WINQ(WCDB語言整合查詢): 通過WINQ,開發者無須為了拼接SQL的字串而寫一大坨膠水程式碼。

  • ORM(Object Relational Mapping): WCDB支援靈活、易用的ORM。開發者可以很便捷地定義表、索引、約束,並進行增刪改查操作。

  • 多執行緒高併發: WCDB支援多執行緒讀與讀、讀與寫併發執行,寫與寫序列執行。

  • 加密:WCDB提供基於SQLCipher的資料庫加密。

  • 損壞修復: WCDB內建了Repair Kit用於修復損壞的資料庫。

  • 反注入: WCDB內建了對SQL隱碼攻擊的保護。

  • 基於SQLCipher的資料庫加密

  • 使用連線池實現併發讀寫

  • 內建 Repair Kit 可用於修復損壞資料庫

  • 針對佔用空間大小優化的資料庫備份/恢復功能

  • 日誌輸出重定向以及效能跟蹤介面

  • 內建用於全文搜尋的 mmicu FTS3/4 分詞器

相關程式碼(SQLiteOpenHelper類)

    /**
     * 類功能描述:</br>
     * 新資料處理幫助類
     * @author 於亞豪
     *  部落格地址: http://blog.csdn.net/androidstarjack
     * 公眾號: 終端研發部
     * @version 1.0 </p> 修改時間:</br> 修改備註:</br>
     */
public class EncryptedDBHelper extends SQLiteOpenHelper {

        private static final String TAG = "EncryptedDBHelper";

        private static final String DATABASE_NAME = "encrypted.db";
        private static final String OLD_DATABASE_NAME = "plain-text.db";
        private static final int DATABASE_VERSION = 2;

        private Context mContext;
        private String mPassphrase;

        public EncryptedDBHelper(Context context, String passphrase) {

            // 呼叫“加密”版本的超類建構函式。
            super(context, DATABASE_NAME, passphrase.getBytes(), null, null, DATABASE_VERSION,
                    null);
            // 儲存上下文物件供以後使用。
            mContext = context;
            mPassphrase = passphrase;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            // 檢查資料庫plain-text.db是否存在 ,存在 如果是這樣,將其匯出到新的加密庫中的。
            File oldDbFile = mContext.getDatabasePath(OLD_DATABASE_NAME);
            if (oldDbFile.exists()) {

                Log.i(TAG, "Migrating plain-text database to encrypted one.");

                //SQLiteOpenHelper在呼叫onCreate()之前開始一個事務。 我們必須結束事務才能附加一個新的資料庫。
                db.endTransaction();

                // 將舊資料庫附加到新建立的加密資料庫。
                String sql = String.format("ATTACH DATABASE %s AS old KEY '';",
                        DatabaseUtils.sqlEscapeString(oldDbFile.getPath()));
                db.execSQL(sql);

                // 匯出舊資料庫。
                db.beginTransaction();
                DatabaseUtils.stringForQuery(db, "SELECT sqlcipher_export('main', 'old');", null);
                db.setTransactionSuccessful();
                db.endTransaction();

                // 獲取舊的資料庫版本供以後升級。
                int oldVersion = (int) DatabaseUtils.longForQuery(db, "PRAGMA old.user_version;", null);

                // 分離舊資料庫並輸入新的事務。
                db.execSQL("DETACH DATABASE old;");

                // 舊資料庫現在可以刪除。
                oldDbFile.delete();

                // 在進一步的操作之前,還原事務。
                db.beginTransaction();

                // 檢查我們是否需要升級架構。
                if (oldVersion > DATABASE_VERSION) {
                    onDowngrade(db, oldVersion, DATABASE_VERSION);
                } else if (oldVersion < DATABASE_VERSION) {
                    onUpgrade(db, oldVersion, DATABASE_VERSION);
                }
            } else {
                Log.i(TAG, "Creating new encrypted database.");

                // 如果舊資料庫不存在,請進行真正的初始化。
                db.execSQL("CREATE TABLE message (content TEXT, "
                        + "sender TEXT);");
            }

            // 損壞恢復的備份主資訊。
            RepairKit.MasterInfo.save(db, db.getPath() + "-mbak", mPassphrase.getBytes());
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            Log.i(TAG, String.format("Upgrading database from version %d to version %d.",
                    oldVersion, newVersion));

            //將新列新增到資料庫升級的訊息表中。
            db.execSQL("ALTER TABLE message ADD COLUMN sender TEXT;");

            //損壞恢復的備份主資訊
            RepairKit.MasterInfo.save(db, db.getPath() + "-mbak", mPassphrase.getBytes());
        }
    }複製程式碼

WCDB如何查詢資料庫的相關示例:

new AsyncTask<Void, Void, Cursor>() {
            @Override
            protected void onPreExecute() {
                mAdapter.notifyDataSetChanged();
            }
            @Override
            protected Cursor doInBackground(Void... params) {
                if (mDB == null || !mDB.isOpen())
                    return null;

                String message = "Message inserted on " + DATE_FORMAT.format(new Date());

                if (mDBVersion == 1) {
                    mDB.execSQL("INSERT INTO message VALUES (?);",
                            new Object[]{"yyh"});
                    return mDB.rawQuery("SELECT rowid as _id, content, '???' as sender FROM message;",
                            null);
                } else {
                    mDB.execSQL("INSERT INTO message VALUES (?, ?);",
                            new Object[]{"yyh", "男"});
                    return mDB.rawQuery("SELECT rowid as _id, content, sender FROM message;",
                            null);
                }
            }
            @Override
            protected void onPostExecute(Cursor cursor) {
                if (cursor == null)
                    return;
                list = getAllStudent(cursor);
                mAdapter.changeCursor(list);
            }
        }.execute();複製程式碼

WWCDB如何插入表的相關示例:

final DateFormat DATE_FORMAT = SimpleDateFormat.getDateTimeInstance();
        new AsyncTask<Void, Void, Cursor>() {
            @Override
            protected void onPreExecute() {
                mAdapter.notifyDataSetChanged();
            }
            @Override
            protected Cursor doInBackground(Void... params) {
                if (mDB == null || !mDB.isOpen())
                    return null;

                String message = "Message inserted on " + DATE_FORMAT.format(new Date());

                if (mDBVersion == 1) {
                    mDB.execSQL("INSERT INTO message VALUES (?);",
                            new Object[]{"yyh"});
                    return mDB.rawQuery("SELECT rowid as _id, content, '???' as sender FROM message;",
                            null);
                } else {
                    mDB.execSQL("INSERT INTO message VALUES (?, ?);",
                            new Object[]{"yyh", "男"});
                    return mDB.rawQuery("SELECT rowid as _id, content, sender FROM message;",
                            null);
                }
            }
            @Override
            protected void onPostExecute(Cursor cursor) {
                if (cursor == null)
                    return;
                list = getAllStudent(cursor);
                mAdapter.changeCursor(list);
            }
        }.execute();複製程式碼

WCDB如何刪除表的相關示例:

if (mDB == null || !mDB.isOpen()){
        return  ;

    }
    mDB.execSQL("DELETE FROM message WHERE content"+"=?",new Object[]{"yyh"});
    com.tencent.wcdb.Cursor cursor =  mDB.rawQuery("SELECT rowid as _id, content, sender FROM message;",null);
    list = getAllStudent(cursor);
    mAdapter.changeCursor(list);複製程式碼

完整demo下載地址:

相關專案下載地址(github):

github.com/androidstar…

csdn下載連結
download.csdn.net/detail/andr…

關於WCDB還有很多的地方要去學習,該demo中只是演示的其中的冰山一角,接下來我們還有很多要探尋的。

WCDB官方地址:

WCDB官方地址

github.com/Tencent/wcd…

相信自己,沒有做不到的,只有想不到的

如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809
微信公眾號:終端研發部

Markdown
Markdown

(這裡 學到的不僅僅是技術)

相關文章