SQLite數(shù)據(jù)庫险毁,和其他的SQL數(shù)據(jù)庫不同制圈, 我們并不需要在手機上另外安裝一個數(shù)據(jù)庫軟件,Android系統(tǒng)已經(jīng)集成了這個數(shù)據(jù)庫辱揭。
SQLite有什么特點
SQlite通過文件來保存數(shù)據(jù)庫离唐,一個文件就是一個數(shù)據(jù)庫,數(shù)據(jù)庫中又包含多個表格问窃,表格里又有 多條記錄亥鬓,每個記錄由多個字段構(gòu)成,每個字段有對應(yīng)的值域庇,每個值我們可以指定類型嵌戈,也可以不指定 類型(主鍵除外)
為什么要用SQLite:
SP是一種輕量級數(shù)據(jù)存儲方式,存儲一些跟賬號密碼個人信息相關(guān)的數(shù)據(jù)听皿,如果數(shù)據(jù)繁雜這時候就要用到SQLite存儲以提高數(shù)據(jù)存取得效率熟呛。
幾個相關(guān)的類:
SQLiteOpenHelper
:抽象類,我們通過繼承該類尉姨,然后重寫數(shù)據(jù)庫創(chuàng)建以及更新的方法庵朝, 我們還可以通過該類的對象獲得數(shù)據(jù)庫實例,或者關(guān)閉數(shù)據(jù)庫又厉!
SQLiteDatabase:數(shù)據(jù)庫訪問類:我們可以通過該類的對象來對數(shù)據(jù)庫做一些增刪改查的操作
Cursor:游標(biāo)九府,有點類似于JDBC里的resultset,結(jié)果集覆致!可以簡單理解為指向數(shù)據(jù)庫中某 一個記錄的指針侄旬!可以通過Cursor對數(shù)據(jù)進(jìn)行一行一行查詢的操作
?
使用SQLiteOpenHelper類創(chuàng)建數(shù)據(jù)庫與版本管理
安卓給我們提供了SQLiteOpenHelper的兩個方法, onCreate( )與onUpgrade( )來實現(xiàn)
onCreate(database)
:首次使用軟件時生成數(shù)據(jù)庫表
onUpgrade(database,oldVersion,newVersion)
:在數(shù)據(jù)庫的版本發(fā)生變化時會被調(diào)用, 一般在軟件升級時才需改變版本號煌妈,而數(shù)據(jù)庫的版本是由程序員控制的儡羔,假設(shè)數(shù)據(jù)庫現(xiàn)在的 版本是1宣羊,由于業(yè)務(wù)的變更,修改了數(shù)據(jù)庫表結(jié)構(gòu)汰蜘,這時候就需要升級軟件仇冯,升級軟件時希望 更新用戶手機里的數(shù)據(jù)庫表結(jié)構(gòu),為了實現(xiàn)這一目的鉴扫,可以把原來的數(shù)據(jù)庫版本設(shè)置為2 或者其他與舊版本號不同的數(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)建時被調(diào)用
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE person(personid INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20))");
}
//軟件版本號發(fā)生改變時調(diào)用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD phone VARCHAR(12) NULL");
}
}
?
我們會創(chuàng)建這個my.db的文件澈缺,并且會執(zhí)行onCreate()里的方法坪创, 創(chuàng)建一個Person的表,他又兩個字段姐赡,主鍵personId和name字段莱预;接著如我我們修改db的版本 號,那么下次啟動就會調(diào)用onUpgrade()里的方法项滑,往表中再插入一個字段依沮!另外這里是插入 一個字段,所以數(shù)據(jù)不會丟失枪狂,如果是重建表的話危喉,表中的數(shù)據(jù)會全部丟失(下面數(shù)據(jù)庫更新解決)
?
流程:
Step 1:自定義一個類繼承SQLiteOpenHelper類
Step 2:在該類的構(gòu)造方法的super中設(shè)置好要創(chuàng)建的數(shù)據(jù)庫名,版本號
Step 3:重寫onCreate( )方法創(chuàng)建表結(jié)構(gòu)
Step 4:重寫onUpgrade( )方法定義版本號發(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ù)依次是:表名,強行插入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條件,以及約束毒姨,如果不指定三四兩個參數(shù)哑蔫,會更改所有行
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語句,這個是執(zhí)行修改數(shù)據(jù)庫內(nèi)容的sql語句用的
rawQuery(SQL,Object[]):使用帶占位符的SQL查詢操作 另外前面忘了介紹下Curosr這個東西以及相關(guān)屬性闸迷,這里補充下: ——
Cursor:對象有點類似于JDBC中的ResultSet,結(jié)果集!使用差不多,提供一下方法移動查詢結(jié)果的記錄指針:
move(offset):指定向上或者向下移動的行數(shù),整數(shù)表示向下移動;負(fù)數(shù)表示向上移動!
moveToFirst():指針移動到第一行,成功返回true,也說明有數(shù)據(jù)
moveToLast():指針移動到最后一樣,成功返回true;
moveToNext():指針移動到下一行,成功返回true,表明還有元素泉懦!
moveToPrevious():移動到上一條記錄
getCount( )獲得總得數(shù)據(jù)條數(shù)
isFirst():是否為第一條記錄
isLast():是否為最后一項
moveToPosition(int):移動到指定行
使用代碼示例:
//插入數(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ù)
多個操作捆綁在一起勋又,只有所有操作都執(zhí)行完畢于个,事務(wù)才會生效,如果其中有一個操作未執(zhí)行完畢邦投,之前所有操作都會撤銷。
?
方法:
beginTransaction():開啟事務(wù)
endTransaction():結(jié)束事務(wù)
setTransactionSuccessful():結(jié)束事務(wù)有兩張方式酣栈,事務(wù)回滾或者事務(wù) 提交险胰,默認(rèn)為false撤銷,如果提交設(shè)置為true.
簡單點說就是:寫在事務(wù)里的所有數(shù)據(jù)庫操作都成功矿筝,事務(wù)提交起便,否則,事務(wù)回滾到原始狀態(tài)
SQLite存儲大二進(jìn)制文件
一般我們很少往數(shù)據(jù)庫中存儲大二進(jìn)制文件窖维,比如圖片榆综,音頻,視頻等铸史,對于這些我們一般 是存儲文件路徑鼻疮,但總會有些奇葩的需求。以圖片為例子琳轿,將圖片保存到SQLite中判沟,以及讀取SQLite中的圖片!
?
1.保存圖片到Sqlite中:
(1)創(chuàng)建數(shù)據(jù)庫表的時候崭篡,需要創(chuàng)建一個BLOB的字段挪哄,用于存儲二進(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īng)升級到第三個版本了,我們在第二個版本增加了一個表塘偎,
然后第三個版本也增加了一個表疗涉,加入用戶直接從第一個版本升級到第三個版本,這樣
沒經(jīng)過第二個版本吟秩,就沒有增加的那個表咱扣,這可怎么破?
?
@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);
}