Android开发之利用SQLite进行数据存储
- Android开发之利用SQLite进行数据存储
- SQLite数据库简介
- Android中如何使用SQLite
- 1 创建SQLiteOpenHelper对象并创建表
- 2 通过SQLiteDatabase对象执行增删改查操作
- 3 SQLiteDatabase之事务transaction
1.SQLite数据库简介
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起M
ysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2015年已经有15个年头,SQLite也迎来了一个版本 SQLite 3已经发布。
总结 : SQLite作为移动终端的数据库是非常合适的,占用内存小、轻量级、处理速度快…
2.Android中如何使用SQLite
2.1 创建SQLiteOpenHelper对象,并创建表
新建一个类,命名为MySQLiteOpenHelper,并将其继承自SQLiteOpenHelper:
新建后会报错,因为没有添加构造方法,添加构造方法:
package com.example.sqllitetest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class MySQLOpenHelper extends SQLiteOpenHelper { public MySQLOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub } /** * 数据库创建时会调用,在这里执行创建表的语句 */ @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub } /** * 数据库升级时,此方法会调用,在这里执行数据库更新操作 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } /** * 数据库打开时,此方法会调用 */ @Override public void onOpen(SQLiteDatabase db) { // TODO Auto-generated method stub super.onOpen(db); } }
在上面的onCreate();方法中执行一条创建表名为person的语句
db.execSQL("create table person (_id integer primary key autoincrement, name char(10), age integer(3), phone integer(20))");
注意:其实在sqlite中除了id主键以外,所有的字段都没有明确的类型限制,举个列子,我们向integer类型的字段中插入char类型的数据也是可以的
那么既然这样,我们创建数据库时,指定的数据类型意图何在?
这些是为了,让我们程序员了解某个字段的类型限制,实际编码时,还是要指定字段明确类型的,方便日后维护和理解。
新建一个测试类SqliteTestCase.java:
package com.example.sqllitetest; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.test.AndroidTestCase; public class SqlliteTestCase extends AndroidTestCase { private MySQLOpenHelper oh; private SQLiteDatabase db; public void test() { System.out.println("This is test method!"); } /** * 测试框架初始化完毕过后,在测试方法调用之前调用此方法 */ @Override protected void setUp() throws Exception { super.setUp(); // 获得可写的数据库对象(若数据库不存在,先创建数据库,再获取可读可写的数据库对象;如果数据库存在,就直接打开) // *********************** 参数说明 *********************** // 参数1 : 获取Context对象,AndroidTestCase中为了方便测试,提供了getContext()方法 // 参数2 : 数据库文件名 // 参数3 : 游标工厂对象,被用来创建游标对象,默认为空 // 参数4 : 用来标识数据库的版本,用来与之前创建的时候做对比,当版本大于,则调用onUpgrade() oh = new MySQLOpenHelper(getContext(), "person.db", null, 1); /** * ************** 第一种方法:获取数据库 ************** * 1.被用来创建或打开一个可读写的数据库, * 当它被第一次调用的时候,会根据new SQLOpenHelper()中的数据库名和版本号 * 当已存在相同数据库文件,并且版本号相同,则直接打开, * 反之,则调用创建或更新方法。 * * 2.数据一旦打开成功,将被缓存起来,当我们在需要录入数据时,可以在任何地方去调用返回 * 的对象去操作数据库,注意:但不需要使用数据库时,需要关闭数据库 * * 3.但没有权限时,抑或磁盘满了的时候,这个方法将会被调用失败,但是,若问题得到解决,即可成功调用 * * 4.调用这个方法,若触发更新操作,你就需要警觉了: * 因为数据库的更新是个耗时的操作,我们不应该在应用的主线程中去调用它,包括ContentProvider.onCreate() * */ db = oh.getWritableDatabase(); /** * ************** 第二种方法:获取数据库 ************** * 不要被名字误导,这个方法同样可获得可读写的数据库对象, * 它与上面方法的区别是,当遇到一些问题:(列如:磁盘满了,这个时候调用不会失败,而是将会返回一个只读的数据库对象) */ db = oh.getReadableDatabase(); } /** * 测试方法执行完毕过后,调用此方法 */ @Override protected void tearDown() throws Exception { // TODO Auto-generated method stub super.tearDown(); // 关闭数据库 db.close(); } }
注意:当我们new SQLiteOpenHelper()打开某个数据库时,传入的版本号不应比之前创建这个数据库的时候绑定的版本号低,否则会出现下面的错误,版本号只能递增
运行test()方法,显示为绿色,说明没有错误
通过DDMS–>File Explore,查看data/data/项目包名/databases目录下:
导出文件,在SQLite Expert软件中打开:
可以看到,数据库和表都被正确创建。
2.2 通过SQLiteDatabase对象执行增删改查操作
2.2.1添加数据操作
添加数据有两种方法:
- 第一种方法 : 通过手写sql语句,执行execSQL();方法;
在SqliteTestCase.java中添加insert()方法
public void insert() { db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"张三", 18, "180199678455"}); db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"赵四", 16, "180199678455"}); db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"Android", 15, "180199678455"}); }
执行结果,数据成功插入表中:
- 第二种方法 : 通过Android API,将数据封装到contentValues中;
在SqliteTestCase.java中添加insertByApi()方法:
public void insertApi() { // 把所有的数据封装到contentValues中 ContentValues values = new ContentValues(); values.put("name", "zhangsan"); values.put("age", 78); values.put("phone", "13812235689"); // 参数说明: // 第一个参数table : 表名 // 第二个参数nullColumnHack :可以指定为null,若为null,当你values中无值,则不会插入行 // 若你指定了nullColumnHack的值,即便你的values中无值,也会 // 插入null值到你的字段下 // 第三个参数values : ContentValues对象 db.insert("person", null, values); }
导出db文件,刷新:
2.2.1删除数据操作
删除数据同样有两种方法:
- 第一种方法 : 通过手写sql语句,执行execSQL();方法;
public void delete() { // 删除id为1的行 db.execSQL("delete from person where _id = ?", new Object[]{1}); }
- 第二种方法 : 通过Android API;
public void deleteApi() { // 删除表中age = 78, id = 4的记录 // 返回值为受影响的行,删除了多少行 int i = db.delete("person", "age = ? and _id = ?", new String[]{"78", "4"}); }
2.2.1修改数据操作
修改数据同样有两种方法:
- 第一种方法 : 通过手写sql语句,执行execSQL()方法:
public void update() { // 修改id为2的phone值为110 db.execSQL("update person set phone = ? where _id = ?", new Object[]{"110", 2}); }
查看结果:
- 第二种方法 : 通过Android API;
public void updateApi() { // 通过ContentValues来指定修改后的值 ContentValues values = new ContentValues(); values.put("phone", "120"); // 返回值为受影响的行 int i = db.update("person", values, "_id = ? and age = ?", new String[]{"3", "15"}); }
查看结果:
2.2.1查询数据操作
查询数据同样有两种方法:
- 第一种方法 : rawQuery()方法:
public void query() { Cursor cursor = db.rawQuery("select name, age, phone from person ", null); while (cursor.moveToNext()) { // 不推荐用这种下标的方式来获取值,一旦后期字段的位置有所改动,维护起来比较麻烦 // String name = cursor.getString(0); // int age = cursor.getInt(1); // String phone = cursor.getString(2); // 推荐使用 String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); String phone = cursor.getString(cursor.getColumnIndex("phone")); System.out.println("name : " + name + "; age = " + age + ";" + " phone = " + phone); } }
logcat输出结果:
- 第二种方法 : 通过Android API;
public void queryApi() { Cursor cursor = db.query("person", null, null, null, null, null, null); while (cursor.moveToNext()) { String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); String phone = cursor.getString(cursor.getColumnIndex("phone")); System.out.println("name : " + name + "; age = " + age + ";" + " phone = " + phone); } }
2.3 SQLiteDatabase之事务transaction
应用场景:当需要保证多条语句同时执行成功,否则,回滚
这里,我们简单的模拟一下,假设我们需要id为2的age加1岁,同时又要保证id为3的age减1岁
原本数据在数据库中是这样:
如果事务执行成功后,name为赵四的age将变为17,而name为Android的age变为14,反之,两条数据的所有属性值不变。
首先,我们人为的导致执行失败:
添加方法:
public void transaction() { try { // 开启事务 db.beginTransaction(); ContentValues values = new ContentValues(); values.put("age", 17); db.update("person", values, "_id = ?", new String[]{"2"}); values.clear(); values.put("age", 14); db.update("person", values, "_id = ?", new String[]{"3"}); int i = 1 / 0; // 这里有错,将导致事务执行失败 // 设置事务执行成功 db.setTransactionSuccessful(); } catch (Exception e) { // TODO: handle exception } finally { // 结束事务,同时提交,如果已经设置事务执行成功,则sql语句生效,反之,则回滚 db.endTransaction(); } }
导出db文件,刷新,看到数据无任何变化:
再将错误去掉,执行方法:
结果如下,执行成功:
版权声明:本文为博主原创文章,未经博主允许不得转载。