Android筆記之存儲(SQLite數據庫)

SQLite數據庫存儲:
需要存儲大量複雜的關係型數據的時候,使用此方法存儲。

創建數據庫:
藉助SQLiteOpenHelper類對數據庫進行創建和升級。
SQLiteOpenHelper是抽象類,意味着要使用它必須創建一個子類去繼承它,而且要在子類中重寫SQLiteOpenHelper類的兩個抽象方法,分別是onCreate()和onUpgrade()。然後分別在這兩個方法中實現創建,升級數據庫的邏輯。

SQLiteOpenHelper類中還有兩個非常重要的實例方法,getReadableDatabase()和getWritableDatabase()。這兩個方法都可以創建或打開一個現有的數據庫(如果數據庫已存在則直接打開,否則創建一個新的數據庫)。並返回一個可對數據庫進行讀寫操作的對象。不同的是,當數據庫不可寫入時(如磁盤控件已滿)getReadableDatabase()方法返回的對象將以只讀的方式打開數據庫,而getWritableDatabase()方法則出現異常。

SQLiteOpenHelper中有兩個構造方法可供重寫,一般使用參數少一點的構造方法即可。該構造方法中接收四個參數,第一個是Context,第二個是數據庫名,第三個參數允許在查詢數據的時候返回一個自定義的Cursor,一般都是傳入null。第四個參數表示當前數據庫的版本號,可用於對數據庫進行升級操作。

構建出SQLiteOpenHelper實例後,再調用它的getReadableDatabase()或getWritableDatabase()方法就能創建數據庫。此時,重寫的onCreate()方法會得到執行,所以通常會在這裏去處理一些創建表的邏輯。

假設我們需要創建一個名爲BookStore.db的數據庫。然後在這個數據庫中新建一張Book表,表中有id(主鍵),作者,價格,頁數和書名等列。

創建數據庫表還是需要用建表語句,SQLite中的建表語句如下:

create table Book(
	id integer primary Key autoincrement,
	author text,
	price real,
	pages integer,
	name text)
以上,integer表示整形,real表示浮點型,text表示文本類型,blob表示二進制類型(上面沒有)。同時,還使用了primary Key將id列設爲主鍵,並用autoincrement關鍵字,表示id列是自增長的。

然後需要在代碼中去執行這條SQL語句,才能完成創建表的操作。新建一個子類繼承自SQLiteOpenHelper,示例代碼如下:
//繼承自SQLiteOpenHelper。
public class MyDatabaseHelper extends SQLiteOpenHelper {

    //將建表語句定義成字符串常量,此時CREATE_BOOK就代表建表語句。注意建表語句在android代碼中的格式。
    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;
    //子類構造函數,接收的四個對象就是上面講過的context對象,數據庫名,自定義cursor,版本號。
    public MyDatabaseHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version){
	//重寫父類構造函數。
        super(context,name,factory,version);
	//將接收的context對象的值賦給mContext對象。
        mContext=context;
    }
    //重寫onCreate方法。
    @Override
    public void onCreate(SQLiteDatabase db){
	//調用SQLiteDatabase對象的execSQL方法執行建表語句。這樣就能保證數據庫創建完成的同時創建BOOK表。
        db.execSQL(CREATE_BOOK);
	Toast.makeText(mContext,"創建成功",Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
       
    }
}
然後在佈局文件中創建一個按鈕。
MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
	
	//創建數據庫類對象。接收的第一個對象當然就是當前對象,數據庫名爲BookStore.db。自定義curso爲空,版本號爲1。
        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//監聽器中的邏輯就是調用數據庫對象的getEritableDatabase()方法創建數據庫。調用此方法後,對象中的onCreate()方法才執行。當數據庫已存在時,再次點擊,則不會執行onCrete()方法。
                databaseHelper.getWritableDatabase();
            }
        });
	}
getReadableDatabase()和getWritableDatabase()方法不僅用於創建升級數據庫,同時,他們還會返回一個SQLiteDatabase對象。也就是onCreate()方法接收的那個對象。

以上就是創建數據庫的方法,在重寫的兩個方法中,目前還有一個onUpgrade()方法是沒有寫入邏輯的。onUpgrade()方法是用於對數據庫進行升級。

假設我們需要在數據庫中再添加一張Category表用於記錄書籍的分類,這就用到了Upgrade()方法。
Category表中有id,分類名和分類代碼這幾個列,那麼建表語句就可以寫成:

create table Category(
	id integer primary Key autoincrement,
	category_name text,
	category_code integer)
將這條建表語句寫入android代碼中,也就是本次示例的MyDatabaseHelper中。

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)";
    //同樣將建Category表的建表語句定義成字符常量:CREATE_CATEGORY。
    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){
        db.execSQL(CREATE_BOOK);
	//在這裏增加了一句創建Category表,但如果僅僅只是這樣的話,是沒用的,因爲有了BOOK表,我們再點擊按鈕都是不會執行onCreate方法的。
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext,"創建成功",Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
	//execSQL()方法中執行的是兩條DROP語句,意思是如果存在BOOK和Category表就將其刪除。
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
	//刪除以後再調用onCreate()方法重新創建這兩個表。
        onCreate(db);
    }
}
以上已經將Upgrade()方法中的邏輯寫好了,接下來要做的就是執行此方法。
當初我們在SQLiteOpenHelper的構造函數中接收的第四個參數,也就是版本號裏我們填入的是1,現在只要將其傳入一個比1大的數就可以執行Upgrade()方法了。

MainActivity中的代碼:
public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

	//這次只改動了版本號,表示我們對數據庫進行升級。重新運行程序,重新點擊此按鈕,Upgarde()方法就會得到執行。
        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                databaseHelper.getWritableDatabase();
            }
        });
}
以上都只是創建和升級數據庫的操作代碼。

向數據庫的表中添加數據:
SQLiteDatabase中提供了一個insert()方法,這個方法專門用於添加數據。它接收三個參數,第一個是表名,第二個參數用於在未指定添加數據的情況下給某些可爲空的列自動賦值null,一般用不到,直接傳入null即可。第三個參數是ContextValues對象,它提供了一系列的put方法重載,用於向ContextValues中添加數據。

再次在佈局文件中添加一個按鈕。
修改MainActivity中的代碼,如下所示:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabase=(Button)findViewById(R.id.button);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                databaseHelper.getWritableDatabase();
            }
        });

	//第二個按鈕的實例與監聽器。
        Button addData=(Button)findViewById(R.id.button1);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//之前說過,創建數據庫的方法會返回一個SQLiteDatabase對象,利用這個方法創建一個SQLiteDatabase對象,命名爲db。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//創建一個ContextValues對象。
                ContentValues values=new ContentValues();
		//我們用ContextValues對象的put方法重載向values對象添加數據。
		//這四個put方法重載接收的第一個參數都是鍵名,後面是新增的值。和前面建表時的鍵名一樣,只少了一個id的鍵,因爲我們前面的建表語句中已經將id列設置爲自增長了。
                values.put("name","The Da Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages",454);
                values.put("price",16.96);
		//調用SQLiteDatabase對象的insert()方法添加數據。
                db.insert("Book",null,values);
		//這裏我們要添加兩次數據,爲了防止數據疊加出現異常,第二次添加之前,都要執行一下clear()方法清除第一次的數據。
                values.clear();
		
		//第二次添加數據。
                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);
            }
        });
	//所以,當點擊第二個按鈕的時候,監聽器內的邏輯就會執行,就會自動向BOOK表中的各列添加兩次數據。
}
以上就是向數據庫表中添加數據。

向數據庫的表中更新數據:
SQLiteDatabase中提供了update()方法用於對數據進行更新。此方法接收四個參數,第一個同樣是表名,第二個是ContextValues對象。第三第四個參數用於約束更新某一行或某幾行中的數據,不指定的話默認就是更新所有行。

再次在佈局文件中添加一個按鈕。
MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
	
	.....

        Button updateData=(Button)findViewById(R.id.button2);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//同樣獲取SQLiteDatabase對象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//創建ContextValues對象。
                ContentValues values=new ContentValues();
		//將"price"列的數據更新爲10.99。之前是16.96。
                values.put("price",10.99);
		//調用update()方法。第一個參數表名,第二個ContextValues對象,第三個是SQL語句的where部分,表示更新所有name等於?的行,?是一個佔位符。是通過四個參數提供的字符串數組爲第三個參數中的每個佔位符指定相應的內容。第四個參數中字符串數組其實就是代替了?佔位符。因此代碼表達的意圖就是name="The Da Vinci Code"。更新"The Da Vinci Code"的price值。
                db.update("Book", values, "name=?", new String[]{"The Da Vinci Code"});
            }
        });
	//當點擊以上按鈕時,The Da Vinci Code的price值就會被更新。

}
以上就是向數據庫表中的更新數據代碼。

刪除數據:
SQLiteDatabase提供了delete()方法用於刪除數據。此方法接收三個參數,第一個參數依舊是表名,第二三個參數又是用於約束刪除某一行或某幾行的數據,不指定的話默認就是刪除所有行。

再次在佈局文件中添加一個按鈕,用於點擊刪除數據。

MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
       
	......

        Button deleteData=(Button)findViewById(R.id.button3);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//獲取SQLiteDatabase對象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//delete()方法接收的三個參數,第一個Book表名,第二第三個參數的意思是刪除pages鍵裏值超過500的書籍名,也就是剛纔定義的name裏所對應的書名。剛纔我們的定義的書名中The Lost Symbol書名是超過500的,所以點擊此按鈕時,會刪除此書名數據。
                db.delete("Book", "pages>?", new String[]{"500"});
            }
        });
}
查詢數據:
SQLiteDatabase中提供了一個query()方法用於對數據進行查詢,此方法參數非常複雜,最短的重載也需要七個參數。第一個參數還是表名,第二個參數用於指定查詢哪幾列,不指定默認查詢所有列。第三第四個參數用於約束查詢某一行或某幾行的數據,不指定默認查詢所有行。第五個參數用於指定需要去group by的列,不指定則表示不對查詢結果進行group by操作。第六個參數用於對group by之後的數據進行進一步的過濾,不指定則表示不進行過濾。第七個參數用於指定查詢結果的排列方式,不指定則使用默認的排序方式。
同時調用此方法後會返回一個Cursor對象,查詢到的所有數據都將從這個對象中取出。

再次在佈局文件中添加一個按鈕。
MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        
	......

        Button queryData=(Button)findViewById(R.id.button4);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//獲取SQLiteDatabase對象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//執行query()方法後會返回一個cursor對象,利用這點創建Cursor對象。同時查詢Book表中的數據,不指定其他約束,就全部填入null。
                Cursor cursor=db.query("Book",null,null,null,null,null,null);
		//查詢出來的cursor的初始位置是指向第一條記錄的前一個位置的,cursor.moveToFirst()指向查詢結果的第一個位置。通過判斷cursor.moveToFirst()的值爲true或false來確定查詢結果是否爲空。
                if (cursor.moveToFirst()){
                    do {
                        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:"+name);
                        Log.d("MainActivity","book author:"+author);
                        Log.d("MainActivity","book pages:"+pages);
                        Log.d("MainActivity","book price:"+price);
                    }while (cursor.moveToNext());
                }
		//調用close()方法關閉Cursor。
                cursor.close();
            }
        });
以上是查詢數據代碼,查詢數據是非常複雜的,這只是一個很簡單的實例。

數據庫操作一般就是增刪改查,SQLiteDatabase提供的四個方法分別用於這些操作。
insert()方法用於添加數據,update()方法用於更新數據。delete()方法用於刪除數據,query()方法用於查詢數據。

使用事務:
事務的特性是保證讓某一系列的操作要麼全部完成,要麼一個都完不成。
在上面示例的基礎上增加使用事務,比如Book表中的數據很陳舊,需要全部廢棄替換成新數據。可以先使用delete()方法將Book表中的數據刪除,然後再使用insert()方法將新的數據添加到表中。在此要保證的是,刪除和添加的操作必須一起完成,否則就還要繼續保留原來的數據。

再次在佈局文件中添加一個按鈕。
MainActivity中的代碼:

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper databaseHelper;
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        databaseHelper=new MyDatabaseHelper(this,"BookStore.db",null,2);
        
	......

        Button replaceData=(Button)findViewById(R.id.button5);
        replaceData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
		//獲取SQLiteDatabase對象。
                SQLiteDatabase db=databaseHelper.getWritableDatabase();
		//調用beginTransaction()方法來開啓事務。
                db.beginTransaction();
                try {
		    //刪除Book表中的所有數據。
                    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 {
		    //結束事務。
                    db.endTransaction();
                }
            }
        });
    }
}
以上就是使用事務的代碼,這是很基礎的示例。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章