像我們做的很多應用程序及網站一樣,基本都是對數據庫進行增刪改查來實現相應的功能。那么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,希望多多諒解,有問題多多交流。希望這里會是我們擁有共同愛好的程序員們相互交流共同進步的平台,而不是只是為了增加訪問量而將文章放在這里。