帶你走進游戲開發(fā)的世界之?dāng)?shù)據(jù)庫SQLite 詳細介紹
數(shù)據(jù)庫SQLite介紹
數(shù)據(jù)庫最經(jīng)典的四個操作 添加、刪除、修改、查找,在處理大量數(shù)據(jù)的時候使用數(shù)據(jù)庫可以幫我們迅速定位當(dāng)前須要處理的數(shù)據(jù),舉個例子 好比現(xiàn)在要實現(xiàn)一個搜索功能 用數(shù)據(jù)庫的話只須要其中一個搜索條件 一個數(shù)據(jù)庫語句就可以迅速的在N條數(shù)據(jù)中找到我們需要的數(shù)據(jù),如果不使用數(shù)據(jù)庫那么查找起來會非常麻煩,效率大打折扣,所以在處理大量數(shù)據(jù)的時候使用數(shù)據(jù)庫是明確的選擇,在Android的開發(fā)中使用的數(shù)據(jù)庫是SQLite ,它是一個輕量級的數(shù)據(jù)庫 、非常小 、 移植性好、效率高、可靠 ,嵌入式設(shè)備因為受到硬件條件的限制所以非常適合使用 SQLite 數(shù)據(jù)庫。
創(chuàng)建與刪除數(shù)據(jù)庫
封裝一個類去繼承SQLiteOpenHelper 在構(gòu)造函數(shù)中傳入數(shù)據(jù)庫名稱與數(shù)據(jù)庫版本號,數(shù)據(jù)庫被創(chuàng)建的時候會調(diào)用onCreate(SQLiteDatabase db) 方法,數(shù)據(jù)庫版本號發(fā)生改變的時候會調(diào)用onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)方法,可以方便的對軟件游戲升級后做出相應(yīng)處理避免覆蓋安裝數(shù)據(jù)庫發(fā)生改變產(chǎn)生的錯誤。調(diào)用SQLiteOpenHelper 的getReadableDatabase()方法去創(chuàng)建數(shù)據(jù)庫,如果數(shù)據(jù)庫不存在則創(chuàng)建 并且返回SQLiteDatabase對象,如果數(shù)據(jù)庫存在則不創(chuàng)建只返回SQLiteDatabase對象。調(diào)用deleteDatabase(DATABASE_NAME)方法 傳入數(shù)據(jù)庫名稱則可刪除數(shù)據(jù)庫。
封裝了一個DatabaseHelper類繼承SQLiteOpenHelper 我使用了設(shè)計模式中的單例模式來處理這個類,這里說一下單例模式 單例模式是常見的代碼設(shè)計模式之一 它的好處是在于避免在內(nèi)存中頻繁的實例化所以將它的對象寫成static 靜態(tài) 這樣它的對象就只有一份存在靜態(tài)內(nèi)存區(qū)使用的時候只須要通過getInstance()就可以直接拿到這個靜態(tài)對象。 - public class DatabaseHelper extends SQLiteOpenHelper {
private static DatabaseHelper mInstance = null;
/** 數(shù)據(jù)庫名稱 **/
public static final String DATABASE_NAME = "xys.db";
/** 數(shù)據(jù)庫版本號 **/
private static final int DATABASE_VERSION = 1;
/**數(shù)據(jù)庫SQL語句 添加一個表**/
private static final String NAME_TABLE_CREATE = "create table test("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+"hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**單例模式**/
static synchronized DatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseHelper(context);
}
return mInstance;
}
@Override
public void onCreate(SQLiteDatabase db) {
/**向數(shù)據(jù)中添加表**/
db.execSQL(NAME_TABLE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
/**可以拿到當(dāng)前數(shù)據(jù)庫的版本信息 與之前數(shù)據(jù)庫的版本信息 用來更新數(shù)據(jù)庫**/
}
/**
* 刪除數(shù)據(jù)庫
* @param context
* @return
*/
public boolean deleteDatabase(Context context) {
return context.deleteDatabase(DATABASE_NAME);
}
}
復(fù)制代碼 在這個類中使用DatabaseHelper對象 實現(xiàn)創(chuàng)建與刪除數(shù)據(jù)庫、 - public class NewSQLite extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_sql);
mContext = this;
//創(chuàng)建DatabaseHelper對象
mDbHelper = DatabaseHelper.getInstance(mContext);
//調(diào)用getReadableDatabase方法如果數(shù)據(jù)庫不存在 則創(chuàng)建 如果存在則打開
mDb= mDbHelper.getReadableDatabase();
Button button0 = (Button)findViewById(R.id.createDateBase);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Toast.makeText(NewSQLite.this, "成功創(chuàng)建數(shù)據(jù)庫", Toast.LENGTH_LONG).show();
}
});
Button button1 = (Button)findViewById(R.id.deleteDateBase);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
mDbHelper = DatabaseHelper.getInstance(mContext);
// 調(diào)用getReadableDatabase方法如果數(shù)據(jù)庫不存在 則創(chuàng)建 如果存在則打開
mDb = mDbHelper.getReadableDatabase();
// 關(guān)閉數(shù)據(jù)庫
mDbHelper.close();
// 刪除數(shù)據(jù)庫
mDbHelper.deleteDatabase(mContext);
Toast.makeText(NewSQLite.this, "成功刪除數(shù)據(jù)庫", Toast.LENGTH_LONG).show();
}
});
super.onCreate(savedInstanceState);
}
}
復(fù)制代碼 創(chuàng)建的數(shù)據(jù)庫會被保存在當(dāng)前項目中 databases 路徑下 具體如圖所示
添加與刪除數(shù)據(jù)庫中的表
數(shù)據(jù)庫是可以由多張數(shù)據(jù)表組成的 如果添加一張數(shù)據(jù)庫的表的話 可以使用 數(shù)據(jù)庫語句 create table 名稱(內(nèi)容) 來進行添加 。這里給出一條創(chuàng)建數(shù)據(jù)庫的語句 。 意思是創(chuàng)建一張表 名稱為gameInfo 表中包含的字段 為 _id 為INTEGER 類型 并且遞增 name 為Text類型 hp mp 為INTEGER 默認數(shù)值為100 number 為INTEGER 類型。 - /**創(chuàng)建一張表的SQL語句**/
private static final String NAME_TABLE_CREATE = "create table gameInfo("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+ "hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
復(fù)制代碼 數(shù)據(jù)庫中刪除一張表 直接使用DROP TABLE 表名稱 就可以刪除 - /**刪除一張表的SQL語句**/
private static final String NAME_TABLE_DELETE = "DROP TABLE gameInfo";
復(fù)制代碼 在代碼中去執(zhí)行一條SQL語句 使用SQLiteDatabase對象去調(diào)用execSQL() 傳入SQL語句就OK了。 - mDb.execSQL(NAME_TABLE_CREATE);
復(fù)制代碼
以創(chuàng)建一張名稱為gameInfo的表為例 給出代碼實現(xiàn) - public class NewTable extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
/**創(chuàng)建一張表的SQL語句**/
private static final String NAME_TABLE_CREATE = "create table gameInfo("
+ "_id INTEGER PRIMARY KEY AUTOINCREMENT," + "name TEXT,"+ "hp INTEGER DEFAULT 100,"+ "mp INTEGER DEFAULT 100,"
+ "number INTEGER);";
/**刪除一張表的SQL語句**/
private static final String NAME_TABLE_DELETE = "DROP TABLE gameInfo";
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_table);
mContext = this;
mDbHelper = DatabaseHelper.getInstance(mContext);
mDb= mDbHelper.getReadableDatabase();
Button button0 = (Button)findViewById(R.id.createTable);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
mDb.execSQL(NAME_TABLE_CREATE);
Toast.makeText(NewTable.this, "成功添加數(shù)據(jù)表", Toast.LENGTH_LONG).show();
}catch(SQLiteException e) {
Toast.makeText(NewTable.this, "數(shù)據(jù)庫中已存此表", Toast.LENGTH_LONG).show();
}
}
});
Button button1 = (Button)findViewById(R.id.deleteTable);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
try {
mDb.execSQL(NAME_TABLE_DELETE);
Toast.makeText(NewTable.this, "成功刪除數(shù)據(jù)表", Toast.LENGTH_LONG).show();
}catch(SQLiteException e) {
Toast.makeText(NewTable.this, "數(shù)據(jù)庫中已無此表", Toast.LENGTH_LONG).show();
}
}
});
super.onCreate(savedInstanceState);
}
}
復(fù)制代碼 增加 刪除 修改 查詢 數(shù)據(jù)庫中的數(shù)據(jù)
使用SQLiteDatabase對象調(diào)用 insert()方法 傳入標(biāo)的名稱與ContentValues 添加的內(nèi)容 則可以向數(shù)據(jù)庫表中寫入一條數(shù)據(jù) delete ()為刪除一條數(shù)據(jù) update()為更新一條數(shù)據(jù)。
我詳細說一下查找一條數(shù)據(jù)使用的方法 query 中 跟了8個參數(shù)
public Cursor query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit);
參數(shù)說明:
table:數(shù)據(jù)庫表的名稱
columns:數(shù)據(jù)庫列名稱數(shù)組 寫入后最后返回的Cursor中只能查到這里的列的內(nèi)容
selection:查詢條件
selectionArgs:查詢結(jié)果
groupBy:分組列
having:分組條件
orderBy:排序列
limit:分頁查詢限制
Cursor:返回值,將查詢到的結(jié)果都存在Cursor
Cursor是一個游標(biāo)接口,每次查詢的結(jié)果都會保存在Cursor中 可以通過遍歷Cursor的方法拿到當(dāng)前查詢到的所有信息。
Cursor的方法
moveToFirst() //將Curor的游標(biāo)移動到第一條
moveToLast()///將Curor的游標(biāo)移動到最后一條
move(int offset)//將Curor的游標(biāo)移動到指定ID
moveToNext()//將Curor的游標(biāo)移動到下一條
moveToPrevious()//將Curor的游標(biāo)移動到上一條
getCount() //得到Cursor 總記錄條數(shù)
isFirst() //判斷當(dāng)前游標(biāo)是否為第一條記錄
isLast()//判斷當(dāng)前游標(biāo)是否為最后一條數(shù)據(jù)
getInt(int columnIndex) //根據(jù)列名稱獲得列索引ID
getString(int columnIndex)//根據(jù)索引ID 拿到表中存的字段
這里給出一個例子遍歷Cursor的例子 - private void query(SQLiteDatabase db) {
// 把整張表的所有數(shù)據(jù)query到cursor中
Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
//判斷cursor不為空 這個很重要
if (cursor != null) {
// 循環(huán)遍歷cursor
while (cursor.moveToNext()) {
// 拿到每一行name 與hp的數(shù)值
String name = cursor.getString(cursor.getColumnIndex("name"));
String hp = cursor.getString(cursor.getColumnIndex("hp"));
Log.v("info", "姓名是 " + name + "hp為 " + hp);
}
// 關(guān)閉
cursor.close();
}
}
復(fù)制代碼 向大家推薦一個查看數(shù)據(jù)庫的軟件非常好用, 名稱是SQLiteSpy.exe 如圖所示 打開xys.db 文件 可以清晰的看見數(shù)據(jù)庫表中儲存的內(nèi)容并且該軟件支持執(zhí)行SQL語句 可以直接在軟件中操作,我給出這款軟件的下載地址。
下載地址: - public class Newdate extends Activity {
DatabaseHelper mDbHelper = null;
SQLiteDatabase mDb = null;
Context mContext = null;
/** 數(shù)據(jù)庫字段 **/
public final static String TABLE_NAME = "test";
public final static String ID = "_id";
public final static String NAME = "name";
public final static String HP = "hp";
public final static String MP = "mp";
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.create_date);
mContext = this;
// 創(chuàng)建DatabaseHelper對象
mDbHelper = DatabaseHelper.getInstance(mContext);
// 調(diào)用getReadableDatabase方法如果數(shù)據(jù)庫不存在 則創(chuàng)建 如果存在則打開
mDb = mDbHelper.getReadableDatabase();
// 初始化 給數(shù)據(jù)庫表寫入一些信息
for (int i = 0; i < 10; i++) {
insert(NAME, "雨松MOMO" + i);
}
// 增加
Button button0 = (Button) findViewById(R.id.add);
button0.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
insert(NAME, "新添加小可愛");
Toast.makeText(Newdate.this, "添加一條數(shù)據(jù)名稱為小可愛", Toast.LENGTH_LONG)
.show();
}
});
// 刪除
Button button1 = (Button) findViewById(R.id.delete);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
delete(ID, "1");
Toast.makeText(Newdate.this, "刪除一條_id=1的數(shù)據(jù)", Toast.LENGTH_LONG)
.show();
}
});
// 修改
Button button2 = (Button) findViewById(R.id.modify);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
update(NAME, "雨松MOMO3", "小可愛3");
Toast.makeText(Newdate.this, "更新名稱雨松MOMO3 為小可愛3",
Toast.LENGTH_LONG).show();
}
});
// 查找
Button button3 = (Button) findViewById(R.id.find);
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Cursor cursor = find(ID, "5");
String name = cursor.getString(cursor.getColumnIndex(NAME));
Toast.makeText(Newdate.this, "查找ID為5數(shù)據(jù)的名稱是 " + name,
Toast.LENGTH_LONG).show();
}
});
super.onCreate(savedInstanceState);
}
/**
* 插入一條數(shù)據(jù)
*
* @param key
* @param date
*/
public void insert(String key, String date) {
ContentValues values = new ContentValues();
values.put(key, date);
mDb.insert(TABLE_NAME, null, values);
}
/**
* 刪除一掉數(shù)據(jù)
*
* @param key
* @param date
*/
public void delete(String key, String date) {
mDb.delete(TABLE_NAME, key + "=?", new String[] { date });
}
/**
* 更新一條數(shù)據(jù)
*
* @param key
* @param oldDate
* @param newDate
*/
public void update(String key, String oldDate, String newDate) {
ContentValues values = new ContentValues();
values.put(key, newDate);
mDb.update(TABLE_NAME, values, key + "=?", new String[] { oldDate });
}
/**
* 查找一條數(shù)據(jù)
*
* @param key
* @param date
* @return
*/
public Cursor find(String key, String date) {
Cursor cursor = mDb.query(TABLE_NAME, null, key + "=?",
new String[] { date }, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
}
復(fù)制代碼 這里我在強調(diào)一下query中的第二個參數(shù)String [] columns , 舉個例子 當(dāng)前在數(shù)據(jù)中query 數(shù)值 如果我只想要數(shù)據(jù)中符合條件數(shù)據(jù)每一行的name字段和hp 字段 那么第二個參數(shù)就不要寫成null了。
第二個參數(shù)我寫成了new String[] {"name","hp"} 這樣的話得到的Cursor 中的數(shù)據(jù)只會存有 數(shù)據(jù)庫表中"name " 與 "hp"兩個字段 因為其它字段我們根本不需要所以著么寫可以大大提高代碼的效率。如果寫成null的話 Cursor 中的數(shù)據(jù)就會把數(shù)據(jù)庫表中所以的字段都保存進去這樣在計算Cursor 的時候代碼就會消耗更多沒用的時間。
cursor.getString(0); 的意思就是拿到對應(yīng)new String[] {"name","hp"} 數(shù)組中的一個字段的內(nèi)容 意思就是拿到 數(shù)據(jù)庫字段"name"的值, cursor.getString(1);的意思就是拿到數(shù)據(jù)庫字段"hp"的值 。cursor.getString()中的ID 是完全對應(yīng)第二個參數(shù)String [] columns數(shù)組角標(biāo)。 - public void find() {
Cursor cursor = mDb.query(TABLE_NAME, new String[] {"name","hp"}, null,
null, null, null, null);
while(cursor.moveToNext()) {
String name = cursor.getString(0);
String hp = cursor.getString(1);
Log.v("info", "name is "+name);
Log.v("info", "hp is "+hp);
}
}
復(fù)制代碼 最后如果你還是覺得我寫的不夠詳細 看的不夠爽 不要緊我把源代碼的下載地址貼出來 歡迎大家一起討論學(xué)習(xí)
第八講android數(shù)據(jù)庫SQLite.rar(407.37 KB, 下載次數(shù): 958)[/I]2011-9-3 00:16 上傳點擊文件名 下載積分: 下載豆 -2 |