像我们做的很多应用程序及网站一样,基本都是对数据库进行增删改查来实现相应的功能。那么Android开发也一样,不过由于在移动客户端应用,所以不会像sql server、mysql那么复杂,Android应用程序支持本地数据库,SQLiteDatabase,通俗的说就是在手机上我们开发的应用程序中创建一个数据库,然后我们可以在手机上对我们的数据进行增删改查,不过这并不是绝对的,像前段时间我们开发一个小组OA,需要多人使用,功能简单,但需要大家连接到一个数据库中进行数据读取操作,所以这种情况下就要考虑到用mysql这样的数据库,最后选择了用php操作后台,然后然会Android进行数据处理,不过对于我们使用的2G网络很多程度上对速度还是有影响的。缓存这一块接触的比较少,计划等到Android这一块学的差不多了再研究其稍底层的一些开发。
这篇文章主要向大家分享如何操作SQLiteDatabase。
当然首先我们要了解SQLiteDatabase,它具有很多优点:
SQLite特性:
1. 轻量级
2. 独立性
3. 隔离性
SQLite数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件内,方便管理和维护。
4. 跨平台
5. 多语言接口
6. 安全性
SQLite数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。在某个进程或现成向数据库执行操作之前,必须获得独占锁定。在发出独占锁定以后,其他的读或写操作将不会再发生。
创建和打开数据库:
openOrCreateDatabase(),自动检测是否存在这个数据库,如果存在则打开,否则创建,创建成功会返回一个SQLiteDatabase对象,否则抛出异常FileNotFoundException:
mSQLiteDatabase = this.openOrCreateDatabase("abc.db",MODE_PRIVATE,null);
创建表:
execSQL():
String Create_Table = "Create table table1...";
mSQLiteDatabase.execSQL(Create_Table);
向表中添加数据:
insert方法需要把数据打包到ContentValues中,ContentValues其实就是一个Map,Key值是字段名称,Value值是字段的值。通过ContentValues的put方法就可以把数据放到ContentValues对象中,然后插入到表中:
ContentValue cv = new ContentValues();
cv.put(table_num,1);
mSQLiteDatabase.insert(TABLE_NAME,null,cv);
从表中删除数据:
delete():
mSQLiteDatabase.delete("abc.db","where...",null);
修改表数据:
update():
ContentValues cv = new ContentValues();
cv.put(TABLE_NUM,3);
mSQLiteDatabase.update("table1",cv,"num"+"="+Integer.toString(0),null);
当然,插入、删除和修改操作也可以通过execSQL(sql)方法来实现。
关闭数据库:
mSQLiteDatabase.close();
删除指定表:
mSQLiteDatabase.execSQL("DROP TABLE table1");
删除数据库:
this.deleteDatabase("abc.db");
查询表中的某条记录:
通过Cursor类实现,当使用SQLiteDatabase.query()方法时,会得到一个Cursor对象,Cursor指向的就是每一条数据。它提供了很多有关查询的方法:
方法 |
说明 |
move |
以当前位置为参考,将Cursor移动到指定的位置,成功返回true |
moveToPosition |
将Cursor移动的指定的位置,返回boolean |
moveToNext |
将Cursor向前移动一个位置,返回boolean |
moveToLast |
将Cursor向后移动一个位置,返回boolean |
moveToFirst |
将Cursor移动的第一行,返回boolean |
isBeforeFirst |
返回Cursor是否指向第一项数据之前 |
isAfterLast |
返回Cursor是否指向最后一项数据之后 |
isClosed |
返回Cursor是否关闭 |
isFirst |
返回Cursor是否指向第一项数据 |
isLast |
返回Cursor是否指向最后一项数据 |
isNull |
返回指定位置的值是否为null |
getCount |
返回总的数据项数 |
getInt |
返回当前行指定索引的数据 |
例如:
Cursor cur = mSQLiteDatabase.rawQuery("select * from table",null);
if(cur != null)
{
if(cur.moveToFirst())
{
do{
int numColumn = cur.getColumnIndex("num");
int num = cur.getInt(numColumn);
}while(cur.moveToNext());
}
}
使用SQLiteDatabase数据库后要及时关闭,否则可能会抛出SQLiteException异常。
上面的方法像大部分基础语法书上一样直接执行sql语句的形式,那么在Android中为了简化用户操作以及提高性能,Android系统提供了SQLiteOpenHelper,封装了常用的数据库操作方法。利用它我们可以很轻松的完成对数据库的增删改查。
首先我们创建一个DBHelper类继承SQLiteOpenHelper,用它来完成数据库的初始化工作:创建数据库,创建表等操作。
他包含一些借口方法,在下面的注释里已经注释的很详细,就不再罗嗦。
1 package com.example.core; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteDatabase.CursorFactory; 6 import android.database.sqlite.SQLiteOpenHelper; 7 8 public class DBHelper extends SQLiteOpenHelper{ 9 10 public DBHelper(Context context) { 11 //创建数据库名为march_test.db的数据库 12 super(context,"march_test.db",null,1); 13 } 14 15 /* (non-Javadoc) 16 * 数据库每次被创建时调用 17 * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase) 18 */ 19 @Override 20 public void onCreate(SQLiteDatabase db) { 21 //创建数据库表 22 String create_sql = "CREATE TABLE student(id integer primary key autoincrement," + 23 "name varchar(20),age integer not null)"; 24 db.execSQL(create_sql); 25 } 26 27 /* (non-Javadoc) 28 * 版本号发生变化时执行 29 * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int) 30 */ 31 @Override 32 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 33 // TODO Auto-generated method stub 34 String alter_sql = "ALTER TABLE student ADD money integer"; 35 db.execSQL(alter_sql); 36 } 37 38 }
通过实例化这个类,可以创建一个名为march_test.db的数据库。包含数据表student。可以文件系统中看到:
路径为data/data/包名/databases/数据库名:
这种db格式的数据库在这里给大家推荐一个非常好用的工具SQLite Expert Professional,非常好用,在网上也很好找到。他mysql workbench等数据库可视化工具一样给我们提供了可视化数据库操作,软件界面如下:
我们可以把我们创建的表在文件系统中导出来然后放到这里查看。
首先要声明我们要操作的数据类型类:
1 package com.example.sqllite; 2 3 public class Student{ 4 5 private Integer id; 6 private String name; 7 private Integer age; 8 9 public Student(Integer id, String name, Integer age) { 10 super(); 11 this.id = id; 12 this.name = name; 13 this.age = age; 14 } 15 16 public Student(String name , Integer age){ 17 super(); 18 this.name = name; 19 this.age = age; 20 } 21 22 public Integer getId() { 23 return id; 24 } 25 26 public void setId(Integer id) { 27 this.id = id; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 38 public Integer getAge() { 39 return age; 40 } 41 42 public void setAge(Integer age) { 43 this.age = age; 44 } 45 46 @Override 47 public String toString() { 48 return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; 49 } 50 51 }
下面要编写对数据库的增删改查类,它继承我们上面创建的SQLiteOpenHelper为基类的DBHelper类:
1 package com.example.core; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.content.Context; 7 import android.database.Cursor; 8 import android.database.sqlite.SQLiteDatabase; 9 10 import com.example.sqllite.Student; 11 12 /** 13 * @author fanchangfa 14 *数据库操作类 15 *增删改查 16 *获取分页查询数据 17 *获取表中记录总数 18 */ 19 public class DbServer{ 20 21 private DBHelper dbhelper; 22 23 public DbServer(Context context){ 24 this.dbhelper = new DBHelper(context); 25 } 26 27 /** 28 * 增加信息 29 * @param student 增加的学生信息 30 */ 31 public void add(Student student){ 32 SQLiteDatabase db = dbhelper.getWritableDatabase(); 33 db.execSQL("insert into student(name , age) values(?,?)", 34 new Object[]{student.getName(),student.getAge()}); 35 } 36 37 /** 38 * 删除信息 39 * @param id 要删除的学生id 40 */ 41 public void delete(Integer id){ 42 SQLiteDatabase db = dbhelper.getWritableDatabase(); 43 db.execSQL("delete from student where id = ?",new Object[]{id}); 44 } 45 46 /** 47 * 修改指定id的学生信息 48 * @param stu 包括修改学生的id,以及修改的信息 49 */ 50 public void alter(Student stu){ 51 SQLiteDatabase db = dbhelper.getWritableDatabase(); 52 db.execSQL("update student set name=?,age=? where id=?", 53 new Object[]{stu.getName(),stu.getAge(),stu.getId()}); 54 } 55 56 /** 57 * 查找信息 58 * @param id 要查找的学生id 59 */ 60 public Student find(Integer id){ 61 SQLiteDatabase db = dbhelper.getReadableDatabase(); 62 Cursor cursor = db.rawQuery("select * from student where id = ?",new String[]{id.toString()}); 63 64 if(cursor.moveToFirst()) //如果查询结果集中有数据,将游标指向第一条记录 65 { 66 int sid = cursor.getInt(cursor.getColumnIndex("id")); 67 String name = cursor.getString(cursor.getColumnIndex("name")); 68 int age = cursor.getInt(cursor.getColumnIndex("age")); 69 70 return new Student(sid , name , age); 71 } 72 73 cursor.close(); 74 75 return null; 76 } 77 78 /** 79 * 分页查询数据 80 * @param start 分页开始记录数 81 * @param end 分页结束记录数 82 * @return 查询结果集 83 */ 84 public List<Student> page(int start , int end){ 85 SQLiteDatabase db = dbhelper.getReadableDatabase(); 86 List<Student> page = new ArrayList<Student>(); 87 Cursor cur = db.rawQuery("select id,name,age from student order by id limit ?,?", 88 new String[]{String.valueOf(start),String.valueOf(end)}); 89 90 while(cur.moveToNext()){ 91 int id = cur.getInt(cur.getColumnIndex("id")); 92 String name = cur.getString(cur.getColumnIndex("name")); 93 int age= cur.getInt(cur.getColumnIndex("age")); 94 page.add(new Student(id,name,age)); 95 } 96 97 cur.close(); 98 99 return page; 100 } 101 102 /** 103 * 返回指定分页数据 104 * @param start 105 * @param end 106 * @return Cursor型数据 107 */ 108 public Cursor curpage(int start , int end){ 109 SQLiteDatabase db = dbhelper.getReadableDatabase(); 110 Cursor cur = db.rawQuery("select id as _id,name,age from student order by id limit ?,?", 111 new String[]{String.valueOf(start),String.valueOf(end)}); 112 113 cur.moveToFirst(); 114 115 return cur; 116 } 117 118 /** 119 * 获取表记录总数 120 * @return 121 */ 122 public long getCount(){ 123 SQLiteDatabase db = dbhelper.getReadableDatabase(); 124 125 Cursor cur = db.rawQuery("select count(*) from student",null); 126 cur.moveToFirst(); 127 128 long count = cur.getLong(0); 129 130 cur.close(); 131 132 return count; 133 } 134 135 /** 136 * 执行事务 137 */ 138 public void transaction(){ 139 SQLiteDatabase db = dbhelper.getWritableDatabase(); 140 db.beginTransaction(); 141 142 try{ 143 db.execSQL("update student set age = 21 where id =5"); 144 db.execSQL("update student set age= 22 where id=6"); 145 db.setTransactionSuccessful(); 146 //事务默认有commit、rollback,默认为False,即非提交状态,需要设置为commit 147 } 148 finally{ 149 db.endTransaction(); 150 } 151 152 } 153 }
具体操作代码中已经注释完善,可以进行试验。
下面要对其进行测试:
编写测试单元如下:
1 package com.example.test; 2 3 import java.util.List; 4 5 import com.example.core.DbServer; 6 import com.example.sqllite.Student; 7 8 import android.test.AndroidTestCase; 9 import android.util.Log; 10 11 /** 12 * @author fanchangfa 13 * 数据库操作单元测试 14 * 测试DbServer中数据的增删改查 15 * 16 */ 17 public class DbServerTest extends AndroidTestCase{ 18 19 //控制台打印信息标志 20 private static final String TAG = "SQLtest"; 21 22 /** 23 * 添加数据测试 24 */ 25 public void addTest(){ 26 DbServer dbserver = new DbServer(this.getContext()); 27 for(int i = 0 ; i<20 ; i++) 28 { 29 Student stu = new Student("fanchangfa"+i,20); 30 dbserver.add(stu); 31 } 32 } 33 34 public void deleteTest(){ 35 DbServer dbserver = new DbServer(this.getContext()); 36 dbserver.delete(2); 37 } 38 39 public void alterTest(){ 40 DbServer dbserver = new DbServer(this.getContext()); 41 Student stu = dbserver.find(3); 42 stu.setName("liuzihang"); 43 stu.setAge(25); 44 dbserver.alter(stu); 45 } 46 47 /** 48 * 测试数据库查找 49 * 根据提供id返回记录结果 50 */ 51 public void findTest(){ 52 DbServer dbserver = new DbServer(this.getContext()); 53 Student stu = dbserver.find(5); 54 Log.i(TAG, stu.toString()); 55 } 56 57 /** 58 * 数据库查找分页测试 59 */ 60 public void findpage(){ 61 DbServer dbserver = new DbServer(this.getContext()); 62 List<Student> students = dbserver.page(0, 8); 63 64 for(Student stu : students){ 65 Log.i(TAG,stu.toString()); 66 } 67 68 } 69 70 /** 71 * 执行事务测试 72 */ 73 public void transactionTest(){ 74 DbServer dbserver = new DbServer(this.getContext()); 75 dbserver.transaction(); 76 } 77 78 }
经验证,没有问题,由于此文件系统和操作比较麻烦,我将自己写的实例放到这里共大家下载,此实例中包括数据库的操作以及SQLite中事物的使用,以及将在下一篇写的关于ListView显示数据的几种方法,界面虽然很难看,不过这只是demo,希望多多谅解,有问题多多交流。希望这里会是我们拥有共同爱好的程序员们相互交流共同进步的平台,而不是只是为了增加访问量而将文章放在这里。