这篇文章是数据库系列篇文章的第一篇,主要讲Android Sqlite数据库存储,后面陆续出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何关于Android中SQLite的问题,都可以直接在我的文章底部留言,或者直接在我的公众号aserbao留言,文章会持续更新,希望这篇文章能为大家提供到帮助!如果觉得文章对你有用,就帮忙点个赞,若觉得文章写得不好之处望指出,必将加以修正!
这篇文章主要讲SQlite数据库存储,从数据库建表到数据库的增删改查操作,再到数据库升级操作,最后是文章总结及参考链接
Android中使用SQlite,需要自己创建库,建表,添加数据!好在Android中提供了SQLiteOpenHelper类来帮助创建使用数据库,我们只需要继承这个类就可以实现数据库的创建和对数据的操作了!Android 中创建数据库需要通过如下几部:
public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "mysql.db";
private static final int VERSION = 1;
public ThingManagerDBOpenHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS "
+ ThingDBController.TABLE_NAME
+ String.format(
"("
+ "%s INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "%s VARCHAR, "
+ "%s INTEGER"
+")"
, ThingManagerDBModel.ID
, ThingManagerDBModel.MESSAGE
, ThingManagerDBModel.TIME
)) ;
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
……
}
}
说下SQlite的数据类型 :
值 | 作用 |
---|---|
NULL: | 这个值为空值 |
VARCHAR(n): | 长度不固定且其最大长度为 n 的字串,n不能超过 4000。 |
CHAR(n): | 长度固定为n的字串,n不能超过 254。 |
INTEGER: | 值被标识为整数,依据值的大小可以依次被存储为1,2,3,4,5,6,7,8. |
REAL: | 所有值都是浮动的数值,被存储为8字节的IEEE浮动标记序号. |
TEXT: | 值为文本字符串,使用数据库编码存储(TUTF-8, UTF-16BE or UTF-16-LE). |
BLOB: | 值是BLOB数据块,以输入的数据格式进行存储。如何输入就如何存储,不改 变格式。 |
DATA: | 包含了 年份、月份、日期。 |
TIME: | 包含了 小时、分钟、秒。 |
public final class ThingManagerDBModel {
public static final String TABLE_NAME = "mysql_thing";
public static final String ID = "_id";
public static final String MESSAGE = "message";
public static final String TIME = "time";
int id;
String message;
long time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public ContentValues toContentValues(){
ContentValues cv = new ContentValues();
cv.put(MESSAGE, message);
cv.put(TIME, time);
return cv;
}
}
public boolean insertApi(int id, String message, long time){
ThingManagerDBModel dbModel = new ThingManagerDBModel();
if(id >= 0) {
dbModel.id = id;
}
dbModel.message = message;
dbModel.time = time;
final boolean success = db.insert(TABLE_NAME, null, dbModel.toContentValues()) != -1;
dbClose();
return success;
}
public void insertRaw(String message, long time){
String sql = " insert into " + TABLE_NAME + "(message,time) values(?,?)";
Object[] args = {message,time};
db.execSQL(sql,args);
dbClose();
}
public boolean deleteApi(String whereClause,String[] whereArgs){
boolean sucess = db.delete(TABLE_NAME, whereClause,whereArgs) != -1;
dbClose();
return sucess;
}
public void deleteRaw(String message){
String sql = "delete from "+TABLE_NAME + " where message = ?";
Object[] args = {message};
db.execSQL(sql,args);
dbClose();
}
public boolean updateApi(int id,String message,long time){
ThingManagerDBModel dbModel = new ThingManagerDBModel();
if(id >= 0) {
dbModel.id = id;
}
dbModel.message = message;
dbModel.time = time;
boolean success = db.update(TABLE_NAME, dbModel.toContentValues(), "_id = ?", new String[]{String.valueOf(id)}) != -1;
dbClose();
return success;
}
public void updateRaw(int id,String message,long time){
String sql = "update "+TABLE_NAME + " set message = ?,time = ? where _id = ?";
Object[] args = {message,time,id};
db.execSQL(sql,args);
dbClose();
}
/**
* @param cloums 要查询的字段
* @param selection 查询条件
* @param selectionArgs 填充查询条件的值
* @return
*/
public List queryApi(String[] cloums,String selection,String[] selectionArgs){
try {
Cursor c = db.query(TABLE_NAME, cloums, selection, selectionArgs, null, null, null);
ArrayList arrayList = new ArrayList<>();
if (!c.moveToLast()) {
return arrayList;
}
do {
Thing model = new Thing();
model.setId(c.getInt(c.getColumnIndexOrThrow(ThingManagerDBModel.ID)));
model.setTime(c.getLong(c.getColumnIndexOrThrow(ThingManagerDBModel.TIME)));
model.setMessage(c.getString(c.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
arrayList.add(model);
} while (c.moveToPrevious());
c.close();
return arrayList;
}catch (Exception e){
e.printStackTrace();
}finally {
dbClose();
}
return new ArrayList<>();
}
public List queryRawById(String id){
//cursor获取的一定是在这里申明的查询条件值
String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";
Cursor cursor = db.rawQuery(sql, new String[]{id});
ArrayList arrayList = new ArrayList<>();
if (!cursor.moveToLast()) {
return arrayList;
}
do {
Thing model = new Thing();
model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));
model.setTime(cursor.getLong(cursor.getColumnIndex(ThingManagerDBModel.TIME)));
model.setMessage(cursor.getString(cursor.getColumnIndexOrThrow(ThingManagerDBModel.MESSAGE)));
arrayList.add(model);
} while (cursor.moveToPrevious());
cursor.close();
dbClose();
return arrayList;
}
在开发的过程中,我们避免不了需要修改数据库结构,添加字段或者删除字段!我们通过增加传递给SQLiteOpenHelper的版本值,得到onUpgrade方法的回调来实现对数据库的操作来进行升级。这里需要注意的是,如果用户安装版本1之后直接跳装版本3,这时候我们就需要在onUpgrade方法中通过oldVersion来进行每一个版本的逐渐升级,方法如下:
public class ThingManagerDBOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "mysql.db";
private static final int VERSION = 3;
……
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion){
case 1:
upToDbVersion2(db);
case 2:
upToDbVersion3(db);
default:
break;
}
}
public void upToDbVersion2(SQLiteDatabase db){
db.execSQL("ALTER TABLE " + ThingDBController.TABLE_NAME + " ADD COLUMN add_user_name text");
}
public void upToDbVersion3(SQLiteDatabase db) {
ContentValues values = new ContentValues();
values.put("message", "版本升级后的数据");
db.update(ThingDBController.TABLE_NAME, values, null, null);
}
}
Cursor只会拥有你查询的数据,如果在查询条件里面没有申请,Cursor里面就不会包含这个值,就会出现如下异常:
错误写法:
String sql = "select message,time from "+TABLE_NAME + " where _id = ?";//条件里面没有申请查询_id的值
……something……
model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//在这里提取会报异常
正确写法:
String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";//条件里面没有申请查询_id的值
……something……
model.setId(cursor.getInt(cursor.getColumnIndex(ThingManagerDBModel.ID)));//这里进行id值的提取
异常:
java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:513)
at android.database.CursorWindow.getInt(CursorWindow.java:580)
at android.database.AbstractWindowedCursor.getInt(AbstractWindowedCursor.java:69)
at com.aserbao.aserbaosandroid.functions.database.mySql.beans.ThingDBController.queryRawById(ThingDBController.java:109)
at com.aserbao.aserbaosandroid.functions.database.mySql.MySqlActivity.queryData(MySqlActivity.java:70)
at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity.onViewClicked(DataBaseBaseActivity.java:85)
at com.aserbao.aserbaosandroid.functions.database.base.DataBaseBaseActivity_ViewBinding$2.doClick(DataBaseBaseActivity_ViewBinding.java:48)
at butterknife.internal.DebouncingOnClickListener.onClick(DebouncingOnClickListener.java:22)
at android.view.View.performClick(View.java:6291)
at android.view.View$PerformClick.run(View.java:24931)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:166)
at android.app.ActivityThread.main(ActivityThread.java:7425)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:245)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:921)