Android 数据库升级中数据保持和导入已有数据库(转)

 

一.数据库升级:html

  在咱们的程序中,或多或少都会涉及到数据库,使用数据库一定会涉及到数据库的升级,数据库升级带来的一些问题,如旧版本数据库的数据记录的保持,对新表的字段的添加等等一系列问题,还记得当我来西安的时候,面试的第二家公司,作音乐播放客户端的,就问到了这个问题;android

  咱们开发了一个程序,当前是1.0版本。该程序用到了数据库。到1.1版本时,在数据库的某个表中增长了一个字段。那么软件1.0版本用的数据库在软件1.1版本就要被升级了。软件的1.0版本升级到1.1版本时,老的数据不能丢。那么在1.1版本的程序中就要有地方可以检测出来新的软件版本与老的数据库不兼容,而且把1.0软件的数据库升级到1.1软件可以使用的数据库。也就是说,要在1.0软件的数据库的那个表中增长那个字段,并赋予这个字段默认值。面试

  程序如何知道咱们的数据库须要升级呢?SQLiteOpenHelper类的构造函数有一个参数是version即数据库版本号。好比在软件1.0版本中,咱们使用SQLiteOpenHelper访问数据库时,该参数为1,那么数据库版本号1就会写在咱们的数据库中。到了1.1版本,咱们的数据库须要发生变化,那么咱们1.1版本的程序中就要使用一个大于1的整数来构造SQLiteOpenHelper类,用于访问新的数据库,好比2。当咱们的1.1新程序读取1.0版本的老数据库时,就发现老数据库里存储的数据库版本是1,而咱们新程序访问它时填的版本号为2,系统就知道数据库须要升级。sql

  当系统在构造SQLiteOpenHelper类的对象时,若是发现版本号不同,就会自动调用onUpgrade函数,在这个方法里对数据库进行升级。在这个函数中把老版本数据库的相应表中增长字段,并给每条记录增长默认值便可。新版本号和老版本号都会做为onUpgrade函数的参数传进来,便于开发者知道数据库应该从哪一个版本升级到哪一个版本。升级完成后,数据库会自动存储最新的版本号为当前数据库版本号。数据库

  SQLite提供了ALTER TABLE命令,容许用户重命名或添加新的字段到已有表中,可是不能从表中删除字段。而且只能在表的末尾添加字段,好比,为Test添加一个字段:"ALTER TABLE Test ADDCOLUMN age"
下面是个人一个测试:ide

 

public class DataSQL extends SQLiteOpenHelper {
    public DataSQL(Context context, int version) {
        super(context, "Test", null, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table test(id integer primary key autoincrement, name)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if (newVersion == 2) {
            db.execSQL("ALTER TABLE test ADD COLUMN age");
            Cursor cr = db.rawQuery("select * from test", null);
            while (cr.moveToNext()) {
                String name = cr.getString(cr.getColumnIndex("name"));
                ContentValues values = new ContentValues();
                values.put("name", name);
                values.put("age", 23);
                db.update("test", values, "name=?", new String[] { name });
            }
        }
    }
}

 

添加数据及读取数据函数

DataSQL sql = new DataSQL(this, 2);
        SQLiteDatabase db = sql.getWritableDatabase();
        Cursor cr = db.query("test", null, null, null, null, null, null);
        while (cr.moveToNext()) {
            Log.e("cr-name", "" + cr.getString(cr.getColumnIndex("name")));
            Log.e("cr-age", "" + cr.getInt(cr.getColumnIndex("age")));
        }

 

若是遇到复杂的修改操做,好比在修改的同时,须要进行数据的转移,那么能够采起在一个事务中执行以下语句来实现修改表的需求。
  1. 将表名改成临时表
         ALTERTABLE Test RENAME TO _Test;
  2. 建立新表
        CREATETABLE Test(id VARCHAR(32PRIMARYKEY ,UserName VARCHAR(32NOTNULL , Age VARCHAR(16NOTNULL);
      3. 导入数据  
         INSERTINTO Test SELECT id, “”, Age FROM _Test;
  或者  
        INSERTINTO Test() SELECT id, “”, Age FROM _Test;
  * 注意 双引号”” 是用来补充原来不存在的数据的!
      4. 删除临时表  
        DROPTABLE _Test;
  经过以上四个步骤,就能够完成旧数据库结构向新数据库结构的迁移,而且其中还能够保证数据不会由于升级而流失。
固然,若是遇到减小字段的状况,也能够经过建立临时表的方式来实现。测试

下面仍然经过一个例子来进行测试:this

  1.修改DataSQL的onUpgrade方法spa

if (newVersion == 3) {
            char str = '"';
            db.beginTransaction();
            db.execSQL("ALTER TABLE test RENAME TO _Test");
            db.execSQL("CREATE TABLE test(id integer primary key autoincrement , PassWord VARCHAR(20) NOT NULL,"
                    + " UserName VARCHAR(32) NOT NULL , Age VARCHAR(16) NOT NULL)");
            db.execSQL("INSERT INTO test SELECT id, " + str + str
                    + ", name, age FROM _Test");
            db.setTransactionSuccessful();
            db.endTransaction();
        }

 

2.修改Activity中打印信息

            Log.e("cr-name", "" + cr.getString(cr.getColumnIndex("UserName")));
            Log.e("cr-age", "" + cr.getInt(cr.getColumnIndex("Age")));
            Log.e("cr-password", "" + cr.getInt(cr.getColumnIndex("PassWord")));

 

在实际开发工做中,咱们的处理可能比上面所述的复杂;

  假如咱们开发的程序已经发布了两个版本:V1.0,V1.2,咱们正在开发V1.3。每一版的数据库版本号分别是8,9,10。对于这种状况,咱们应该如何实现升级?
用户的选择有:                   

  1) V1.0 -> V1.3  DB 8 -> 10                  
  2) V1.2 -> V1.3  DB 9 -> 10      
  3)注意:数据库的每个版本所表明的数据库必须是定义好的,好比说V1.0的数据库,它可能只有两张表TableA和TableB,若是V1.2要添加一张表TableC,若是V1.3要修改TableC,那么每个版本所对应的数据库结构以下:
V1.0  --->  TableA, TableB
V1.2  --->  TableA, TableB, TableC
V1.3  --->  TableA, TableB, TableC (Modify)

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
        int upgradeVersion  = oldVersion;
        if (8 == upgradeVersion) {
            // Create table C
            String sql = "CREATE TABLE ...";
            db.execSQL(sql);
            upgradeVersion = 9;
        }
        if (9 == upgradeVersion) {
            // Modify table C
            upgradeVersion = 10;
        }
        if (upgradeVersion != newVersion) {
            // Drop tables
            db.execSQL("DROP TABLE IF EXISTS " + tableName);
            // Create tables
            onCreate(db);
        }
    }

 

在onUpgrade()方法中,处理了数据库版本从8 -> 10的升级过程,这样作的话,不论用户从8 -> 10,仍是从9 - 10,最终程序的数据库都能升级到V1.3所对应的数据库结构。

二.导入已有数据库

  在有的状况下,咱们要在程序一开始运行的时候就导入某些固定的数据,而这些数据过大,又不可能直接代码写死,此时就须要经过导入已有数据库的方法导入数据,咱们知道raw文件夹下的东西,android会原封不动的拷贝到程序中,而不会转换为二进制文件,因此,咱们把数据库放到raw文件夹下供程序导入使用;

 

public class DBImporter {
    public static final String PACKAGE_NAME = "com.example.sql";
    public static final String DB_NAME = "xxx.db";
    public static String DB_PATH = "/data/data/" + PACKAGE_NAME;
    private Context context;

    public DBImporter(Context mContext) {
        this.context = mContext;
    }

    public SQLiteDatabase openDataBase() {
        return SQLiteDatabase.openOrCreateDatabase(DB_PATH + "/" + DB_NAME, null);
    }

    public void copyDB() {
        File file = new File(DB_PATH + "/" + DB_NAME);
        if (!file.exists()) {
            try {
                FileOutputStream out = new FileOutputStream(file);
                int buffer = 400000;
          // 读取数据库并保存到data/data/packagename/xx.db...
                InputStream ins = context.getResources().openRawResource(R.raw.sql_);
                byte[] bts = new byte[buffer];
                int length;
                while ((length = ins.read(bts)) > 0) {
                    out.write(bts, 0, bts.length);
                }
                out.close();
                ins.close();
                SQLiteDatabase.openOrCreateDatabase(DB_PATH + "/" + DB_NAME, null);
            } catch (FileNotFoundException e) {
            } catch (IOException e) {
            }
        }
    }
}

 

接下来即是在须要使用到该数据库的地方调用

 

        DBImporter importer = new DBImporter(this);
        importer.copyDB();
        SQLiteDatabase db = importer.openDataBase(); // 获取到数据库对象,接下来即可操做了~

 

 

 

 

转自: http://www.cnblogs.com/a284628487/p/3345820.html

相关文章
相关标签/搜索