SQLiteOperHelper对数据库进行版本管理
如果应用使用到了SQLite数据库,在用户初次使用软件时,需要创建应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。在Android系统,为我们提供了一个名为SQLiteOpenHelper的类,该类用于对数据库版本进行管理,该类是一个抽象类,必须继承它才能使用。 为了实现对数据库版本进行管理,SQLiteOpenHelper类有两种重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。
getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。但getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。
public class DatabaseHelperextends SQLiteOpenHelper {
//类没有实例化,是不能用作父类构造器的参数,必须声明为静态
privatestatic final String name = "itcast";//数据库名称
privatestatic final intversion = 1;//数据库版本
public DatabaseHelper(Contextcontext) {
//第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
super(context,name, null, version);
}ee
@Override public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATETABLE IF NOT EXISTS person (personidinteger primary key autoincrement,name varchar(20),age INTEGER)");
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROPTABLE IF EXISTS person");
onCreate(db);
}
}
上面onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失。
第一次调用getWritableDatabase()或getReadableDatabase()方法后,SQLiteOpenHelper会缓存当前的SQLiteDatabase实例,SQLiteDatabase实例正常情况下会维持数据库的打开状态,所以在你不再需要SQLiteDatabase实例时,请及时调用close()方法释放资源。一旦SQLiteDatabase实例被缓存,多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例。
package com.xqq.domain; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.widget.ListView; import com.xqq.Db.MySQLieHelper; import com.xqq.entity.Person; public class PersonService { private MySQLieHelper dbOpenHelper; private Context context; public PersonService(Context context) { super(); this.context = context; dbOpenHelper = new MySQLieHelper(context); } public void save(Person person) { SQLiteDatabase database=dbOpenHelper.getWritableDatabase(); database.beginTransaction(); try { database.execSQL("INSERT into person(name,age) values(?,?)", new Object[] { person.getName(), person.getAge() }); database.setTransactionSuccessful(); } catch (Exception e) { } database.endTransaction(); } public void update(Person person) { SQLiteDatabase db=dbOpenHelper.getWritableDatabase(); db.execSQL("update person set name=?,age=? where personid=?", new Object[]{person.getName(),person.getAge(),person.getId()}); } public Person find(Integer id) { SQLiteDatabase db=dbOpenHelper.getWritableDatabase(); Cursor cursor=db.rawQuery("select * from person where personid=?", new String[]{String.valueOf(id)}); Person person=new Person(); if(cursor.moveToNext()){ person.setAge(cursor.getInt(cursor.getColumnIndex("age"))); person.setName(cursor.getString(cursor.getColumnIndex("name"))); } return person; } public void delete(Integer... ids) { if(ids.length>0){ StringBuilder sb=new StringBuilder(); for (Integer id : ids) { sb.append("?").append(","); } sb.deleteCharAt(sb.length()-1); SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); db.execSQL("delete from person where personid in ( "+sb+" )",(Object[])ids); } } public List<Person> getScrollData(int startResult, int maxResult) { List<Person> persons=new ArrayList<Person>(); SQLiteDatabase db = dbOpenHelper.getWritableDatabase(); Cursor cursor=db.rawQuery("select * from person limit ?,?", new String[]{String.valueOf(startResult),String.valueOf(maxResult)}); while(cursor.moveToNext()){ Person person=new Person(); person.setAge(cursor.getInt(cursor.getColumnIndex("age"))); person.setName(cursor.getString(cursor.getColumnIndex("name"))); persons.add(person); } return persons; } public long getCount(){ SQLiteDatabase db=dbOpenHelper.getWritableDatabase(); Cursor cursor=db.rawQuery("select count(*) from person", null); if(cursor.moveToNext()){ return cursor.getLong(0); } return 0; } }
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务。当应用需要提交事务,必须在程序执行到endTransaction()方法之前使用setTransactionSuccessful() 方法设置事务的标志为成功,如果不调用setTransactionSuccessful() 方法,默认会回滚事务。使用例子如下:
SQLiteDatabasedb= ....;
db.beginTransaction();//开始事务
try{
db.execSQL("insertinto person(name, age) values(?,?)", new Object[]{"传智播客",4});
db.execSQL("updateperson set name=? where personid=?",new Object[]{"传智",1});
db.setTransactionSuccessful();//调用此方法会在执行到endTransaction()时提交当前事务,如果不调用此方法会回滚事务
}finally {
db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
}
db.close();
上面两条SQL语句在同一个事务中执行。