Android-将加密数据库转换为普通数据库文件的最佳/高效方法是什么
我已经使用SQLiteCipher为我的应用程序数据库添加了安全性,问题是,它比默认的android SQLiteAPI慢得多。因此,我切换回默认的SQLite API,但我确实需要SQLCipher提供的安全性,所以我所做的是: 打开我的应用程序时Android-将加密数据库转换为普通数据库文件的最佳/高效方法是什么,android,database,sqlite,sqlcipher,Android,Database,Sqlite,Sqlcipher,我已经使用SQLiteCipher为我的应用程序数据库添加了安全性,问题是,它比默认的android SQLiteAPI慢得多。因此,我切换回默认的SQLite API,但我确实需要SQLCipher提供的安全性,所以我所做的是: 打开我的应用程序时 打开加密的数据库文件 创建一个普通的数据库文件 将记录从加密数据库传输到普通数据库 删除加密的数据库文件 使用普通数据库文件 当我的应用程序关闭时 打开普通数据库文件 创建加密的数据库文件 将记录从普通数据库传输到加密数据库 删除普通数据库文件 这
private final static String phrase = "passW0rd3r";
private EditText StudNum, StudName, StudCrse;
private DBHelper dbIns;
SQLiteDatabase DBFile;
private MainDBHelper DBHelp;
private MenuItem msg_app;
final Context con = this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StudNum = (EditText)findViewById(R.id.txtsNum);
StudName = (EditText)findViewById(R.id.txtsName);
StudCrse = (EditText)findViewById(R.id.txtCourse);
StudNum.requestFocus();
SQLiteDatabase.loadLibs(this);
dbIns = new DBHelper(this, DB_NAME);
DBFile = dbIns.getWritableDatabase(phrase);
DBHelp = new MainDBHelper(this);
//Takes too much time to load, loads around 3 seconds, compared to
//the default SQLite API, which is half a second only
}
MainDBHelper类
public class MainDBHelper {
private static final String DB_NAME = "StudentInfo.db";
private static final String TABLE_NAME = "StudentInfo";
private final static String phrase = "passW0rd3r";
private DBHelper openHelper;
private SQLiteDatabase database;
public MainDBHelper(Context context) {
openHelper = new DBHelper(context, DB_NAME);
database = openHelper.getWritableDatabase(phrase);
}
}
public class DBHelper extends SQLiteOpenHelper{
private String DBName;
public DBHelper(Context context, String DBname) {
super(context, DBname, null, 5);
this.DBName = DBname.substring(0,DBname.length()-3);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase arg0) {
// TODO Auto-generated method stub
arg0.execSQL("CREATE TABLE " + DBName + " (_id INTEGER PRIMARY KEY, " +
"Stud_Num TEXT, Stud_Name TEXT, Stud_Crse TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
arg0.execSQL("DROP TABLE IF EXISTS " + DBName);
onCreate(arg0);
}
}
DBHelper类
public class MainDBHelper {
private static final String DB_NAME = "StudentInfo.db";
private static final String TABLE_NAME = "StudentInfo";
private final static String phrase = "passW0rd3r";
private DBHelper openHelper;
private SQLiteDatabase database;
public MainDBHelper(Context context) {
openHelper = new DBHelper(context, DB_NAME);
database = openHelper.getWritableDatabase(phrase);
}
}
public class DBHelper extends SQLiteOpenHelper{
private String DBName;
public DBHelper(Context context, String DBname) {
super(context, DBname, null, 5);
this.DBName = DBname.substring(0,DBname.length()-3);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase arg0) {
// TODO Auto-generated method stub
arg0.execSQL("CREATE TABLE " + DBName + " (_id INTEGER PRIMARY KEY, " +
"Stud_Num TEXT, Stud_Name TEXT, Stud_Crse TEXT)");
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
arg0.execSQL("DROP TABLE IF EXISTS " + DBName);
onCreate(arg0);
}
}
使用相同数据库连接的额外类
DisplayMessageActivity类-此类加载约2秒,仅在列表视图中显示3条记录。如果我使用默认的SQLite API,它可以在一秒钟内加载多达10条记录
public class DisplayMessageActivity extends Activity {
private ListAdapter listAdapt;
private MainDBHelper DBHelp;
private EditText edtName, edtSnum, edtCrse;
private TextView dName, dSnum, dCrse, ssn;
private ListView lst_snum;
private SearchView sView;
private MenuItem sItem;
private View lView, diagView;
private AlertDialog.Builder DBuilder;
private AlertDialog ADiag;
private String StudentNumber, edSname, edSnum, edCrse;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
DBHelp = new MainDBHelper(this);
lst_snum = (ListView)findViewById(R.id.lv_test);
refreshList();
createADiag(this);
lst_snum.setOnItemLongClickListener(new OnItemLongClickListener(){
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
lView = view;
ssn = (TextView)view.findViewById(R.id.studNum);
ADiag.show();
return false;
}
});
}
private void refreshList(){
listAdapt = null;
listAdapt = new ListAdapter(this, DBHelp.getTimeRecordList());
lst_snum.setAdapter(listAdapt);
}
}
public类DisplayMessageActivity扩展活动{
私有ListAdapter listAdapt;
私人MainDBHelper数据库帮助;
私有编辑文本edtName、EDTSUM、edtCrse;
私有文本视图dName、dSnum、dCrse、ssn;
私有ListView lst_snum;
私人搜索视图;
私有菜单项站点;
私有视图lView,diagView;
私有AlertDialog.Builder DBuilder;
私人警报;
私人字符串学生编号、edSname、edSnum、edCrse;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity\u display\u message);
DBHelp=新的MainDBHelper(此);
lst_snum=(ListView)findViewById(R.id.lv_测试);
刷新列表();
createADiag(这个);
lst_snum.setOnItemLongClickListener(新的OnItemLongClickListener(){
@凌驾
长单击(AdapterView父视图、视图、,
内部位置,长id){
//TODO自动生成的方法存根
lView=视图;
ssn=(TextView)view.findViewById(R.id.studNum);
ADiag.show();
返回false;
}
});
}
私有无效刷新列表(){
listAdapt=null;
listAdapt=newListAdapter(这是DBHelp.getTimeRecordList());
lst_snum.setAdapter(listAdapt);
}
}
更新:我已经阅读了一些与我相关的问题,我真的看到一些人在使用SQLCipher时也面临性能问题,一个回答说,为了一次连接“缓存数据库”,只能在同一个应用程序上的多个活动上使用,问题是,我不知道如何做到这一点有一些非常重要的准则可用于优化SQLCipher性能:
- 不要反复打开和关闭连接,因为键派生是非常昂贵的
- 使用事务来包装插入/更新/删除操作。除非在事务作用域中执行,否则每个操作都将发生在它自己的事务中,这会将速度降低几个数量级
- 确保数据规范化(即,使用良好的做法将数据分离到多个表中以消除冗余)。不必要的数据复制会导致数据库膨胀,这意味着SQLCipher需要操作更多的页面
- 确保为用于搜索或联接条件的所有列编制索引。如果不这样做,SQLCipher将需要跨大量页面执行完整的数据库扫描
- 如果执行大型删除、更新等操作,请定期清理数据库,以确保数据库紧凑
最后,为了进一步诊断特定查询语句的性能,有两个选项。首先,我建议运行上面提到的Commonware
PRAGMA cipher_profile
,您可以阅读更多有关用法的信息。这将为您提供对数据库执行的查询及其各自的执行时间(以毫秒为单位)的日志。接下来,对一些可能执行得很差的查询运行命令?explain query命令的输出如下所述。“它比默认的android SQLite API慢得多”——我没有听说过这方面的主要问题。加密开销并没有那么大,因此,如果使用SQLCipher速度较慢,那么使用普通SQLite(例如,强制表扫描的查询)速度可能会较慢。你可以考虑使用<代码> Pracmi-CiffelPrime,看看它是否能帮助你找出问题所在。由于Android中没有“app is closed”的概念,你提出的方法将无法可靠地工作。嗯,如果你说我的代码很快(我将用我的代码更新我的问题),那么我的代码似乎有点奇怪。PRAGMA cipher_profile需要我构建源代码吗?关于应用程序关闭的概念,我开发了我的应用程序,以便在用户离开时自动退出/完成(通过activityForResult),因此我想我的应用程序可以在完全退出之前加密数据库。