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源码
这就是Sugar ORM 的目录结构,其实原理并不算特别复杂,就是封装了一层将Object翻译为SQL语句的过程 ,再通过SQLiteDatabase查询。
比较关键的类
SugarDb 继承了 android.database.sqlite.SQLiteOpenHelper,主要负责数据库的创建,更新,关闭等生命周期,实际更新是通过SchemaGenerator这个类实现的。其他类使用的SQLiteDatabase 也是由该单例类获得。SugarDb.getInstance().getDB()
SugarRecord 该类负责实际的增删改查,通过调用SugarDb的SQLiteDatabase实现。
ManifestHelper 该类是个工具类,负责读取Manifest里面meta-data的数据库名,版本等信息
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
onConfigure方法也报错了,因为sqlcipher的SQLiteOpenHelper没有该方法,因此我们将这个配置方法移到onCreate里面
接下来我们需要一个数据库加密的秘钥
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文件看效果。
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源码
这就是Sugar ORM 的目录结构,其实原理并不算特别复杂,就是封装了一层将Object翻译为SQL语句的过程 ,再通过SQLiteDatabase查询。
比较关键的类
SugarDb 继承了 android.database.sqlite.SQLiteOpenHelper,主要负责数据库的创建,更新,关闭等生命周期,实际更新是通过SchemaGenerator这个类实现的。其他类使用的SQLiteDatabase 也是由该单例类获得。SugarDb.getInstance().getDB()
SugarRecord 该类负责实际的增删改查,通过调用SugarDb的SQLiteDatabase实现。
ManifestHelper 该类是个工具类,负责读取Manifest里面meta-data的数据库名,版本等信息
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
onConfigure方法也报错了,因为sqlcipher的SQLiteOpenHelper没有该方法,因此我们将这个配置方法移到onCreate里面
接下来我们需要一个数据库加密的秘钥
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文件看效果。
Well Done!!!
4.尾语
这次从客户提出要加密到集成结束也就花了三个小时,但是这次阅读别人的源码确实也受益匪浅。SQLCipher的内容讲得比较少,建议参考这里再阅读会更能理解。