應用場景:
在前面幾講我們講了Android的數據存儲使用文件或SharedPreferences存儲數據,除此之外呢,有時候我們需要用到一個小型的數據庫用於來保存我們的一些持久型的數據。所以在在Android平臺上,集成了一個嵌入式關係型數據庫—SQLite,SQLite3。因此中我們可以選擇使用SQLite數據庫存儲數據。
SQLite概述:
SQLite,是一款輕型的數據庫,是遵守ACID的關聯式數據庫管理系統,它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它佔用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源世界著名的數據庫管理系統來講,它的處理速度比他們都快。SQLite第一個Alpha版本誕生於2000年5月. 至今已經有10個年頭,SQLite也迎來了一個版本 SQLite 3已經發布。
SQLite所支持的數據類型:
SQLite,SQLite3支持 NULL、INTEGER、REAL(浮點數字)、TEXT(字符串文本)和BLOB(二進制對象)數據類型,雖然它支持的類型只有五種,但實際上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等數據類型,只不過在運算或保存時會轉成對應的五種數據類型。
SQLite最大的特點是你可以把各種類型的數據保存到任何字段中,而不用關心字段聲明的數據類型是什麼。例如:可以在Integer類型的字段中存放字符串,或者在布爾型字段中存放浮點數,或者在字符型字段中存放日期型值。 但有一種情況例外:定義爲INTEGER PRIMARY KEY的字段只能存儲64位整數, 當向這種字段保存除整數以外的數據時,將會產生錯誤。 另外, SQLite 在解析CREATE TABLE 語句時,會忽略 CREATE TABLE 語句中跟在字段名後面的數據類型信息,如下面語句會忽略 name字段的類型信息:
CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))
SQLite語句示範:
查詢語句:select * from 表名 where 條件子句 group by 分組字句 having ... order by 排序子句
如:select * from person
select * from person order by id desc
select name from person group by name having count(*)>1
分頁SQL與mysql類似,下面SQL語句獲取5條記錄,跳過前面3條記錄
select * from Account limit 5 offset 3 或者 select * from Account limit 3,5
插入語句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘張三’,3)
更新語句:update 表名 set 字段名=值 where 條件子句。如:update person set name=‘張三‘ where id=10
刪除語句:delete from 表名 where 條件子句。如:delete from person where id=10
使用SQLiteOpenHelper對數據庫進行版本管理
SQLiteOpenHelper
它是一個抽象類,用於對數據庫版本進行控制。爲了達到對數據庫的一種管理我們必須繼承自SQLiteOpenHelper這個抽象類。它是通過對數據庫版本進行管理來實現一些需求。 爲了實現對數據庫版本進行管理,SQLiteOpenHelper類提供了兩個重要的方法,分別是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),
下面將列出一些SQLiteOpenHelper類的一些常見方法:
兩個構造方法:
方法名稱 |
描述 |
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version) |
|
public SQLiteOpenHelper (Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) |
|
方法名稱 |
描述 |
public void onOpen (SQLiteDatabase db) |
打開數據庫 |
public abstract void onCreate (SQLiteDatabase db) |
初次使用軟件時生成數據庫表。在這個方法裏面可以生成數據庫表結構及添加一些應用使用到的初始化數據 |
public abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) |
用於升級軟件時更新數據庫表結構。在數據庫的版本發生變化時會被調用,一般在軟件升級時才需改變版本號
|
public synchronized SQLiteDatabase getWritableDatabase () |
得到一個可寫的SQLiteDatabase實例 |
public synchronized SQLiteDatabase getReadableDatabase () |
得到一個可讀的SQLiteDatabase實例 |
getWritableDatabase()和getReadableDatabase()的區別:
getWritableDatabase()和getReadableDatabase()方法都可以獲取一個用於操作數據庫的SQLiteDatabase實例。但getWritableDatabase() 方法以讀寫方式打開數據庫,一旦數據庫的磁盤空間滿了,數據庫就只能讀而不能寫,倘若使用getWritableDatabase()打開數據庫就會出錯。getReadableDatabase()方法先以讀寫方式打開數據庫,如果數據庫的磁盤空間滿了,就會打開失敗,當打開失敗後會繼續嘗試以只讀方式打開數據庫。
SQLiteDatabase
SQLiteDatabase代表的是一個數據庫(底層就是一個數據庫文件),一量應用程序獲得了代表指定的數據庫的SQLiteDatabase對象,接下來我們就可以用它來完成管理、操作數據庫了。
幾個靜態方法獲得SQLiteDatabase對象
方法名稱 |
描述 |
public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler) |
打開path下的所代表的SQLite數據庫 |
public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags) |
打開path下的所代表的SQLite數據庫 |
public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) |
打開path下的所代表的SQLite數據庫 |
public static SQLiteDatabase openOrCreateDatabase (String path, SQLiteDatabase.CursorFactory factory) |
打開或者創建path下的所代表的SQLite數據庫 |
public static SQLiteDatabase openOrCreateDatabase (File file, SQLiteDatabase.CursorFactory factory) |
打開或者創建file下的所代表的SQLite數據庫 |
常用方法
方法名稱 |
描述 |
public void execSQL (String sql) |
執行SQL語句 |
public void execSQL (String sql, Object[] bindArgs) |
執行帶佔位符的SQL語句 |
public long insert (String table, String nullColumnHack, ContentValues values) |
向table表中插入數據 |
public int update (String table, ContentValues values, String whereClause, String[] whereArgs) |
更新指定表table中的特定數據 |
public int delete (String table, String whereClause, String[] whereArgs) |
刪除指定表(table)中的特定數據 |
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) |
對執行數據表進行查詢 |
public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) |
對執行數據表進行查詢。參數說明: table: columns: selection: selectionArgs: groupBy: having: orderBy: |
public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) |
對執行數據表進行查詢 |
public Cursor rawQuery (String sql, String[] selectionArgs) |
執行帶佔位符的SQL查詢。參數說明: sql: selectionArgs: |
public void beginTransaction () |
開始事務 |
public void endTransaction () |
結束事務 |
Cursor類
它是一個接口。Cursor的中文意思可以理解爲一個遊標,也類似於結果集,比如我們在JDBC中的ResultSet。它有以下的常用方法
方法名稱 |
描述 |
public abstract void move(int offset) |
將記錄指針向上或向下移動指定的行數。Offset爲正向下移動,爲負身上移動 |
public abstract boolean moveToFirst() |
將記錄指定移動到第一行,如果移動成功返回true |
public abstract boolean moveToLast() |
將記錄指針移動到最後一行。如果成功返回true |
public abstract boolean moveToNext() |
將記錄指定移動到下一行,如果成功返回true |
public abstract boolean moveToPosition(int position) |
將記錄指定移動到指定的行,如果移動成功則返回true |
public abstract boolean moveToPrevious(0 |
將記錄指針將到上一行,如果移動成功則返回true |
熟悉完上面的所有API那麼我們就來看如何使用這個輕型的SQLite來完成我們的數據持久化。
實例:
實現效果:
Activity主要代碼:
- package com.jiahui.sqlite;
- import java.util.ArrayList;
- import java.util.Currency;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.zip.Inflater;
- import com.jiahui.model.Person;
- import android.app.Activity;
- import android.content.ContentValues;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ListView;
- import android.widget.SimpleAdapter;
- import android.widget.TextView;
- import android.widget.Toast;
- public class SQLiteDemoActivity extends Activity {
- private Button btnAdd;
- private Button btnQueryAll;
- private ListView lvpersons;
- private EditText edtname;
- private EditText edtage;
- private List<Person> persons;
- private Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- //接到子線程發回來的數據,完成列表的顯示
- List<Map<String, Object>> data = (List<Map<String, Object>>) msg.obj;
- SimpleAdapter simpleAdapter = new SimpleAdapter(
- SQLiteDemoActivity.this, data, R.layout.list_item,
- new String[] { "id", "name", "age" }, new int[] {
- R.id.tvid, R.id.tvname, R.id.tvage });
- lvpersons.setAdapter(simpleAdapter);
- }
- };
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnAdd = (Button) this.findViewById(R.id.btnAdd);
- btnQueryAll = (Button) this.findViewById(R.id.btnQueryAll);
- edtname = (EditText) this.findViewById(R.id.edtname);
- edtage = (EditText) this.findViewById(R.id.edtage);
- lvpersons = (ListView) this.findViewById(R.id.lvpersons);
- persons = new ArrayList<Person>();
- DBHelper dbHelper = new DBHelper(this);
- final SQLiteDatabase database = dbHelper.getWritableDatabase();
- btnAdd.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- ContentValues values = new ContentValues();
- values.put("name", edtname.getText().toString());
- values.put("age", edtage.getText().toString());
- long result = database.insert("person", null, values);
- if (result != -1) {
- Toast.makeText(SQLiteDemoActivity.this, "增加數據成功",
- Toast.LENGTH_LONG).show();
- }
- }
- });
- btnQueryAll.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //查詢數據可能花費太多時間交給子線程去做,在Handler完成數據的顯示
- myThread thread = new myThread(database);
- thread.start();
- }
- });
- }
- class myThread extends Thread {
- private SQLiteDatabase database;
- public myThread(SQLiteDatabase database) {
- this.database = database;
- }
- public void run() {
- System.out.println("----------");
- Cursor cursor = database.query("person", new String[] { "_id",
- "name", "age" }, null, null, null, null, null);
- while (cursor.moveToNext()) {
- Person person = new Person();
- person.setId(cursor.getInt(cursor.getColumnIndex("_id")));
- person.setName(cursor.getString(cursor.getColumnIndex("name")));
- person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
- persons.add(person);
- }
- List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
- for (int i = 0; i < persons.size(); i++) {
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("id", persons.get(i).getId());
- map.put("name", persons.get(i).getName());
- map.put("age", persons.get(i).getAge());
- data.add(map);
- System.out.println(persons.get(i));
- }
- Message msg = handler.obtainMessage();
- msg.obj = data;
- handler.sendMessage(msg);
- }
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- }
- }