Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android-将加密数据库转换为普通数据库文件的最佳/高效方法是什么_Android_Database_Sqlite_Sqlcipher - Fatal编程技术网

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

Android-将加密数据库转换为普通数据库文件的最佳/高效方法是什么,android,database,sqlite,sqlcipher,Android,Database,Sqlite,Sqlcipher,我已经使用SQLiteCipher为我的应用程序数据库添加了安全性,问题是,它比默认的android SQLiteAPI慢得多。因此,我切换回默认的SQLite API,但我确实需要SQLCipher提供的安全性,所以我所做的是: 打开我的应用程序时 打开加密的数据库文件 创建一个普通的数据库文件 将记录从加密数据库传输到普通数据库 删除加密的数据库文件 使用普通数据库文件 当我的应用程序关闭时 打开普通数据库文件 创建加密的数据库文件 将记录从普通数据库传输到加密数据库 删除普通数据库文件 这

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

打开我的应用程序时

  • 打开加密的数据库文件
  • 创建一个普通的数据库文件
  • 将记录从加密数据库传输到普通数据库
  • 删除加密的数据库文件
  • 使用普通数据库文件
  • 当我的应用程序关闭时

  • 打开普通数据库文件
  • 创建加密的数据库文件
  • 将记录从普通数据库传输到加密数据库
  • 删除普通数据库文件
  • 这项工作没有任何问题,但传输记录需要一些时间,而且会消耗更多的时间(我假设我的数据库文件在实际使用过程中会包含数千条记录)。那么,我所做的还有其他方法吗? 有没有更有效的方法?蒂亚

    编辑:下面是一些使用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),因此我想我的应用程序可以在完全退出之前加密数据库。