Android - 什么是将加密数据库转换为普通数据库文件的最佳/最有效方法

时间:2014-06-11 12:22:00

标签: android database sqlite sqlcipher

我使用SQLiteCipher为我的应用程序数据库添加安全性,问题是,它比默认的android SQLite API慢得多。所以我切换回默认的SQLite API,但我真的需要SQLCipher提供的安全性,所以我做的是:

打开我的应用

  1. 打开加密数据库文件
  2. 创建普通数据库文件
  3. 将记录从加密数据传输到普通数据库
  4. 删除加密的数据库文件
  5. 使用普通数据库文件
  6. 当我的应用关闭时,

    1. 打开普通数据库文件
    2. 创建加密数据库文件
    3. 将记录从普通数据库传输到加密数据库
    4. 删除普通数据库文件
    5. 这没有任何问题,但传输记录需要一些时间并且会消耗更多(我假设我的数据库文件在其实际使用期间将包含数千条记录)。那么我有什么其他办法吗? 有没有更有效的方法来做到这一点? TIA!

      编辑:以下是一些使用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);
          }
      }
      

      DBHelper类

      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);
              }
          }
      

      更新:我已经阅读了一些与我有关的问题,我真的看到有些人也面临着使用SQLCipher的性能问题,一个答案说“缓存数据库”只能用于多次连接在相同的应用程序上的活动,问题是,我不知道这样做

1 个答案:

答案 0 :(得分:0)

最佳SQLCipher性能有一些非常重要的指导原则:

  • 不要重复打开和关闭连接,因为密钥派生非常昂贵,设计
  • 使用事务来包装插入/更新/删除操作。除非在事务范围内执行,否则每个操作都将发生在它自己的事务中,这会使事情减慢几个数量级。
  • 确保您的数据已规范化(即,使用良好做法将数据分成多个表以消除冗余)。不必要的数据重复导致数据库膨胀,这意味着SQLCipher可以运行更多页面
  • 确保索引用于搜索或加入条件的所有列。如果你不这样做,SQLCipher将需要在大量页面上执行完整的数据库扫描
  • 定期吸尘以确保数据库紧凑,如果您进行大量删除,更新等。

最后,为了进一步诊断特定查询语句的性能,有几个选项。首先,我建议运行PRAGMA cipher_profile作为上面提到的CommonsWare,您可以阅读有关使用here的更多信息。这将为您提供对数据库执行的查询及其各自执行时间的日志(以毫秒为单位)。接下来,对一些可能性能不佳的查询运行explain query plan命令?说明查询命令的输出描述为here