SQLite數(shù)據(jù)庫,和其他的SQL數(shù)據(jù)庫不同, 我們并不需要在手機(jī)上另外安裝一個(gè)數(shù)據(jù)庫軟件,Android系統(tǒng)已經(jīng)集成了這個(gè)數(shù)據(jù)庫。
SQLite有什么特點(diǎn)
SQlite通過文件來保存數(shù)據(jù)庫,一個(gè)文件就是一個(gè)數(shù)據(jù)庫,數(shù)據(jù)庫中又包含多個(gè)表格,表格里又有 多條記錄,每個(gè)記錄由多個(gè)字段構(gòu)成,每個(gè)字段有對(duì)應(yīng)的值,每個(gè)值我們可以指定類型,也可以不指定 類型(主鍵除外)
為什么要用SQLite:
SP是一種輕量級(jí)數(shù)據(jù)存儲(chǔ)方式,存儲(chǔ)一些跟賬號(hào)密碼個(gè)人信息相關(guān)的數(shù)據(jù),如果數(shù)據(jù)繁雜這時(shí)候就要用到SQLite存儲(chǔ)以提高數(shù)據(jù)存取得效率。
幾個(gè)相關(guān)的類:
SQLiteOpenHelper
:抽象類,我們通過繼承該類,然后重寫數(shù)據(jù)庫創(chuàng)建以及更新的方法, 我們還可以通過該類的對(duì)象獲得數(shù)據(jù)庫實(shí)例,或者關(guān)閉數(shù)據(jù)庫!
SQLiteDatabase:數(shù)據(jù)庫訪問類:我們可以通過該類的對(duì)象來對(duì)數(shù)據(jù)庫做一些增刪改查的操作
Cursor:游標(biāo),有點(diǎn)類似于JDBC里的resultset,結(jié)果集!可以簡單理解為指向數(shù)據(jù)庫中某 一個(gè)記錄的指針!可以通過Cursor對(duì)數(shù)據(jù)進(jìn)行一行一行查詢的操作
?
使用SQLiteOpenHelper類創(chuàng)建數(shù)據(jù)庫與版本管理
安卓給我們提供了SQLiteOpenHelper的兩個(gè)方法, onCreate( )與onUpgrade( )來實(shí)現(xiàn)
onCreate(database)
:首次使用軟件時(shí)生成數(shù)據(jù)庫表
onUpgrade(database,oldVersion,newVersion)
:在數(shù)據(jù)庫的版本發(fā)生變化時(shí)會(huì)被調(diào)用, 一般在軟件升級(jí)時(shí)才需改變版本號(hào),而數(shù)據(jù)庫的版本是由程序員控制的,假設(shè)數(shù)據(jù)庫現(xiàn)在的 版本是1,由于業(yè)務(wù)的變更,修改了數(shù)據(jù)庫表結(jié)構(gòu),這時(shí)候就需要升級(jí)軟件,升級(jí)軟件時(shí)希望 更新用戶手機(jī)里的數(shù)據(jù)庫表結(jié)構(gòu),為了實(shí)現(xiàn)這一目的,可以把原來的數(shù)據(jù)庫版本設(shè)置為2 或者其他與舊版本號(hào)不同的數(shù)字即可!
?
?
public class MyDBOpenHelper extends SQLiteOpenHelper {
public MyDBOpenHelper(Context context, String name, CursorFactory factory,
int version) {super(context, "my.db", null, 1); }
@Override
//數(shù)據(jù)庫第一次創(chuàng)建時(shí)被調(diào)用
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE person(personid INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20))");
}
//軟件版本號(hào)發(fā)生改變時(shí)調(diào)用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD phone VARCHAR(12) NULL");
}
}?
我們會(huì)創(chuàng)建這個(gè)my.db的文件,并且會(huì)執(zhí)行onCreate()里的方法, 創(chuàng)建一個(gè)Person的表,他又兩個(gè)字段,主鍵personId和name字段;接著如我我們修改db的版本 號(hào),那么下次啟動(dòng)就會(huì)調(diào)用onUpgrade()里的方法,往表中再插入一個(gè)字段!另外這里是插入 一個(gè)字段,所以數(shù)據(jù)不會(huì)丟失,如果是重建表的話,表中的數(shù)據(jù)會(huì)全部丟失(下面數(shù)據(jù)庫更新解決)
?
流程:
Step 1:自定義一個(gè)類繼承SQLiteOpenHelper類
Step 2:在該類的構(gòu)造方法的super中設(shè)置好要?jiǎng)?chuàng)建的數(shù)據(jù)庫名,版本號(hào)
Step 3:重寫onCreate( )方法創(chuàng)建表結(jié)構(gòu)
Step 4:重寫onUpgrade( )方法定義版本號(hào)發(fā)生改變后執(zhí)行的操作
使用Android提供的API操作SQLite
?
db = myDBHelper.getWritableDatabase();
switch (v.getId()) {
case R.id.btn_insert:
ContentValues values1 = new ContentValues();
values1.put("name", "呵呵~" + i);
i++;
//參數(shù)依次是:表名,強(qiáng)行插入null值得數(shù)據(jù)列的列名,一行記錄的數(shù)據(jù)
db.insert("person", null, values1);
Toast.makeText(mContext, "插入完畢~", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_query:
sb = new StringBuilder();
//參數(shù)依次是:表名,列名,where約束條件,where中占位符提供具體的值,指定group by的列,進(jìn)一步約束
//指定查詢結(jié)果的排序方式
Cursor cursor = db.query("person", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
sb.append("id:" + pid + ":" + name + "\n");
} while (cursor.moveToNext());
}
cursor.close();
Toast.makeText(mContext, sb.toString(), Toast.LENGTH_SHORT).show();
break;
case R.id.btn_update:
ContentValues values2 = new ContentValues();
values2.put("name", "嘻嘻~");
//參數(shù)依次是表名,修改后的值,where條件,以及約束,如果不指定三四兩個(gè)參數(shù),會(huì)更改所有行
db.update("person", values2, "name = ?", new String[]{"呵呵~2"});
break;
case R.id.btn_delete:
//參數(shù)依次是表名,以及where條件與約束
db.delete("person", "personid = ?", new String[]{"3"});
break;
}
?
?
使用SQL語句操作數(shù)據(jù)庫
?
不想用Android提供的這些API, 你可以直接使用SQLiteDatabase給我們提供的相關(guān)方法:
execSQL(SQL,Object[]):使用帶占位符的SQL語句,這個(gè)是執(zhí)行修改數(shù)據(jù)庫內(nèi)容的sql語句用的
rawQuery(SQL,Object[]):使用帶占位符的SQL查詢操作 另外前面忘了介紹下Curosr這個(gè)東西以及相關(guān)屬性,這里補(bǔ)充下: ——
Cursor:對(duì)象有點(diǎn)類似于JDBC中的ResultSet,結(jié)果集!使用差不多,提供一下方法移動(dòng)查詢結(jié)果的記錄指針:
move(offset):指定向上或者向下移動(dòng)的行數(shù),整數(shù)表示向下移動(dòng);負(fù)數(shù)表示向上移動(dòng)!
moveToFirst():指針移動(dòng)到第一行,成功返回true,也說明有數(shù)據(jù)
moveToLast():指針移動(dòng)到最后一樣,成功返回true;
moveToNext():指針移動(dòng)到下一行,成功返回true,表明還有元素!
moveToPrevious():移動(dòng)到上一條記錄
getCount( )獲得總得數(shù)據(jù)條數(shù)
isFirst():是否為第一條記錄
isLast():是否為最后一項(xiàng)
moveToPosition(int):移動(dòng)到指定行
使用代碼示例:
//插入數(shù)據(jù)
public void save(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("INSERT INTO customer(customerName,deliveryPhone) values(?,?)",new String[]{customer.getCustomerName(),customer.getDeliveryPhone()});
}
//刪除數(shù)據(jù)
public void delete(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("DELETE FROM customer WHERE customerid=?",new Integer[]{customerid});
}
//更新數(shù)據(jù)
public void updata(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("UPDATA customer SET customerName=?,deliveryPhone=? WHERE customerid=?",new String[]{customer.getCustomerName(),customer.getDeliveryPhone(), String.valueOf(customer.getCustomerId())});
}
//查詢數(shù)據(jù)
public Customer select(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT * FROM customer WHERE customerid=?",new String[]{customerid.toString()});
//存在數(shù)據(jù)才返回true
if(cursor.moveToFirst()){
int id=cursor.getInt(cursor.getColumnIndex("customerid"));
String name=cursor.getString(cursor.getColumnIndex("customerName"));
String phone=cursor.getString(cursor.getColumnIndex("deliveryPhone"));
return new Customer(id,name,phone);
}
cursor.close();
return null;
}
//.數(shù)據(jù)分頁查詢
public List<Customer> getScrollData(int offset, int maxResult)
{
List<Customer> person = new ArrayList<Customer>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM person ORDER BY personid ASC LIMIT= ?,?",
new String[]{String.valueOf(offset),String.valueOf(maxResult)});
while(cursor.moveToNext())
{
int id = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
person.add(new Customer(id,name,phone)) ;
}
cursor.close();
return person;
}
//查詢記錄數(shù)
public long getCount()
{
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT COUNT (*) FROM customer",null);
cursor.moveToFirst();
long result = cursor.getLong(0);
cursor.close();
return result;
}
public void save(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("INSERT INTO customer(customerName,deliveryPhone) values(?,?)",new String[]{customer.getCustomerName(),customer.getDeliveryPhone()});
}
//刪除數(shù)據(jù)
public void delete(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("DELETE FROM customer WHERE customerid=?",new Integer[]{customerid});
}
//更新數(shù)據(jù)
public void updata(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("UPDATA customer SET customerName=?,deliveryPhone=? WHERE customerid=?",new String[]{customer.getCustomerName(),customer.getDeliveryPhone(), String.valueOf(customer.getCustomerId())});
}
//查詢數(shù)據(jù)
public Customer select(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT * FROM customer WHERE customerid=?",new String[]{customerid.toString()});
//存在數(shù)據(jù)才返回true
if(cursor.moveToFirst()){
int id=cursor.getInt(cursor.getColumnIndex("customerid"));
String name=cursor.getString(cursor.getColumnIndex("customerName"));
String phone=cursor.getString(cursor.getColumnIndex("deliveryPhone"));
return new Customer(id,name,phone);
}
cursor.close();
return null;
}
//.數(shù)據(jù)分頁查詢
public List<Customer> getScrollData(int offset, int maxResult)
{
List<Customer> person = new ArrayList<Customer>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM person ORDER BY personid ASC LIMIT= ?,?",
new String[]{String.valueOf(offset),String.valueOf(maxResult)});
while(cursor.moveToNext())
{
int id = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
person.add(new Customer(id,name,phone)) ;
}
cursor.close();
return person;
}
//查詢記錄數(shù)
public long getCount()
{
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT COUNT (*) FROM customer",null);
cursor.moveToFirst();
long result = cursor.getLong(0);
cursor.close();
return result;
}
?
除了上面獲取條數(shù)的方法外還可以使用cursor.getCount()方法獲得數(shù)據(jù)的條數(shù), 但是SQL語句要改改!比如SELECT * FROM customer;
?
SQLite事務(wù)
多個(gè)操作捆綁在一起,只有所有操作都執(zhí)行完畢,事務(wù)才會(huì)生效,如果其中有一個(gè)操作未執(zhí)行完畢,之前所有操作都會(huì)撤銷。
?
方法:
beginTransaction():開啟事務(wù)
endTransaction():結(jié)束事務(wù)
setTransactionSuccessful():結(jié)束事務(wù)有兩張方式,事務(wù)回滾或者事務(wù) 提交,默認(rèn)為false撤銷,如果提交設(shè)置為true.
簡單點(diǎn)說就是:寫在事務(wù)里的所有數(shù)據(jù)庫操作都成功,事務(wù)提交,否則,事務(wù)回滾到原始狀態(tài)
SQLite存儲(chǔ)大二進(jìn)制文件
一般我們很少往數(shù)據(jù)庫中存儲(chǔ)大二進(jìn)制文件,比如圖片,音頻,視頻等,對(duì)于這些我們一般 是存儲(chǔ)文件路徑,但總會(huì)有些奇葩的需求。以圖片為例子,將圖片保存到SQLite中,以及讀取SQLite中的圖片!
?
1.保存圖片到Sqlite中:
(1)創(chuàng)建數(shù)據(jù)庫表的時(shí)候,需要?jiǎng)?chuàng)建一個(gè)BLOB的字段,用于存儲(chǔ)二進(jìn)制值。
sqLiteDatabase.execSQL("CREATE TABLE test(_id INTEGER PRIMARY KEY AUTOINCREAMENT,head_img BLOB)");(2)將圖片轉(zhuǎn)換成BLOB格式(這里是ImageView為例,如果是普通圖片只需要轉(zhuǎn)換成Bitmap再調(diào)用即可)
try {
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
//壓縮為PNG格式,100標(biāo)示跟原圖大小一致
(BitmapDrawable)imageView.getDrawable().getBitmap().compress(Bitmap.CompressFormat.PNG,100,byteArrayOutputStream);
Object[] objects=new Object[]{byteArrayOutputStream.toByteArray()};
sqLiteDatabase.execSQL("INSERT INTO test(head_img) values(?)",objects);
byteArrayOutputStream.close();
sqLiteDatabase.close();
} catch (IOException e) {
e.printStackTrace();
}?
讀取SQLite中的圖片
//讀取SQLIte中的圖片
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT head_img FROM text",null);
if(cursor!=null){
if(cursor.moveToFirst()){
//取出圖片保存到字節(jié)數(shù)組中
byte[] img=cursor.getBlob(cursor.getColumnIndex("head_img"));
//將圖片顯示到Imageview上面
if(img!=null){
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(img);
imageView.setImageDrawable(Drawable.createFromStream(byteArrayInputStream,"img"));
}
}
cursor.close();
}
?
數(shù)據(jù)庫升級(jí)
假如我們已經(jīng)升級(jí)到第三個(gè)版本了,我們?cè)诘诙€(gè)版本增加了一個(gè)表,
然后第三個(gè)版本也增加了一個(gè)表,加入用戶直接從第一個(gè)版本升級(jí)到第三個(gè)版本,這樣
沒經(jīng)過第二個(gè)版本,就沒有增加的那個(gè)表,這可怎么破?
?
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgrade(db, oldVersion, newVersion);
}
private void upgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
if (oldVersion + 1 == newVersion) {
switch (oldVersion) {
case 1:
upgrade1_2(db);
break;
case 2:
upgrade2_3(db);
break;
case 3:
upgrade3_4(db);
case 4:
upgrade4_5(db);
case 5:
upgrade5_6(db);
case 6:
upgrade6_7(db);
case 7:
upgrade7_8(db);
case 8:
upgrade8_9(db);
default:
break;
}
return;
}
upgrade(db, oldVersion, newVersion - 1);
upgrade(db, newVersion - 1, newVersion);
}
}
private void upgrade1_2(SQLiteDatabase db) {
String sql = "drop table storage;";
db.execSQL(sql);
db.execSQL(storageSQL);
}