登录 注册写文章
首页下载APP
aserbao 关注
赞赏支持
数据库SQLite.jpg
qrcode_for_gh_2886db5aaf83_258.jpg
aserbao 拥有147钻 (约15.57元) 关注 "小礼物走一走,来简书关注我" 赞赏
广告
aserbao关注 拥有147钻 (约15.57元) Android 相机开发,音视频入门教程全解 阅读 74 Android P之后关于网络的小知识点 阅读 38 年薪200W要交多少税 阅读 210
广告
评论0 赞6 6赞7赞 赞赏
一篇技术好文之Android数据库 SQite全解析
一篇技术好文之Android数据库 SQite全解析
0.556 字数 737阅读 672
数据库SQLite.jpg
这篇文章是数据库系列篇文章的第一篇,主要讲Android Sqlite数据库存储,后面陆续出GreenDao,LitePal, Realm,wcdb的文章,一如既往,如果遇到任何关于Android中SQLite的问题,都可以直接在我的文章底部留言,或者直接在我的公众号aserbao留言,文章会持续更新,希望这篇文章能为大家提供到帮助!如果觉得文章对你有用,就帮忙点个赞,若觉得文章写得不好之处望指出,必将加以修正!
qrcode_for_gh_2886db5aaf83_258.jpg
这篇文章主要讲SQlite数据库存储,从数据库建表到数据库的增删改查操作,再到数据库升级操作,最后是文章总结及参考链接
SQlite
1. 创建数据库
Android中使用SQlite,需要自己创建库,建表,添加数据!好在Android中提供了SQLiteOpenHelper类来帮助创建使用数据库,我们只需要继承这个类就可以实现数据库的创建和对数据的操作了!Android 中创建数据库需要通过如下几部:
- 创建一个类继承SQLiteOpenHelper,需要实现其三个方法:
- 构造方法:需要给SQLiteOpenHelper传递四个参数:(上下文,数据库名,游标工厂(通常为null),当前数据库版本号);
- onCreate(): 表的创建,初始化操作
- onUpgrade(): 表升级
- 还有:onDowngrade(): 表降级,onOpen:每次打开数据库,onBeforeDelete:
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: | 包含了 小时、分钟、秒。 |
2. 创建一个数据库存储对象
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;
}
}
3. 创建一个数据库控制器实现增删改查
1. 增
- 使用Android APi来实现增加数据
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;
}
- 使用Sql语句实现增加数据
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();
}
2. 删
- 使用Api
public boolean deleteApi(String whereClause,String[] whereArgs){
boolean sucess = db.delete(TABLE_NAME, whereClause,whereArgs) != -1;
dbClose();
return sucess;
}
- 使用Sql语句
public void deleteRaw(String message){
String sql = "delete from "+TABLE_NAME + " where message = ?";
Object[] args = {message};
db.execSQL(sql,args);
dbClose();
}
3. 改
- 使用api
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;
}
- 使用Sql条件修改
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();
}
4. 查
- 使用Api
/**
* @param cloums 要查询的字段
* @param selection 查询条件
* @param selectionArgs 填充查询条件的值
* @return
*/
public List<Thing> queryApi(String[] cloums,String selection,String[] selectionArgs){
try {
Cursor c = db.query(TABLE_NAME, cloums, selection, selectionArgs, null, null, null);
ArrayList<Thing> 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<>();
}
- 使用sql条件
public List<Thing> queryRawById(String id){
//cursor获取的一定是在这里申明的查询条件值
String sql = "select _id,message,time from "+TABLE_NAME + " where _id = ?";
Cursor cursor = db.rawQuery(sql, new String[]{id});
ArrayList<Thing> 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;
}
4. 数据库的升级
在开发的过程中,我们避免不了需要修改数据库结构,添加字段或者删除字段!我们通过增加传递给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)
参考链接
6人点赞 技术好文推荐阅读更多精彩内容
- Android - 收藏集 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
hw1212
- Android - 收藏集 Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
passiontim
- 一篇技术好文之Android数据库 GreenDao的使用完全解析 之前在开发过程中,数据库基本上会使用Litepal或者SQlite自己写,最近换新环境,公司原先使用的数据库就是G...
aserbao
- 【Android】数据存储全方案之SQLite初体验 作者:邹峰立,微博:zrunker,邮箱:zrunker@yahoo.com,微信公众号:书客创作,个人平台:ww...
吾非言
- 不要抛弃我,不要拒绝我(续) 关于我和宁巸的关系的确有些耐人寻味的地方。通常进入长程治疗的患者,我都会给予我的电话,以便患者在有需要时方便求助。...
爱闲聊的康老师