核心:SQLiteOpenHelper幫助類(是一個(gè)抽象類)
借助這個(gè)類就可以非常簡單地對(duì)數(shù)據(jù)庫進(jìn)行創(chuàng)建和升級(jí)民泵;
創(chuàng)建數(shù)據(jù)庫
SQLiteOpenHelper是抽象類,需創(chuàng)建自己的類繼承;
其中有兩個(gè)抽象方法静檬,
onCreate()
和onUpgrade()
帘营,
需重寫,實(shí)現(xiàn)創(chuàng)建
和升級(jí)
數(shù)據(jù)庫的邏輯翩活。還有兩個(gè)重要的實(shí)例方法:
getReadableDatabase()
和getWritableDatabase()
判没。
都可創(chuàng)建
或打開現(xiàn)有數(shù)據(jù)庫
(數(shù)據(jù)庫已經(jīng)存在則直接打開,沒有則創(chuàng)建)隅茎,
并返回可對(duì)數(shù)據(jù)庫進(jìn)行讀寫操作的對(duì)象澄峰。
其不同:當(dāng)數(shù)據(jù)庫不可寫入時(shí)(如磁盤空間已滿)
,
前者
返回的對(duì)象以getReadableDatabase()
打開數(shù)據(jù)庫辟犀,getWritableDatabase()
將出現(xiàn)異常
俏竞。SQLiteOpenHelper
有兩個(gè)構(gòu)造方法可供重寫,
一般使用參數(shù)少一點(diǎn)的那個(gè)構(gòu)造方法堂竟,
其接收四個(gè)參數(shù):
Context
魂毁,
數(shù)據(jù)庫名
,創(chuàng)建數(shù)據(jù)庫時(shí)使用的就是這里指定的名稱
出嘹;
允許
查詢數(shù)據(jù)時(shí)返回一個(gè)自定義的Cursor(一般傳入null)席楚,
當(dāng)前數(shù)據(jù)庫版本號(hào)
(用于升級(jí)
操作)。
構(gòu)建SQLiteOpenHelper實(shí)例
后税稼,
再調(diào)用他的getReadableDatabase()/getWritableDatabase()方法
就能創(chuàng)建數(shù)據(jù)庫
了
(數(shù)據(jù)庫文件會(huì)存放在/data/data/<package name>/databases/
目錄下)烦秩。
此時(shí)重寫的onCreate()方法
被執(zhí)行(通常處理創(chuàng)建表的邏輯
)。@善汀V混簟!H偶 E浊蕖!
示例代碼
創(chuàng)建名為BookStore.db
的數(shù)據(jù)庫曙旭,并新建一張Book
表盗舰。
新建MyDatabaseHelper
類繼承自SQLiteOpenHelper
:
public class MyDatabaseHelper extends SQLiteOpenHelper {
//將見表語句定義成字符串常量
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)" ;
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
//在數(shù)據(jù)庫創(chuàng)建完成時(shí)創(chuàng)建Book表
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
注意
autoincrement
表示id
是自增長的;
使用MyDatabaseHelper
創(chuàng)建數(shù)據(jù)庫
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbhelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//構(gòu)建SQLiteOpenHelper實(shí)例
dbhelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//調(diào)用SQLiteOpenHelper實(shí)例的getReadableDatabase()/getWritableDatabase()方法
//就能創(chuàng)建數(shù)據(jù)庫了
//此時(shí)重寫的onCreate()方法被執(zhí)行
//如以上所寫桂躏,則創(chuàng)建了Book表
dbhelper.getWritableDatabase();
}
});
}
}
升級(jí)(更新)數(shù)據(jù)庫
基于以上代碼钻趋,
再添加一張Category表用于記錄圖書分類,
在繼承自SQLiteOpenHelper
的MyDatabaseHelper
類中添加代碼:
(添加的地方以感嘆號(hào)標(biāo)記沼头,一共四處)
public class MyDatabaseHelper extends SQLiteOpenHelper {
//將見表語句定義成字符串常量
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)" ;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 1.
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text, "
+ "category_code integer)";**
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
//在數(shù)據(jù)庫創(chuàng)建完成時(shí)創(chuàng)建Book表
db.execSQL(CREATE_BOOK);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 2.
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 3.
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 4.
}
}
再次調(diào)用
getWritableDatabase();
時(shí)爷绘,
onCreate()
不會(huì)再執(zhí)行了书劝,
因?yàn)閿?shù)據(jù)庫只能創(chuàng)建一次,剛剛已經(jīng)創(chuàng)建過了土至;
所以這里只能在onUpgrade()
中购对,
執(zhí)行Drop
將原來的表刪掉,
再重新調(diào)用onCreate()
方法陶因,
這樣一開始的表
和新加的表
都會(huì)被創(chuàng)建骡苞;
調(diào)用onUpgrade()
:
構(gòu)造SQLiteOpenHelper
實(shí)例的時(shí)候,
給第四個(gè)參數(shù)(version)
傳入大于舊版本的數(shù)字
楷扬,
即可讓onUpgrade()
執(zhí)行解幽,進(jìn)而更新數(shù)據(jù)庫:
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbhelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
dbhelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbhelper.getWritableDatabase();
}
});
}
}
CRUD核心:
getReadableDatabase()
和getWritableDatabase()
返回的SQLiteDatabase
對(duì)象;
在Android中即使不去編寫SQL語句烘苹,
提供了一系列輔助性方法躲株,
也能輕松完成所有CRUD操作。
SQLiteOpenHelper的兩個(gè)實(shí)例方法getReadableDatabase()/getWritableDatabase()
會(huì)返回SQLiteDatabase對(duì)象镣衡,
借助這個(gè)對(duì)象就可對(duì)數(shù)據(jù)進(jìn)行CRUD操作霜定。
添加數(shù)據(jù)
首先調(diào)用
ContentValues
實(shí)例的各種重載的put(表的某個(gè)屬性,值)
方法廊鸥,
向ContentValues
實(shí)例自身中添加數(shù)據(jù)望浩;
接著調(diào)用insert()
,即可將數(shù)據(jù)加到對(duì)應(yīng)的表中惰说;
它接收三個(gè)參數(shù):
- 表名磨德,指定向哪張表添加數(shù)據(jù);
- 用于在未指定添加數(shù)據(jù)的情況下吆视,
給某些可為空的列自動(dòng)復(fù)賦值NULL典挑,
一般用不到這個(gè)功能,
直接傳入NULL即可揩环;ContentValues
實(shí)例搔弄;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbhelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbhelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = ...
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbhelper.getWritableDatabase();
ContentValues values = new ContentValues();
//開始組裝第一條數(shù)據(jù)
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages",454);
values.put("price", 16.96);
db.insert("Book",null,values);//插入第一條數(shù)據(jù)
values.clear();//!7峄!5光帧褒墨!
//開始組裝第二條數(shù)據(jù)
values.put("name", "The Lost Symbol");
values.put("author", "Dan Brown");
values.put("pages",510);
values.put("price", 19.95);
db.insert("Book",null,values);//插入第二條數(shù)據(jù)
}
});
...
更新數(shù)據(jù)
- 首先調(diào)用
ContentValues
實(shí)例的各種重載的put(表的某個(gè)屬性,值)
方法擎宝,- 接著調(diào)用
update()
實(shí)現(xiàn)更新——
第三郁妈、四個(gè)參數(shù)用于約束更新
某一行或某幾行數(shù)據(jù),
默認(rèn)更新所有行绍申;
第三個(gè)參數(shù)對(duì)應(yīng)SQL的where語句噩咪,顾彰?
為占位符
,
通過第四個(gè)參數(shù)提供的字符串?dāng)?shù)組
指定相應(yīng)內(nèi)容
胃碾;
第一參數(shù)表名涨享,第二參數(shù)ContentValues
實(shí)例;
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbhelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price", 10.99);
db.update("Book",values, "name = ?", new String[]{"The Da Vinci Code"});
}
});
上述代碼表達(dá)的意圖將name為The Da Vinci Code的這本書的價(jià)格改成10.99仆百;
刪除數(shù)據(jù)
- 直接用
SQLiteDatabase實(shí)例
調(diào)用delete()
厕隧;
其第一參,表明俄周;
二三參吁讨,同update()
的三四參;
Button button = (Button) findViewById(R.id.delete_data);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbhelper.getWritableDatabase();
db.delete("Book", "pages > ?", new String[]{"500"});
}
});
查詢數(shù)據(jù)
- 通過
query()
進(jìn)行查詢峦朗;
其重載方法多建丧,參數(shù)復(fù)雜,
我們看參數(shù)最少(7個(gè)參數(shù))的一個(gè)波势;
參數(shù)對(duì)應(yīng)內(nèi)容可參考下表:
(其三四參茶鹃,同update()
的三四參;)
query()
參數(shù)多艰亮,
但是多數(shù)情況不必要全部參數(shù)都用闭翩,
指定少數(shù)幾個(gè)參數(shù)即可完成查詢
(如只傳入第一個(gè)參數(shù)表名,
后面全為null迄埃,則查詢表中的所有數(shù)據(jù))疗韵;
調(diào)用query()
后會(huì)返回一個(gè)Cursor(n.光標(biāo))對(duì)象
,
查詢到的所有數(shù)據(jù)
都將從這個(gè)對(duì)象中取出
侄非;
示例代碼:
Button queryButton = (Button) findViewById(R.id.query_data);
queryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SQLiteDatabase db = dbhelper.getWritableDatabase();
//查詢Book表中所有數(shù)據(jù)
Cursor cursor = db.query("Book", null,null,null,null,null,null);
if (cursor.moveToFirst()){
do {
//遍歷Cursor對(duì)象蕉汪,取出數(shù)據(jù)并打印
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.d("MainActivity", "book name is " + name);
Log.d("MainActivity", "book author is " + author);
Log.d("MainActivity", "book pages is " + pages);
Log.d("MainActivity", "book price is " + price);
}while (cursor.moveToNext());
}
cursor.close();
}
});
Cursor實(shí)例每次指向返回?cái)?shù)據(jù)表的一行,
通過moveToFirst()
和moveToNext()
等方法來調(diào)節(jié)其指向的位置逞怨;
令其指向某一行者疤,或者一行一行遍歷返回的數(shù)據(jù)表,
對(duì)返回的數(shù)據(jù)進(jìn)行處理即可叠赦。