前沿介绍

腾讯开源微信数据库框架WCDB,他是一个高效、完整、易用的移动数据库框架,基于SQLCipher,支持iOS, macOS和Android。

便捷地定义表、索引、约束,并进行增删改查操作

项目演示效果如下:


Markdown

微信 即时通讯软件

  • 微信(英文名:wechat)是腾讯公司于2011年1月21日推出的一个为智能终端提供即时通讯服务的免费应用程序
  • 微信支持跨通信运营商、跨操作系统平台通过网络快速发送免费语音短信、视频、图片和文字
  • 同时,也可以使用通过共享流媒体内容的资料和基于位置的社交插件“摇一摇”、“漂流瓶”、“朋友圈”、”公众平台“、”语音记事本“等服务插件。
  • 腾讯于6月9日在 GMTC 全球移动技术大会上正式宣布, WCDB(WeChat Database)作为微信的一个开源组件正式对外开源

基本功能


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 于亚豪
     */
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…

关于WCDB还有很多的地方要去学习,该demo中只是演示的其中的冰山一角,接下来我们还有很多要探寻的。

WCDB官方地址:

WCDB官方地址

github.com/Tencent/wcd…

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

Markdown

(这里 学到的不仅仅是技术)