《第一行代码》阅读笔记(二十三)——数据库设计(补充)
废话不多说,先看下结构
然后直接上代码
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回调,即可。