SQLite数据库
SQLite简介:
Sqlite是一款轻量级的关系型数据库。关系型数据库以行和列的形式存储数据,以便于用户理解。
关系型数据库:是指采用了关系模型来组织数据的数据库
非关系型数据库:网状模型、对象模型、半结构化模型等。
SQLite是无类型的,定义类型只是为了方便程序员查看,可以在integer中添加字符串。
Android中如何管理SQLite:
在android系统中,提供了一个SQLiteOpenHelper抽象类,用于对数据库进行操作。
/**
* Created by gj on 2016/4/21.
* Message消息信息数据库帮助类
*/
public class MessageDBOpenHelper extends SQLiteOpenHelper {
/**
* context 上下文对象,
* 数据库名称
* 游标结果集工厂。null使用android默认的
* 数据库版本号,必须大于1
*/
public MessageDBOpenHelper(Context context) {
super(context, "phonekeymes.db", null, 1);
}
/**
* 数据库创建,数据库第一次创建时调用。
* @param db The database.
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table messageinfo(_id integer primary key autoincrement,accountToken varchar(40),subname varchar(40),comeType varchar(20),mesType varchar(20),msg varchar(512),time varchar(20),code integer,isRead varchar(2))");
db.execSQL("create table message_flag(_id integer primary key autoincrement,accountToken varchar(40),code varchar(20))");
}
/**
* 数据库版本升级时回调
* @param db The database. 当前数据库对象,
* @param oldVersion The old database version.老版本号
* @param newVersion The new database version.新版本号
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//更新表结构
// if(oldVersion ==1&& newVersion==2){
// db.execSQL("alter table add column isdelete integer");
// }
}
}
数据库版本号必须大于1,不大于1会抛出异常
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) { if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version); …… }
SQLiteOpenHelper.getWritableDatabase可以拿到数据库对象SQLiteDatabase
遇到的问题:
相同的名称的数据库,两张表,使用了两个SQLiteOpenHelper对象,分别进行创建表。
当执行过一次表的操作后,执行第二张表的操作时,会报找不到这个表 no such table
后来把同一个数据库的建表放到同一个SQLiteOpenHelper中。问题解决。
理解:同一个数据库即一个文件,当有SQLiteOpenHelper类操作这个文件时。再来访问同一个表,即报错。
操作数据库SQLiteDatabase
Android提供了一个SQLiteDatabase的类,该类封装了一些操作数据库的API,使用该类可以完成对数据进行增删改查操作。CRUD
SQLiteDatabase
execSQL(“sql语句”);可以执行insert、delete、update和create table之类有更改行为的sql语句
rawQuery(“sql语句”);用于执行select语句。
增删改查
package cn.gyyx.phonekey.util.db.dao; /** * Created by gj on 2016/4/21. */ public class MessageInfoDao { private MessageDBOpenHelper helper; /** * 只有一个有参的构造方法,要求必须传入上下文 * @param context */ public MessageInfoDao(Context context) { helper = new MessageDBOpenHelper(context); } /** * 添加一條數據 */ public void add(MessageInfo msgeInfo){ SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("insert into messageinfo(accountToken,subname,comeType,mesType,msg,time,code,isRead) values (?,?,?,?,?,?,?,?)", new Object[]{msgeInfo.accountToken,msgeInfo.subName,msgeInfo.comeType,msgeInfo.mesType,msgeInfo.msg,msgeInfo.time,msgeInfo.flagCode,msgeInfo.isRead?1:0}); db.close();//释放资源 helper.close(); } /** * 根据token删除数据 * @param token */ public void deleteByAccountToken(String token){ SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("delete from messageinfo where accountToken=?",new Object[]{token}); db.close(); helper.close(); } /** * 删除所有消息数据 */ public void deleteAllMes(){ SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("delete from messageinfo",new Object[]{}); db.close(); helper.close(); } /** * 添加集合数据 */ public void insertList(List<MessageInfo> list){ SQLiteDatabase db = helper.getWritableDatabase(); db.beginTransaction(); try{ for(MessageInfo msgeInfo:list){ //先判断是否存在 if(selectByTokenAndCode(db,msgeInfo.accountToken,msgeInfo.flagCode)){ }else{ db.execSQL("insert into messageinfo(accountToken,subname,comeType,mesType,msg,time,code,isRead) values (?,?,?,?,?,?,?,?)", new Object[]{msgeInfo.accountToken,msgeInfo.subName,msgeInfo.comeType,msgeInfo.mesType,msgeInfo.msg,msgeInfo.time,msgeInfo.flagCode,msgeInfo.isRead?1:0}); } } db.setTransactionSuccessful(); }catch(Exception e){ e.printStackTrace(); }finally { db.endTransaction(); db.close(); helper.close(); } } /** * 根据当前token和code 更新状态为已读 * @param token * @param code * @return */ public void updataReadByTokenAndCode(String token,String code){ SQLiteDatabase db = helper.getReadableDatabase(); db.execSQL("update messageinfo set isRead = ? where accountToken = ? and code = ?", new String[]{"1", token, code}); db.close(); helper.close(); } /** * 判断当前token和code 信息是否已存在 * @param db * @param token * @param code * @return */ private boolean selectByTokenAndCode(SQLiteDatabase db,String token,String code){ Cursor cursor = db.rawQuery("select * from messageinfo where accountToken = ? and code = ?",new String[]{token,code}); if(cursor.getCount()>0){ return true; } return false; } /** * 获取全部的消息信息 * @return List<MessageInfo> */ public List<MessageInfo> findAll(){ List<MessageInfo> messageInfos =new ArrayList<MessageInfo>(); SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from messageinfo order by code desc", null); while(cursor.moveToNext()){ MessageInfo messageInfo = new MessageInfo(); messageInfo.accountToken = cursor.getString(cursor.getColumnIndex("accountToken")); messageInfo.comeType = cursor.getString(cursor.getColumnIndex("comeType")); messageInfo.mesType = cursor.getString(cursor.getColumnIndex("mesType")); messageInfo.msg = cursor.getString(cursor.getColumnIndex("msg")); messageInfo.time = cursor.getString(cursor.getColumnIndex("time")); messageInfo.flagCode = cursor.getString(cursor.getColumnIndex("code")); messageInfo.isRead = "1".equals(cursor.getString(cursor.getColumnIndex("isRead")))?true:false; messageInfo.subName = cursor.getString(cursor.getColumnIndex("subname")); messageInfos.add(messageInfo); LogUtil.e("gj",messageInfo.toString()); } cursor.close(); db.close(); helper.close(); return messageInfos.size()>0?messageInfos:null; } }
游标结果集:Cursor
游标指向获取到的数据集合的前面
Cursor.moveToNext();将游标移动到下一行,如果移过了最后一行返回false。否则返回true
moveToFirst();移动到第一行,返回boolean
moveToLast();移动到最后一行,返回boolean
cursor.close();关闭游标
事务使用:
事务是什么:
事务就是指一批sql操作,一块执行,要么都成功,要么都失败。
为什么用事务:
1. 提高效率,单独使用插入一条一条的语句,插入一次就是一次磁盘的写入操作,效率会很低。使用事务是在进行事务提交时,将要执行的Sql操作一次性打开数据库连接并执行。(sqlite中)
2. 当执行一批sql操作时,可能会有失败的。前面失败,后面的成功。会造成一些不可控的问题。
主要方法:
beginTransaction();开启一个事务
setTransactionSuccessful();设置成功标记
endTransaction();结束事务,根据标记提交或回滚。
Android自身对SQL语句的封装:
SQLiteDatabase db =helper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("code","1212"); values.put("accountToken","44454345");
//插入 db.insert("表名", "列名", values);
//删除 db.delete("表名", "accountToken =?", new String[]{"44454345"});
//更新 db.update("表名", values, "accountToken=?", new String[]{"1212212"});
//查询,通过code排序降序 Cursor cursor = db.query("表名",new String[]{"code"},"accountToken = ?",new String[]{"1212212"},null,null,"code desc");
//查询所有 Cursor cursor1 = db.query("表名",new String[]{"code"},null,null,null,null,null);
insert
insert into 表名(column1,column2) values(value1,value2)
delete
delete fromtableName where column1 = value1
update
update tableNameset column1 = value1 where column2 = value2
select
select * fromtableName
select * fromtableName where column1>100 order by column2 desc
问题
1.能存储byte吗?
直接存进去转出来有问题。需要做特殊处理
2.数据库版本降级?
Caused by:android.database.sqlite.SQLiteException: Can't downgrade database from version2 to 1
3.b-tree是啥?
百度:B-tree(多路搜索树,并不是二叉的)是一种常见的数据结构。使用B-tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。按照翻译,B 通常认为是Balance的简称。这个数据结构一般用于数据库的索引,综合效率较高。
1.student表,插入age 18,name“xiao王”?
insert intostudent (age,name) values(18,’xiao王’)
2.更新student xiao王 年龄为16?
update student setage=16 where name=’xiao王’ and age=18
3.删除student 年龄大于15的 所有行
delete fromstudent where age>15
4.查询所有student 年龄小于20的,年龄倒叙。
select * fromstudent where age<20 order by age desc