1. 程式人生 > 實用技巧 >《第一行程式碼》閱讀筆記(二十三)——資料庫設計(補充)

《第一行程式碼》閱讀筆記(二十三)——資料庫設計(補充)

廢話不多說,先看下結構

然後直接上程式碼

public class StudyProgressDBHelper extends SQLiteOpenHelper {
    //資料庫名
    private static final String DB_NAME = "progress.db";
    //資料庫版本號
    private static final int DB_VERSION = 1;//9-16 09:38 2-->3  10-14 17:32 3-->4 11-8 14:14 4-->5

    private Context mContext;

    //建構函式
    public StudyProgressDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        mContext = context;
    }

    //建立學習進度資料庫
    private static final String CREATE_STUDY_PROGRESS = "create table if not exists " + StudyProgressDAO.TABLE_NAME + " (" +
            StudyProgressDAO.VOA_ID + " Integer NOT NULL primary key," +
            StudyProgressDAO.LESSON + " varchar(20) ," +
            StudyProgressDAO.LISTEN_TIME + " int," +
            StudyProgressDAO.USER_ID + " int," +
            StudyProgressDAO.TOTAL_LISTEN_TIME + " int," +
            StudyProgressDAO.RIGHT_QUE_NUM + " int," +
            StudyProgressDAO.TOTAL_QUE_NUM + " int," +
            StudyProgressDAO.IS_EVALUATION_SENT_NUM + " int," +
            StudyProgressDAO.TOTAL_SENT_NUM + " int" + ")";

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_STUDY_PROGRESS);
        Timber.e("建立表成功"+CREATE_STUDY_PROGRESS);
    }

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

        }
    }
}
public interface StudyProgressDAO {

    String TABLE_NAME = "study_progress";

    String VOA_ID = "voa_id";
    String LESSON = "lesson";
    String USER_ID = "user_id";
    String LISTEN_TIME = "listen_time";
    String TOTAL_LISTEN_TIME = "total_listen_time";
    String RIGHT_QUE_NUM = "right_que_num";
    String TOTAL_QUE_NUM = "total_que_num";
    String IS_EVALUATION_SENT_NUM = "is_evaluation_sent_num";
    String TOTAL_SENT_NUM = "total_sent_num";

    public void setStudyProgress(int voaID, String databaseColumn, int value);

    public int getStudyProgress(String databaseColumn ,int voaID);

    public int getVoaId(int voaID);

}
public class StudyProgressDAOImpl implements StudyProgressDAO {

    private final SQLiteDatabase db;

    StudyProgressDAOImpl(SQLiteDatabase db) {
        this.db = db;
    }


    @Override
    public void setStudyProgress(int voaID, String databaseColumn, int value) {
        String sql;
        if (getVoaId(voaID) == 0) {
            sql = "Insert Into " + TABLE_NAME
                    + " ( " + VOA_ID + "," + databaseColumn + " )" +
                    " VALUES (" + voaID + "," + value + ")";
        } else {
            sql = " UPDATE " + TABLE_NAME
                    + " SET " + databaseColumn + " = " + value
                    + " WHERE " + VOA_ID + " = " + voaID;
        }
        db.execSQL(sql);
    }

    @Override
    public int getStudyProgress(String databaseColumn, int voaID) {
        String sql = " Select " + databaseColumn
                + " FROM " + TABLE_NAME
                + " WHERE " + VOA_ID + "= ?";
        String[] args = {String.valueOf(voaID)};
        Cursor cursor = db.rawQuery(sql, args);
        if (cursor != null && cursor.moveToFirst()) {
            return cursor.getInt(cursor.getColumnIndex(databaseColumn));
        } else {
            return 0;
        }

    }

    @Override
    public int getVoaId(int voaID) {
        String sql = " SELECT voa_id FROM study_progress  WHERE voa_id = ?" ;
        String[] args = {String.valueOf(voaID)};
        Cursor cursor = db.rawQuery(sql, args);
        db.execSQL(sql);
        if (cursor != null && cursor.moveToFirst()) {
            return cursor.getInt(cursor.getColumnIndex(VOA_ID));
        } else {
            return 0;
        }
    }
}

public class StudyProgressDBManager implements StudyProgressDAO {

    private static StudyProgressDBManager sInstance;

    private static StudyProgressDAOImpl studyProgressDAOImpl;

    public static void init(Context appContext) {
        if (sInstance == null) {
            sInstance = new StudyProgressDBManager(appContext);          
        }
    }

    public static StudyProgressDBManager getInstance() {
        if (null == sInstance) throw new NullPointerException("not init");
        return sInstance;
    }

    private StudyProgressDBManager(Context context) {
        StudyProgressDBHelper dbHelper = new StudyProgressDBHelper(context);//onCreate
        SQLiteDatabase db = dbHelper.getWritableDatabase();
     
        studyProgressDAOImpl = new StudyProgressDAOImpl(db);
    }

    @Override
    public void setStudyProgress(int voaID, String databaseColumn, int value) {
        studyProgressDAOImpl.setStudyProgress(voaID,databaseColumn,value);
    }

    @Override
    public int getStudyProgress(String databaseColumn, int voaID) {
        return studyProgressDAOImpl.getStudyProgress(databaseColumn,voaID);
    }

    @Override
    public int getVoaId(int voaID) {
        return studyProgressDAOImpl.getVoaId(voaID);
    }
}

大家看懂了沒有?這是公司裡面一個大神的資料庫設計方式,第一次看到也被這種清晰的結構所折服。接下來就讓筆者班門弄斧一下,給大家提供一些解釋吧。

StudyProgressDBHelper

public class StudyProgressDBHelper extends SQLiteOpenHelper {
    //資料庫名
    private static final String DB_NAME = "progress.db";
    //資料庫版本號
    private static final int DB_VERSION = 1;//9-16 09:38 2-->3  10-14 17:32 3-->4 11-8 14:14 4-->5

    private Context mContext;

    //建構函式
    public StudyProgressDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        mContext = context;
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
     
    }

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

        }
    }
}

首先我們應該編寫的就是Helper類,這個類需要繼承SQLiteOpenHelper。其實大家在建立郭神的《第一行程式碼》中應該早就熟悉了這個類的使用。

在這個類中,我們需要確定包名和資料庫版本,均使用 public static final修飾,並提供一個環境的成員變數。
之後新增一個建構函式,在建構函式中直接呼叫父類的建構函式,傳入環境,資料庫名,null(工廠),資料庫版本,同時將環境賦值給成員變數。

然後重寫SQLiteOpenHelper的兩個方法,建立資料庫和更新資料庫,並把建立資料庫的SQL抽取出來,讓結構更加清晰。

StudyProgressDBManager

這個管理類就是整個資料庫設計的核心,在這裡採用非常常用的單例設計模式,這樣就可以有效的防止資料庫操作的衝突。

private static StudyProgressDBManager sInstance;

下面這三個函式就是Manager的核心

public static void init(Context appContext) {
        if (sInstance == null) {
            sInstance = new StudyProgressDBManager(appContext);
            Timber.e("sInstance 建立");
        }
    }

    public static StudyProgressDBManager getInstance() {
        if (null == sInstance) throw new NullPointerException("not init");
        return sInstance;
    }

    private StudyProgressDBManager(Context context) {
        StudyProgressDBHelper dbHelper = new StudyProgressDBHelper(context);//onCreate
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Timber.e("資料庫建立成功");
    }

init()函式接收的是一個Application的Context,然後判斷sInstance是不是null,如果不為空就呼叫StudyProgressDBManager的建構函式。常常這個函式會被放在自定義的Application中,這樣就可以在專案一被建立就例項化成功。

StudyProgressDBManager的建構函式中,首先例項化StudyProgressDBHelper,然後建立一個數據庫。

最後就是一個getInstance()的方法,如果sInstance成員變數不為空,就返回例項化的sInstance(在init()函式中被例項化)。

在後續的程式設計中如果需要例項Manager,實現以下程式碼即可。

private StudyProgressDBManager 
studyProgressDBManager = StudyProgressDBManager.getInstance();
studyProgressDBManager.xxx

StudyProgressDAO

StudyProgressDAO是一個介面,相當於資料庫中的表,裡面的資訊有表名和欄位名。還有一些需要使用的方法,例如新增,查詢等。

編寫完成後,可以在helper類中,建立資料庫表。

    //建立學習進度資料庫
    private static final String CREATE_STUDY_PROGRESS = "create table if not exists " + StudyProgressDAO.TABLE_NAME + " (" +
            StudyProgressDAO.VOA_ID + " Integer NOT NULL primary key," +
            StudyProgressDAO.LESSON + " varchar(20) ," +
            StudyProgressDAO.LISTEN_TIME + " int," +
            StudyProgressDAO.USER_ID + " int," +
            StudyProgressDAO.TOTAL_LISTEN_TIME + " int," +
            StudyProgressDAO.RIGHT_QUE_NUM + " int," +
            StudyProgressDAO.TOTAL_QUE_NUM + " int," +
            StudyProgressDAO.IS_EVALUATION_SENT_NUM + " int," +
            StudyProgressDAO.TOTAL_SENT_NUM + " int" + ")";

在create函式中新增。

   db.execSQL(CREATE_STUDY_PROGRESS);

如果已經更新過一個版本,就需要增加DB_VERSION的值,並且使用update()更新資料庫。

StudyProgressDAOImpl

StudyProgressDAOImpl是StudyProgressDAO的實現類,實現StudyProgressDAO並繼承方法,其房費就是真正的資料庫操作。

其中還有一個建構函式,接收一個數據庫檔案,並傳遞給成員變數。

編寫完這個類之後,需要讓StudyProgressDBManager繼承StudyProgressDAO,然後重寫方法。並在StudyProgressDBManager建構函式中studyProgressDAOImpl = new StudyProgressDAOImpl(db);例項化DAO的實現了。在重新DAO的方式的時候,直接使用Impl回撥,即可。