SugarORM SQLCipher 数据库及加密教程

1.序言

最近找到了一个非常简单的DB管理工具 名为Sugar ORM 号称不需要编写SQL语句就能实现数据库操作。实际使用了一番发现在数据库表结构不复杂的情况下还是蛮好用的。另外Sugar ORM不提供数据库加密,因此需要配合SQLCipher实现加密。(这两个工具似乎在其他平台也能使用,下面以Android为例)

2.牛刀小试 Sugar ORM

1.导入Module

因为后面需要加入SQLCipher,所以直接下载源码import Module方便修改源码。具体import方法略过。

2.创建数据库基本信息

你的数据库信息需要提前在Manifest里输入,SugarDB才能正确初始化

<application>

<meta-data android:name="DATABASE" android:value="sugar_example.db" />
<meta-data android:name="VERSION" android:value="2" />
<meta-data android:name="QUERY_LOG" android:value="true" />
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.example" />

<application/>

DATABASE 是数据库名称,以.db结束 Example: test.db
VERSION 是数据库版本,每次更改数据库表的时候,VERSION需要加一,否则会出现no such table的错误日志
QUERY_LOG 是否输出日志,建议Debug为true,Release为false
DOMAIN_PACKAGE_NAME 以这个包下的类作为数据库表 Example:com.example.test.bean

接着在Application 里初始化
SugarContext.init(this)

3.Are U Ready?

就这么简单,你已经配置好Sugar DB了。
Sugar DB 是以类作为数据库操作的。比如在你的DOMAIN_PACKAGE_NAME 包名下创建一个类

public class Book extends SugarRecord {

  public String title;
  public String edition;

  public Book(){
  }

  public Book(String title, String edition){
    this.title = title;
    this.edition = edition;
  }
}

这个Book类继承自SugarRecord ,现在已经可以对它进行基本增删改查了。

 Book book = new Book();
 book.title = "钢之炼金术师";
 book.edition = "爱德华";
 book.save();

只要输入好类的属性,调用this.save就能插入一个记录到Book表了。下面用kotlin演示

val books = SugarRecord.find(Book::class.java,"title = ?","钢之炼金术师")

查询数据只需要调用SugarRecord.find(Class,whereClause,whereArgs)即可返回符合条件的Book数组。如果查询条件比较多,可以再往后加

val books = SugarRecord.find(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")

遍历数组即可获得你要的查询后的数据了。

查询表里所有数据
val book = SugarRecord.listAll(Book::class.java)

删除表里所有数据
val book = SugarRecord.deleteAll(Book::class.java)

删除表里特定数据
val books = SugarRecord.deleteAll(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")

改变数据

   val books = SugarRecord.find(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")
   books[0].edition = "牛姨"
   books[0].save()

使用Sugar ORM就能相当简单的实现增删改查。

3.配合SQLCipher对数据库加密

1.导入SQLCipher

implementation 'net.zetetic:android-database-sqlcipher:3.5.7'

2.分析Sugar DB源码

image.png

这就是Sugar ORM 的目录结构,其实原理并不算特别复杂,就是封装了一层将Object翻译为SQL语句的过程 ,再通过SQLiteDatabase查询。

image.png

比较关键的类
SugarDb 继承了 android.database.sqlite.SQLiteOpenHelper,主要负责数据库的创建,更新,关闭等生命周期,实际更新是通过SchemaGenerator这个类实现的。其他类使用的SQLiteDatabase 也是由该单例类获得。SugarDb.getInstance().getDB()
image.png

SugarRecord 该类负责实际的增删改查,通过调用SugarDb的SQLiteDatabase实现。
image.png

ManifestHelper 该类是个工具类,负责读取Manifest里面meta-data的数据库名,版本等信息
image.png

3.集成SQLCipher

SQLCipher的正常使用可以参考这里
但是我现在想Sugar ORM帮我处理增删改查等操作。而使用的SQLiteDatabase需要是SQLCipher的加密SQLiteDatabase。
因此我们修改的重点就是在SugarDb这个类。
首先我们需要把

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

替换成sqlcipher的工具类

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;

可以看到构造方法报错了,你可以将CursorFactory改为sqlcipher的CursorFactory,或者直接传null
image.png

image.png

onConfigure方法也报错了,因为sqlcipher的SQLiteOpenHelper没有该方法,因此我们将这个配置方法移到onCreate里面
image.png

接下来我们需要一个数据库加密的秘钥

private static final String DB_PWD = "abcdefg123"; //数据库密码
将下面用到的getWritableDatabase getReadableDatabase改成

 getWritableDatabase(DB_PWD)
 getReadableDatabase(DB_PWD)

将getReadableDatabase方法的Override去掉,我们这个SugarDB就已经集成好sqlcipher了

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;
import static com.orm.util.ContextUtil.getContext;
import static com.orm.helper.ManifestHelper.getDatabaseVersion;
import static com.orm.helper.ManifestHelper.getDbName;
import static com.orm.SugarContext.getDbConfiguration;

public class SugarDb extends SQLiteOpenHelper {
    private static final String LOG_TAG = "Sugar";
    public static final String DB_PWD="abcdefg123";//数据库密码
    private final SchemaGenerator schemaGenerator;
    private SQLiteDatabase sqLiteDatabase;
    private int openedConnections = 0;

    //Prevent instantiation
    private SugarDb() {
        super(getContext(), getDbName(), null, getDatabaseVersion());
        schemaGenerator = SchemaGenerator.getInstance();
    }

    public static SugarDb getInstance() {
        return new SugarDb();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        schemaGenerator.createDatabase(sqLiteDatabase);

        final SugarDbConfiguration configuration = getDbConfiguration();
        if (null != configuration) {
            sqLiteDatabase.setLocale(configuration.getDatabaseLocale());
            sqLiteDatabase.setMaximumSize(configuration.getMaxSize());
            sqLiteDatabase.setPageSize(configuration.getPageSize());
        }
    }


    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        schemaGenerator.doUpgrade(sqLiteDatabase, oldVersion, newVersion);
    }

    public synchronized SQLiteDatabase getDB() {
        if (this.sqLiteDatabase == null) {
            this.sqLiteDatabase = getWritableDatabase(DB_PWD);
        }

        return this.sqLiteDatabase;
    }

    public synchronized SQLiteDatabase getReadableDatabase() {
        if(ManifestHelper.isDebugEnabled()) {
            Log.d(LOG_TAG, "getReadableDatabase");
        }
        openedConnections++;
        return super.getReadableDatabase(DB_PWD);
    }

    @Override
    public synchronized void close() {
        if(ManifestHelper.isDebugEnabled()) {
            Log.d(LOG_TAG, "getReadableDatabase");
        }
        openedConnections--;
        if(openedConnections == 0) {
            if(ManifestHelper.isDebugEnabled()) {
                Log.d(LOG_TAG, "closing");
            }
            super.close();
        }
    }
}

接下来再将SchemaGenerator 的import android.database.sqlite.SQLiteDatabase;替换成import net.sqlcipher.database.SQLiteDatabase; 如果别的类有出现报错也依次替换包为net.sqlcipher.database

至此,Sugar ORM 跟 SQLCipher的结合已经完成,我们跑一下打开DB文件看效果。

image.png

Well Done!!!

4.尾语

这次从客户提出要加密到集成结束也就花了三个小时,但是这次阅读别人的源码确实也受益匪浅。SQLCipher的内容讲得比较少,建议参考这里再阅读会更能理解。

1.序言

最近找到了一个非常简单的DB管理工具 名为Sugar ORM 号称不需要编写SQL语句就能实现数据库操作。实际使用了一番发现在数据库表结构不复杂的情况下还是蛮好用的。另外Sugar ORM不提供数据库加密,因此需要配合SQLCipher实现加密。(这两个工具似乎在其他平台也能使用,下面以Android为例)

2.牛刀小试 Sugar ORM

1.导入Module

因为后面需要加入SQLCipher,所以直接下载源码import Module方便修改源码。具体import方法略过。

2.创建数据库基本信息

你的数据库信息需要提前在Manifest里输入,SugarDB才能正确初始化

<application>

<meta-data android:name="DATABASE" android:value="sugar_example.db" />
<meta-data android:name="VERSION" android:value="2" />
<meta-data android:name="QUERY_LOG" android:value="true" />
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="com.example" />

<application/>

DATABASE 是数据库名称,以.db结束 Example: test.db
VERSION 是数据库版本,每次更改数据库表的时候,VERSION需要加一,否则会出现no such table的错误日志
QUERY_LOG 是否输出日志,建议Debug为true,Release为false
DOMAIN_PACKAGE_NAME 以这个包下的类作为数据库表 Example:com.example.test.bean

接着在Application 里初始化
SugarContext.init(this)

3.Are U Ready?

就这么简单,你已经配置好Sugar DB了。
Sugar DB 是以类作为数据库操作的。比如在你的DOMAIN_PACKAGE_NAME 包名下创建一个类

public class Book extends SugarRecord {

  public String title;
  public String edition;

  public Book(){
  }

  public Book(String title, String edition){
    this.title = title;
    this.edition = edition;
  }
}

这个Book类继承自SugarRecord ,现在已经可以对它进行基本增删改查了。

 Book book = new Book();
 book.title = "钢之炼金术师";
 book.edition = "爱德华";
 book.save();

只要输入好类的属性,调用this.save就能插入一个记录到Book表了。下面用kotlin演示

val books = SugarRecord.find(Book::class.java,"title = ?","钢之炼金术师")

查询数据只需要调用SugarRecord.find(Class,whereClause,whereArgs)即可返回符合条件的Book数组。如果查询条件比较多,可以再往后加

val books = SugarRecord.find(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")

遍历数组即可获得你要的查询后的数据了。

查询表里所有数据
val book = SugarRecord.listAll(Book::class.java)

删除表里所有数据
val book = SugarRecord.deleteAll(Book::class.java)

删除表里特定数据
val books = SugarRecord.deleteAll(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")

改变数据

   val books = SugarRecord.find(Book::class.java,"title = ? && edition = ?","钢之炼金术师","爱德华")
   books[0].edition = "牛姨"
   books[0].save()

使用Sugar ORM就能相当简单的实现增删改查。

3.配合SQLCipher对数据库加密

1.导入SQLCipher

implementation 'net.zetetic:android-database-sqlcipher:3.5.7'

2.分析Sugar DB源码

image.png

这就是Sugar ORM 的目录结构,其实原理并不算特别复杂,就是封装了一层将Object翻译为SQL语句的过程 ,再通过SQLiteDatabase查询。

image.png

比较关键的类
SugarDb 继承了 android.database.sqlite.SQLiteOpenHelper,主要负责数据库的创建,更新,关闭等生命周期,实际更新是通过SchemaGenerator这个类实现的。其他类使用的SQLiteDatabase 也是由该单例类获得。SugarDb.getInstance().getDB()
image.png

SugarRecord 该类负责实际的增删改查,通过调用SugarDb的SQLiteDatabase实现。
image.png

ManifestHelper 该类是个工具类,负责读取Manifest里面meta-data的数据库名,版本等信息
image.png

3.集成SQLCipher

SQLCipher的正常使用可以参考这里
但是我现在想Sugar ORM帮我处理增删改查等操作。而使用的SQLiteDatabase需要是SQLCipher的加密SQLiteDatabase。
因此我们修改的重点就是在SugarDb这个类。
首先我们需要把

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

替换成sqlcipher的工具类

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;

可以看到构造方法报错了,你可以将CursorFactory改为sqlcipher的CursorFactory,或者直接传null
image.png

image.png

onConfigure方法也报错了,因为sqlcipher的SQLiteOpenHelper没有该方法,因此我们将这个配置方法移到onCreate里面
image.png

接下来我们需要一个数据库加密的秘钥

private static final String DB_PWD = "abcdefg123"; //数据库密码
将下面用到的getWritableDatabase getReadableDatabase改成

 getWritableDatabase(DB_PWD)
 getReadableDatabase(DB_PWD)

将getReadableDatabase方法的Override去掉,我们这个SugarDB就已经集成好sqlcipher了

import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;
import static com.orm.util.ContextUtil.getContext;
import static com.orm.helper.ManifestHelper.getDatabaseVersion;
import static com.orm.helper.ManifestHelper.getDbName;
import static com.orm.SugarContext.getDbConfiguration;

public class SugarDb extends SQLiteOpenHelper {
    private static final String LOG_TAG = "Sugar";
    public static final String DB_PWD="abcdefg123";//数据库密码
    private final SchemaGenerator schemaGenerator;
    private SQLiteDatabase sqLiteDatabase;
    private int openedConnections = 0;

    //Prevent instantiation
    private SugarDb() {
        super(getContext(), getDbName(), null, getDatabaseVersion());
        schemaGenerator = SchemaGenerator.getInstance();
    }

    public static SugarDb getInstance() {
        return new SugarDb();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        schemaGenerator.createDatabase(sqLiteDatabase);

        final SugarDbConfiguration configuration = getDbConfiguration();
        if (null != configuration) {
            sqLiteDatabase.setLocale(configuration.getDatabaseLocale());
            sqLiteDatabase.setMaximumSize(configuration.getMaxSize());
            sqLiteDatabase.setPageSize(configuration.getPageSize());
        }
    }


    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
        schemaGenerator.doUpgrade(sqLiteDatabase, oldVersion, newVersion);
    }

    public synchronized SQLiteDatabase getDB() {
        if (this.sqLiteDatabase == null) {
            this.sqLiteDatabase = getWritableDatabase(DB_PWD);
        }

        return this.sqLiteDatabase;
    }

    public synchronized SQLiteDatabase getReadableDatabase() {
        if(ManifestHelper.isDebugEnabled()) {
            Log.d(LOG_TAG, "getReadableDatabase");
        }
        openedConnections++;
        return super.getReadableDatabase(DB_PWD);
    }

    @Override
    public synchronized void close() {
        if(ManifestHelper.isDebugEnabled()) {
            Log.d(LOG_TAG, "getReadableDatabase");
        }
        openedConnections--;
        if(openedConnections == 0) {
            if(ManifestHelper.isDebugEnabled()) {
                Log.d(LOG_TAG, "closing");
            }
            super.close();
        }
    }
}

接下来再将SchemaGenerator 的import android.database.sqlite.SQLiteDatabase;替换成import net.sqlcipher.database.SQLiteDatabase; 如果别的类有出现报错也依次替换包为net.sqlcipher.database

至此,Sugar ORM 跟 SQLCipher的结合已经完成,我们跑一下打开DB文件看效果。

image.png

Well Done!!!

4.尾语

这次从客户提出要加密到集成结束也就花了三个小时,但是这次阅读别人的源码确实也受益匪浅。SQLCipher的内容讲得比较少,建议参考这里再阅读会更能理解。

点这里发现一个有趣的开发者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值