【Sqlite試用】java語言

boat

  1. 視頻學習來源b站:程序猿拉大鋸
    在這裏插入圖片描述
  2. 【ctrl+N】查找SQLiteOpenHelper發現他是個抽象類,【ctrl+H】查看繼承關係,其沒有實現類
  3. Sql語句
    在這裏插入圖片描述

1. 【創建數據庫】實現升級版本

1.建立一個類DatabaseHelper繼承SQLiteOpenHelper

  1. 實現兩個成員方法onCreate()onUpgrade() 分別是數據庫第一次創建時的回調和升級數據庫時的回調
  2. 複寫一個四參構造方法
    a. 上下文
    b.數據庫名
    c.遊標工廠(用來創建遊標對象,類指針,指向某一行,該行有對應的許多字段,null爲默認)
    d.版本號(只能升級不能降級)
  3. 建立一個類Constances,寫靜態成員變量用於記錄成員信息,供2中的構造方法調用,
  4. 運行虛擬機找到data/data/com.ywjh.databasedemo
    1)目前只有兩個文件夾
    2)new一個help對象,傳入當前上下文,就有數據庫了,暫時告別sql語句
DatabaseHelper helper=new DatabaseHelper(this);//創建對象,調用構造方法創建數據庫
helper.getWritableDatabase();//獲取數據庫

在這裏插入圖片描述

2. 完善增刪改查,首先確定字段

  1. 理所當然的在DatabaseHelper的oncreate方法中初始化創建字段(把原數據庫先刪了),Constances中寫個靜態表名
   public void onCreate(SQLiteDatabase db) {
        Log.d(TAG,"創建數據庫");
        //創建字段
        //sql create table table_name(id integer,name varchar(50),age integer,salary integer)//sqlite 都是varchar
        String sql="create table "+Constants.TABLE_NAME+"(_id integer,name varchar,age integer,salary integer)";
        db.execSQL(sql);//執行語句
    }
  1. 使用Sqlite Expert觀察4個字段就有了
    在這裏插入圖片描述
  2. 使用一下onupdate方法添加字段(數據庫名,老版本號,新版本號)
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG,"升級數據庫");
        //sql:alter table table_name add phone integer;
        String sql="alter table "+Constants.TABLE_NAME+" add phone integer";
        db.execSQL(sql);
    }

運行之後發現沒變化,查看說明要更新版本號纔會調用變化,我們此時更改寫好的靜態調用版本號(後臺會對比,不同則正常old和new版本號進行升級)。運行發現升級的log已經打印了,刷新查看就有了,還多測試了一個sno。
在這裏插入圖片描述在這裏插入圖片描述

  1. 爲了方便觀察版本號更新迭代,可以加入switch(ps:用逗號隔開字段時可能會顯示檢查錯誤,不過是誤報)在這裏插入圖片描述
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG,"升級數據庫");
        //sql:alter table table_name add phone integer;
        String sql;
        switch (oldVersion){
            case 1:
                //添加address和phone字段
                 sql="alter table "+Constants.TABLE_NAME+" add  phone integer,address varchar";
                db.execSQL(sql);
                break;
            case 2:
                sql="alter table "+Constants.TABLE_NAME+" add  sno integer";
                db.execSQL(sql);
                break;
            case 3:
                sql="alter table "+Constants.TABLE_NAME+" add  address varchar";
                db.execSQL(sql);
                break;
        }
    }

2.【增刪改查】

public class Dao {
    private static final String TAG ="Dao Query" ;
    private final DatabaseHelper mhelper;

    public Dao(Context context){

        //創建並拿到數據庫
         mhelper= new DatabaseHelper(context);
        //helper.getWritableDatabase();
    }

    public void insert(){
        //寫入
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
        String sql="insert into "+Constants.TABLE_NAME+"(_id,name,age,salary,phone,sno,address) values(?,?,?,?,?,?,?)";
        db.execSQL(sql,new Object[]{1,"Kirika",18,1,12345,"201701014145","china"});
        db.close();//關閉相關引用
    }
    public void delete(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
        String sql="delete from "+Constants.TABLE_NAME+ " where age=18";
        db.execSQL(sql);
        db.close();//關閉相關引用
    }
    public void update(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
        String sql="update "+Constants.TABLE_NAME+ " set salary=2 where age=18";
        db.execSQL(sql);
        db.close();//關閉相關引用
    }
    public void query(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
        String sql="select * from "+Constants.TABLE_NAME;
        //db.execSQL(sql); 這個方法無返回值的
        Cursor cursor= db.rawQuery(sql,null);
        while (cursor.moveToNext()){
            int index=cursor.getColumnIndex("name");
            String name=cursor.getString(index);
            Log.d(TAG,name);
            //cursor.getString(1);//獲取第一列,從0開始且不含首爲計數列
        }
        cursor.close();//資源型關閉
        db.close();//關閉相關引用
    }
}

3.【編寫測試類】測試的好處在於每個方法都可以直接運行,先不用加入到核心代碼中

  1. 新版不用繼承AndroidTextCase而是
    a. 類前加上@RunWith(AndroidJUnit4.class)
    b.方法前加上 @Test
    c.Context appContext = InstrumentationRegistry.getTargetContext();獲取上下文
    d.運行報錯說找不了test例子,就納悶了,後來查閱將gradle工具run test using改爲IDEA重啓即可。
    在這裏插入圖片描述
  2. 其他測試了也沒問題
package com.ywjh.databasedemo;

import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

@RunWith(AndroidJUnit4.class)
public class TestDatabase  {
    Context appContext = InstrumentationRegistry.getTargetContext();
    @Test
    public void testCreate() {
        //測試創建數據庫

    }
    @Test
    public void testInsert() {
        //測試插入數據
        //System.out.println("111");
        Dao dao=new Dao(appContext);
        dao.insert();

    }
    @Test
    public void testDelete() {
        //測試刪除數據
        Dao dao=new Dao(appContext);
        dao.delete();
    }
    @Test
    public void testUpdate() {
        //測試刪除數據
        Dao dao=new Dao(appContext);
        dao.update();
    }
    @Test
    public void testQuery() {
        //測試查找數據
        Dao dao=new Dao(appContext);
        dao.query();
    }
}

4.【安卓API_CRUD】sql語句較爲嚴格,空格之類的比較麻煩,google提供封裝了語法API

改寫爲面向對象式的,完全OK

public void insert(){
        //寫入
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
       /* String sql="insert into "+Constants.TABLE_NAME+"(_id,name,age,salary,phone,sno,address) values(?,?,?,?,?,?,?)";
        db.execSQL(sql,new Object[]{1,"Kirika",18,1,12345,"201701014145","china"});*/

        ContentValues values=new ContentValues();//接着添加數據
                      values.put("_id",2);
                      values.put("name","larrpage");
                      values.put("age",18);
                      values.put("salary",23243);
                      values.put("phone",12345);
                      values.put("sno","2017023432");
                      values.put("address","china");
        db.insert(Constants.TABLE_NAME,null,values);//二參數是可否爲空字段  三參數是填充內容 hashMap結構
        db.close();//關閉相關引用
    }
    public void delete(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
        /*String sql="delete from "+Constants.TABLE_NAME+ " where age=18";
        db.execSQL(sql);*/
        int result=db.delete(Constants.TABLE_NAME,null,null);//判斷條件與返回值 返回爲刪除行數
        System.out.println("刪除結果爲:"+result);
        db.close();//關閉相關引用
    }
    public void update(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
       /* String sql="update "+Constants.TABLE_NAME+ " set salary=2 where age=18";
        db.execSQL(sql);*/

        ContentValues values=new ContentValues();//接着添加數據
                      values.put("phone",2222222);

        db.update(Constants.TABLE_NAME,values,null,null);//null爲所有記錄
        db.close();//關閉相關引用
    }
    public void query(){
        SQLiteDatabase db= mhelper.getWritableDatabase();//獲取到數據庫後對錶進行查找
     /*   String sql="select * from "+Constants.TABLE_NAME;
        //db.execSQL(sql); 這個方法無返回值的
        Cursor cursor= db.rawQuery(sql,null);
        while (cursor.moveToNext()){
            int index=cursor.getColumnIndex("name");
            String name=cursor.getString(index);
            Log.d(TAG,name);
            //cursor.getString(1);//獲取第一列,從0開始且不含首爲計數列
        }
        cursor.close();//資源型關閉*/


        Cursor cursor=db.query(Constants.TABLE_NAME,null,null,null,null,null,null);
        while (cursor.moveToNext()){
            int id=cursor.getInt(0);
            String name=cursor.getString(1);
            Log.d(TAG,"id=="+id+" name"+name);
        }
        cursor.close();
        db.close();//關閉相關引用
    }

5.【數據庫事務Transcation】安全性與高效性

1.情景

  1. 每月15號,公司發工資,財務有100000,要-1200,你的賬號+1200,此時停電了,公司減了,但賬號未增加

2. 測試安全性編碼

  1. 創建安卓項目後再次新建類繼承SQLiteOpenHelpter,寫個構造方法用於初始化
public class DatabaseHelpter extends SQLiteOpenHelper {
    public DatabaseHelpter(Context context) {
        super(context,"account.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table account(_id integer,name varchar,money integer)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

  1. 編寫測試類
    1)完成數據庫構造方法創建數據庫並且伴生oncreate()創建Account表,接着測試插入和更新(流程都是通過創建的Helpter對象返回的對應數據庫,然後獲取對應權限,返回權限對象,通過對象進行sql操作)

@RunWith(AndroidJUnit4.class)
public class TestDataBase {
    Context appContext = InstrumentationRegistry.getTargetContext();
    @Test//用於執行創建的方法
    public void testDataBase(){
        //測試數據庫創建
        System.out.println("1111111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        helpter.getReadableDatabase();
    }

    @Test
    public void testInsert() {
        //測試插入數據的方法
        //System.out.println("111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        SQLiteDatabase db=helpter.getReadableDatabase();
        db.execSQL("insert into account values(1,'tony',100000)");
        db.execSQL("insert into account values(2,'myc',0)");
        db.close();
    }

    @Test
    public void testUpdate() {
        //測試插入更新數據的方法
        //System.out.println("111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        SQLiteDatabase db=helpter.getReadableDatabase();
        db.execSQL("update account set money = 100000-1200 where name= 'tony'");
        //人爲模擬一次異常 發現只執行了第一句
        int i=10/0;//分母爲0出異常
        db.execSQL("update account set money =1200 where name= 'myc'");
    }
}

執行後發現人爲中斷前的操作都執行了
在這裏插入圖片描述

  1. 改寫update,加入try-catch與事務套餐
 @Test
    public void testUpdate() {
        //測試插入數據
        //System.out.println("111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        SQLiteDatabase db=helpter.getReadableDatabase();
        db.beginTransaction();
        //人爲模擬一次異常 發現只執行了第一句
        try{
            db.execSQL("update account set money = 100000-600 where name= 'tony'");
            int i=10/0;//分母爲0發生異常
            db.execSQL("update account set money =1200 where name= 'myc'");
            db.setTransactionSuccessful();
        }catch(Exception e){
            //處理異常
           throw new RuntimeException("停電了");
        }finally {
            db.endTransaction();
            db.close();
        }

    }

這裏我們修改了中斷前的操作,運行發現中斷前後都不執行,數據庫不變
在這裏插入圖片描述

3.測試高效性編碼

  1. 修改insert,使其插入6000條數
 @Test
    public void testInsert() {
        //測試插入數據
        //System.out.println("111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        SQLiteDatabase db=helpter.getReadableDatabase();

        long start=System.currentTimeMillis();
        for(int i=0;i<3000;i++){
            db.execSQL("insert into account values(1,'company',200000)");
            db.execSQL("insert into account values(2,'my_count',0)");
        }
        Log.d(TAG,"usetime =="+(System.currentTimeMillis()-start));
        System.out.println("使用時間爲:"+(System.currentTimeMillis()-start));

  /*      db.execSQL("insert into account values(1,'tony',100000)");
        db.execSQL("insert into account values(2,'myc',0)");*/
        db.close();
    }
  1. 開啓事務,十分高效開啓和關閉,十分簡潔。 原理是:
    a:原操作是打開數據庫,插入數據,關閉數據庫(耗時較多)
    b:運用事務:將數據存入存,通過內存寫入,同目錄下的journay就是防止文件過大而生成的temp文件。
@Test
    public void testInsert() {
        //測試插入數據
        //System.out.println("111");
        DatabaseHelpter helpter=new DatabaseHelpter(appContext);
        SQLiteDatabase db=helpter.getReadableDatabase();

        long start=System.currentTimeMillis();
        db.beginTransaction();
        for(int i=0;i<3000;i++){
            db.execSQL("insert into account values(1,'company',200000)");
            db.execSQL("insert into account values(2,'my_count',0)");
        }
        db.endTransaction();
        Log.d(TAG,"usetime =="+(System.currentTimeMillis()-start));
        System.out.println("事務使用時間爲:"+(System.currentTimeMillis()-start));

  /*      db.execSQL("insert into account values(1,'tony',100000)");
        db.execSQL("insert into account values(2,'myc',0)");*/
        db.close();
    }

下面是對比圖
在這裏插入圖片描述
在這裏插入圖片描述

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