SQLite是一種嵌入式的數(shù)據(jù)庫(kù)引擎驯妄,最后是以文件的形式保存數(shù)據(jù)的能耻,專門適用于資源有限的設(shè)備上進(jìn)行適量的數(shù)據(jù)存儲(chǔ)帆竹,而Android全面支持標(biāo)準(zhǔn)的SQLite數(shù)據(jù)庫(kù)绕娘。
所有創(chuàng)建的SQLite數(shù)據(jù)庫(kù),僅限于當(dāng)前應(yīng)用訪問(wèn)栽连,如果其他應(yīng)用需要訪問(wèn)险领,則必須提供的ContentProvider的支持侨舆,并且SQLite數(shù)據(jù)庫(kù)會(huì)隨著Android應(yīng)用的卸載而被刪除。
從本質(zhì)上來(lái)看绢陌,SQLite的操作方式只是一種更為便捷的文件操作挨下,當(dāng)應(yīng)用程序創(chuàng)建或打開(kāi)一個(gè)SQLite數(shù)據(jù)庫(kù)時(shí),其實(shí)只是打開(kāi)一個(gè)文件準(zhǔn)備讀寫脐湾。
因?yàn)镾QLite僅適用于資源有限的小型設(shè)備臭笆,所以本身就不應(yīng)該把大量數(shù)據(jù)存儲(chǔ)在設(shè)備的SQLite數(shù)據(jù)庫(kù)里,SQLite只適合存儲(chǔ)一些小型的數(shù)據(jù)秤掌。
為了使SQLite和其他數(shù)據(jù)庫(kù)間的兼容性最大化愁铺,SQLite支持對(duì)列上類型進(jìn)行“類型近似”,列的類型近似指的是存儲(chǔ)在列上的數(shù)據(jù)進(jìn)行推薦類型存儲(chǔ)闻鉴。所以雖然SQLite內(nèi)部只支持null(空)茵乱、integer(整型)、real(浮點(diǎn)數(shù))椒拗、text(文本)和blob(二進(jìn)制)這五種數(shù)據(jù)類型似将,但實(shí)際上SQLite完全可以接受varchar(n)、char(n)蚀苛、decimal(p, s)在验、date等類型數(shù)據(jù),只不過(guò)SQLite會(huì)在運(yùn)算或保存時(shí)將它們轉(zhuǎn)換為上面五種數(shù)據(jù)類型中相應(yīng)的類型堵未。大多數(shù)數(shù)據(jù)庫(kù)的引擎都是使用靜態(tài)的腋舌、強(qiáng)類型的數(shù)據(jù)類型,數(shù)據(jù)的類型是由它的容器決定的渗蟹,這個(gè)容器是指被存放的特定列块饺。而SQLite使用的是動(dòng)態(tài)類型,在SQLite中雌芽,值的數(shù)據(jù)類型跟值本身相關(guān)授艰,而不是與它的容器相關(guān),所以SQLite允許把各種類型的數(shù)據(jù)保存到任何類型字段中世落,開(kāi)發(fā)者可以不用關(guān)心聲明該字段說(shuō)使用的數(shù)據(jù)類型淮腾。但是有一種情況例外,定義為integer primary key的字段只能存儲(chǔ)64位整數(shù)屉佳,當(dāng)向這種字段保存除整數(shù)意外的其他類型的數(shù)據(jù)時(shí)谷朝,SQLite會(huì)產(chǎn)生錯(cuò)誤。
SQLite數(shù)據(jù)庫(kù)文件存放位置
/data/data/<package name>/databases/
SQLite數(shù)據(jù)庫(kù)支持的數(shù)據(jù)類型
SQLite內(nèi)部只支持null(空)武花、integer(整型)圆凰、real(浮點(diǎn)數(shù))、text(文本)和blob(二進(jìn)制)這五種數(shù)據(jù)類型体箕。
SQLiteOpenHelper
SQLiteOpenHelper提供了兩個(gè)構(gòu)造器专钉,用于傳遞當(dāng)前上下文對(duì)象以及SQLite數(shù)據(jù)庫(kù)版本信息挑童,在SQLiteOpenHelper的繼承類的構(gòu)造函數(shù)中會(huì)調(diào)用它,構(gòu)造器的簽名如下:
SQLiteOpenHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version)
SQLiteOpenHelper(Context context, String name,
SQLiteDatabase.CursorFactroy factory, int version,
DatabaseErrorHandler errorHandler)
上面的構(gòu)造函數(shù)中跃须,都是用于創(chuàng)建一個(gè)SQLite數(shù)據(jù)庫(kù)炮沐,context為一個(gè)當(dāng)前應(yīng)用的上下文對(duì)象;name是數(shù)據(jù)庫(kù)名稱回怜;factory是一個(gè)允許子類在查詢時(shí)使用的游標(biāo),一般不用(傳null即可)换薄;version是數(shù)據(jù)庫(kù)版本號(hào)玉雾;errorHandler是一個(gè)接口,傳遞當(dāng)數(shù)據(jù)庫(kù)錯(cuò)誤的時(shí)候轻要,執(zhí)行的補(bǔ)救方法复旬。
在SQLiteOpenHelper中,可以進(jìn)行SQLite數(shù)據(jù)庫(kù)的創(chuàng)建冲泥、維護(hù)驹碍、日志以及獲取可讀寫的數(shù)據(jù)庫(kù)對(duì)象,通過(guò)下面幾個(gè)常用方法得到支持:
1)String getDatabaseName():獲取數(shù)據(jù)庫(kù)名凡恍。
2)SQLiteDatabase getReadableDatabase():創(chuàng)建或者打開(kāi)一個(gè)可讀的數(shù)據(jù)庫(kù)對(duì)象志秃。
3)SQLiteDatabase getWritableDatabase():創(chuàng)建或者打開(kāi)一個(gè)可讀/寫的數(shù)據(jù)庫(kù)對(duì)象。
4)abstract void onCreate(SQLiteDatabase db):當(dāng)?shù)谝淮握{(diào)用SQLiteOpenHelper的時(shí)候執(zhí)行嚼酝,之后再次調(diào)用將不再執(zhí)行浮还,一般用于完成數(shù)據(jù)庫(kù)初始化的工作。
5)void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):當(dāng)數(shù)據(jù)庫(kù)版本號(hào)發(fā)生向上更新時(shí)被執(zhí)行闽巩。
6)void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion):當(dāng)數(shù)據(jù)庫(kù)版本號(hào)發(fā)生向下更新時(shí)被執(zhí)行钧舌。
SQLiteDatabase
當(dāng)使用SQLiteOpenHelper的getReadableDatabase()或者getWritableDatabase()方法獲取到SQLiteDatabase對(duì)象,就可以對(duì)這個(gè)數(shù)據(jù)庫(kù)進(jìn)行操作了涎跨。
CRUD
其中C代表添加(Create)洼冻,R代表查詢(Retrieve),U代表更新(Update)隅很,D代表刪除(Delete)撞牢。
1、使用SQL語(yǔ)句執(zhí)行CRUD操作
1)插入數(shù)據(jù)
db.execSQL("insert into book (name, author, pages, price) values(?, ?, ?, ?)",
new String[] { "The Da Vinci Code", "Dan Brown", "454", "16.96" });
2)更新數(shù)據(jù)
db.execSQL("update book set price = ? where name = ?", new String[] { "10.99", "The Da Vinci Code" });
3)刪除數(shù)據(jù)
db.execSQL("delete from book where pages > ?", new String[] { "500" });
4)查找數(shù)據(jù)
db.rawQuery("select * from book", null);
void execSQL():通過(guò)SQL語(yǔ)句執(zhí)行一條非查詢語(yǔ)句外构。
Cursor rawQuery():通過(guò)SQL語(yǔ)句執(zhí)行一條查詢語(yǔ)句普泡。
2、使用SQLiteDatabase所提供的方法實(shí)現(xiàn)CRUD操作
1)插入一條數(shù)據(jù)
long insert(String table, String nullColumnHack, ContentValues values)
table是表名审编;nullColumnHack用于在未指定添加數(shù)據(jù)的情況下給某些可為空的列自動(dòng)賦值null撼班,一般用不到這個(gè)功能,直接傳入null即可垒酬;values是一個(gè) ContentValues對(duì)象砰嘁,它提供了一系列的put()方法重載件炉,用于向ContentValues中添加數(shù)據(jù),只需要將表中的每個(gè)列名以及相應(yīng)的待添加數(shù)據(jù)傳入即可矮湘。
2)根據(jù)條件斟冕,刪除數(shù)據(jù)。
int delete(String table, String whereCaluse, String[] whereArgs)
table是表名缅阳;whereCaluse和whereArgs用于去約束刪除某一行或某幾行的數(shù)據(jù)磕蛇,不指定的話默認(rèn)就是刪除所有行∈欤
3)根據(jù)條件秀撇,更新數(shù)據(jù)。
int updata(String table,ContentValues values,String whereCaluse,String[] whereArgs)
table是表名向族;values是ContentValues對(duì)象要把更新數(shù)據(jù)在這里組裝進(jìn)去呵燕;whereCaluse和whereArgs用于去約束更新某一行或某幾行中的數(shù)據(jù),不指定的話默認(rèn)就是更新所有行件相。
4)根據(jù)條件再扭,查詢數(shù)據(jù)。
Cursor query(String table, String[] columns, String selection, String[] selectionArgs,
String groupBy, String having, String orderBy)
table是表名夜矗;columns用于指定去查詢哪幾列泛范,如果不指定則默認(rèn)查詢所有列;selection和selectionArgs用于去約束查詢某一行或某幾行的數(shù)據(jù)侯养,不指定則默認(rèn)是查詢所有行的數(shù)據(jù)敦跌;groupBy用于指定需要去group by的列,不指定則表示不對(duì)查詢結(jié)果進(jìn)行g(shù)roup by操作逛揩;having用于對(duì)group by之后的數(shù)據(jù)進(jìn)行進(jìn)一步的過(guò)濾柠傍,不指定則表示不進(jìn)行過(guò)濾;orderBy用于指定查詢結(jié)果的排序方式辩稽,不指定則表示使用默認(rèn)的排序方式惧笛。
示例演示
1)SQLiteOpenHelper幫助創(chuàng)建和更新數(shù)據(jù)庫(kù)
public class DBOpenHelper extends SQLiteOpenHelper {
private Context mContext;
private String createBook;
private String createCategory;
public DBOpenHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
/**
* 創(chuàng)建數(shù)據(jù)庫(kù)
*/
@Override
public void onCreate(SQLiteDatabase db) {
// 創(chuàng)建book表
createBook = "create table book(" +
"id integer primary key autoincrement, " +
"author text, " +
"price real, " +
"pages integer, " +
"name text, " +
"category_id integer)";
db.execSQL(createBook);
// 創(chuàng)建category表
createCategory = "create table category(" +
"id integer primary key autoincrement, " +
"category_name text, " +
"category_code integer)";
db.execSQL(createCategory);
// 提示數(shù)據(jù)庫(kù)創(chuàng)建完畢
Toast.makeText(mContext, "數(shù)據(jù)庫(kù)創(chuàng)建完畢", Toast.LENGTH_SHORT).show();
}
/**
* 更新數(shù)據(jù)庫(kù)
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {
case 1:
// 創(chuàng)建category表
db.execSQL(createCategory);
case 2:
// 向book表添加category_id列
db.execSQL("alter table book add column category_id integer");
break;
}
}
}
2)設(shè)置Activity的布局
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/add_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加數(shù)據(jù)"/>
<Button
android:id="@+id/update_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="更新數(shù)據(jù)"/>
<Button
android:id="@+id/delete_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="刪除數(shù)據(jù)"/>
<Button
android:id="@+id/query_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查詢數(shù)據(jù)"/>
</LinearLayout>
3)在Activity中進(jìn)行數(shù)據(jù)庫(kù)的CRUD操作
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private DBOpenHelper mDBOpenHelper;
private SQLiteDatabase mSqLiteDatabase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 數(shù)據(jù)庫(kù)BookStore.db,版本2逞泄。
mDBOpenHelper = new DBOpenHelper(this, "BookStore.db", null, 2);
/**
* 插入數(shù)據(jù)
*/
findViewById(R.id.add_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 以可寫入的方式獲取數(shù)據(jù)庫(kù)
mSqLiteDatabase = mDBOpenHelper.getWritableDatabase();
// 創(chuàng)建ContentValues并寫入數(shù)據(jù)
ContentValues values = new ContentValues();
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", 454);
values.put("price", 16.96);
// 插入第一條數(shù)據(jù)
mSqLiteDatabase.insert("book", null, values);
// 清空ContentValues
values.clear();
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages", 510);
values.put("price", 19.95);
// 插入第二條數(shù)據(jù)
mSqLiteDatabase.insert("book", null, values);
// 清空ContentValues
values.clear();
Toast.makeText(MainActivity.this, "已插入數(shù)據(jù)", Toast.LENGTH_SHORT).show();
}
});
/**
* 更新數(shù)據(jù)
*/
findViewById(R.id.update_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 以可寫入的方式獲取數(shù)據(jù)庫(kù)
mSqLiteDatabase = mDBOpenHelper.getWritableDatabase();
// 創(chuàng)建ContentValues并寫入數(shù)據(jù)
ContentValues values = new ContentValues();
values.put("price", 10.99);
// 更新數(shù)據(jù)
mSqLiteDatabase.update("book", values,
"name = ?", new String[]{"The Da Vinci Code"});
Toast.makeText(MainActivity.this, "已更新數(shù)據(jù)", Toast.LENGTH_SHORT).show();
}
});
/**
* 刪除數(shù)據(jù)
*/
findViewById(R.id.delete_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 以可寫入的方式獲取數(shù)據(jù)庫(kù)
mSqLiteDatabase = mDBOpenHelper.getWritableDatabase();
mSqLiteDatabase.delete("book", "pages > ?", new String[]{"500"});
Toast.makeText(MainActivity.this, "已刪除數(shù)據(jù)", Toast.LENGTH_SHORT).show();
}
});
/**
* 查詢數(shù)據(jù)
*/
findViewById(R.id.query_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 以只讀的方式獲取數(shù)據(jù)庫(kù)
mSqLiteDatabase = mDBOpenHelper.getReadableDatabase();
// 查詢book表中所有數(shù)據(jù)
Cursor cursor = mSqLiteDatabase.query("book", null, null, null, null, null, null);
// 遍歷Cursor對(duì)象患整,取出數(shù)據(jù)。
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.i(TAG, "name: " + name + ", author: " + author +
", pages: " + pages + ", price: " + price);
}
// 記得關(guān)閉資源
cursor.close();
Toast.makeText(MainActivity.this, "已查詢數(shù)據(jù)", Toast.LENGTH_SHORT).show();
}
});
}
}
使用事務(wù)
SQLiteDatabase db = dbHelper.getWritableDatabase();
// 開(kāi)啟事務(wù)
db.beginTransaction();
try {
db.delete("Book", null, null);
ContentValues values = new ContentValues();
values.put("name", "Game of Thrones");
values.put("author", "George Martin");
values.put("pages", 720);
values.put("price", 20.85);
db.insert("Book", null, values);
// 操作成功
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關(guān)閉事務(wù)
db.endTransaction();
}
參考
《第一行代碼--Android》
Android--數(shù)據(jù)持久化之SQLite