我最近做项目用到了这个SQLite本地数据库,所以写篇博客总结一下,希望也能对小白有所帮助
什么时候用SQLite(有固定规则的,大量的数据要保存时)
SharedPreferences是一种轻型的数据存储方式,在保存数据的时候其实存储的是key-value对,类似于Map。存储位置:/data/data/应用包名/shared_prefs/文件名.xml。通常用来存储一些简单的配置信息。实际开发中,SharedPreferences共享参数经常存储的数据有App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。
简单且孤立的数据可保存在SharedPreferences。若是复杂且相互间有关的数据,则要保存在数据库中。(有固定规则的,大量的数据保存在数据库中)
文本形式的数据可保存在SharedPreferences。若是二进制数据,则要保存在文件中。(没有固定规则的,大量的数据保存在文件中)
haredPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
SQLite是一个小巧的嵌入式数据库,使用方便、开发简单。它只是一个嵌入式的数据库引擎。在Android里,提供了SQLiteDatabase类,该类的一个对象就表明一个数据库,其实在底层就是一个文件。默认存储位置:/data/data/
SQLiteDatabase数据库管理类(直接对数据库进行操作)
SQLiteDatabase是SQLite的数据库管理类,开发者可以在活动页面代码或任何能取到Context的地方获取数据库实例。然后通过SQLiteDatabase提供的一些API来对数据库进行操作:
// 创建名叫test.db的数据库。数据库如果不存在就创建它,如果存在就打开它
SQLiteDatabase db = openOrCreateDatabase(getFilesDir() + "/test.db", Context.MODE_PRIVATE, null);
// 删除名叫test.db数据库
// deleteDatabase(getFilesDir() + "/test.db");
调用该类API要用到SQL语句,SQLite的多数SQL语法与Oracle一样,可以到菜鸟网上查阅:https://www.runoob.com/sqlite/sqlite-tutorial.html
SQLiteDatabase中常用的API:
1. 管理类,用于数据库层面的操作。
- openDatabase:打开指定路径的数据库。
- isOpen:判断数据库是否已打开。
- close:关闭数据库。
- getVersion:获取数据库的版本号。
- setVersion:设置数据库的版本号。
2. 事务类,用于事务层面的操作。
- beginTransaction:开始事务。
- setTransactionSuccessful:设置事务的成功标志。
- endTransaction:结束事务。执行本方法时,系统会判断是否已执行setTransactionSuccessful,如果之前已设置就提交,如果没有设置就回滚。
3. 数据处理类,用于数据表层面的操作。
- execSQL:执行拼接好的SQL控制语句。一般用于建表、删表、变更表结构。
- delete:删除符合条件的记录。
- update:更新符合条件的记录。
- insert:插入一条记录。
- query:执行查询操作,返回结果集的游标。
- rawQuery:执行拼接好的SQL查询语句,返回结果集的游标。
但是直接通过SQLiteDatabase进行操作数据库非常不方便,必须小心不能重复地打开数据库,处理数据库的升级也很不方便。
因此Android提供了一个辅助工具—— SQLiteOpenHelper,我们可以通过SQLiteOpenHelper这个数据库帮助器来安全方便地打开、升级数据库。
SQLiteOpenHelper数据库帮助器(安全方便地打开、升级数据库)
使用方法:
新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和onUpgrade两个方法。
其中,onCreate方法只在第一次打开数据库时执行,在此可进行表结构创建的操作;
onUpgrade方法在数据库版本升高时执行,因此可以在onUpgrade函数内部根据新旧版本号进行表结构变更处理。
例如:
//数据库帮助器SQLiteOpenHelper
public class MySqliteHelper extends SQLiteOpenHelper {
public MySqliteHelper(Context context,
String name,
SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, factory, version);
}
public MySqliteHelper(Context context){
super(context,Constant.DATABASE_NAME,null,Constant.DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO 创建数据库后,对数据库的操作 // sql中Constant是用来存放一些关于数据库的常量的类 // 类型有:Integer、text文本、varchar(n)、real浮点型、blob二进制类型 String sql = "create table if not exists "+Constant.TABLE_NAME+"("+
Constant.ID+" Integer primary key ,"+
Constant.USER+" text,"+
Constant.DATE+" text,"+
Constant.TIME+" text,";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO 更改数据库版本的操作,根据新旧版本号进行表结构变更处理,当打开数据库时传入版本号与当前不同会调用此方法 //在使用中只需要调用构造函数时把版本号参数version改大即可
db.execSQL("drop table if exists " + Constant.TABLE_NAME); onCreate(db);
} @Override public void onOpen(SQLiteDatabase db) { super.onOpen(db); // TODO 每次成功打开数据库后首先被执行 } }
数据库操作的工具类(封装保证数据库安全的必要方法和操作数据库记录的方法)
在这个类中,封装保证数据库安全的必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接,并且封装对表记录进行增加、删除、修改、查询的操作方法。
获取单例对象:确保App运行时数据库只被打开一次,避免重复打开引起错误。
打开数据库连接:SQLite有锁机制,即读锁和写锁的处理;故而数据库连接也分两种,读连接可调用SQLiteOpenHelper的getReadableDatabase方法获得,写连接可调用getWritableDatabase获得。
关闭数据库连接:数据库操作完毕后,应当调用SQLiteDatabase对象的close方法关闭连接。
例如:
/**
* DbManger 操作我们数据库的工具类 我们一般写成单例模式
* 单例模式 : 在整个应用程序中 不管什么地方(类) 获得的都是同一个对象实例*/
public class DbManger {
private static final String TAG = "DbManger";
private static MySqliteHelper helper; //建立一个数据库对象
//表名
private String table_name ="p_data";
/**单例模式:不能让每一个类都能new一个,那样就不是同一个对象了,所以首先构造函数要私有化,以上下文Context作为参数
* @param ctx 本类的上下文对象
* @return
*/
private DbManger(Context ctx){
//由于数据库只需要调用一次,所以在单例中建出来
helper= new MySqliteHelper(ctx);
}
//public static 为静态类型,要调用就要有一个静态的变量,为私有的
private static DbManger instance;
//既然该类是私有的 那么别的类就不能够调用 那么就要提供一个public static(公共的 共享的)的方法
//方法名为getInstance 参数为上下文 返回值类型为这个类的实例
//要加上一个synchronized(同步的)如果同时有好多线程 同时去调用getInstance()方法 就可能会出现一些创建(new)多个BlackDao的现象
public static synchronized DbManger getInstance(Context ctx){
//如果为空 就创建一个, 如果不为空就还用原来的 这样整个应用程序中就只能获的一个实例
if(instance == null){
instance = new DbManger(ctx);
}
return instance;
}//常用方法 增删改查
/**
* 添加数据 至数据库
* @param USER 用户名 DATE 日期 TIME 时间
*/
public void addData(String USER,String DATE,String TIME){
//获得一个可写的数据库的一个引用
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values= new ContentValues();
values.put(Constant.USER, USER);
values.put(Constant.DATE, DATE);
values.put(Constant.TIME, TIME);// 参数一:表名,参数三,是插入的内容
// 参数二:只要能保存 values中是有内容的,第二个参数可以忽略
db.insert(table_name, null, values);
Log.d(TAG, "addData: 数据保存成功:"+USER+""+DATE+""+TIME);
}
/**
* 删除用户
* @param user
*/
public void deletebyuser(String user){
SQLiteDatabase db = helper.getWritableDatabase();
//表名 删除的条件
db.delete(table_name, "user = ?", new String[] {user});
}
/**
* 删除某条记录
* @param id
*/
public void deletebyid(int id){
SQLiteDatabase db = helper.getWritableDatabase();
//表名 删除的条件
db.delete(table_name, "id = ?", new String[] {Integer.valueOf(id).toString()});
}
/**
* //查找 每一个黑名单都有 号码和模式 先把号码和模式封装一个bean
* 获得所有的黑名单
* @param user 用户名
* @param pageIndex 页数
* @param pageSize 每页显示的行数
* @return
*/
//分页查询 修改 p_data是一个新定义的,用来存放一系列数据的类
public List<p_data> getAllData(String user,int pageIndex, int pageSize){//创建集合对象
List<p_data> data = new ArrayList<p_data>();
SQLiteDatabase db = helper.getReadableDatabase(); //Cursor cursor = db.query(p_data, null, null, null, null, null, null);//查询全部数据//order by _id desc 根据_id倒叙排列 使新添加的数据在查询时显示上面。根据用户名查询
//Cursor cursor = db.rawQuery("select * from p_data where user = ?"+";", new String[]{user});
//分页查询:pageSize每页显示的数目,pageIndex页数
Cursor cursor = db.rawQuery("select * from p_data where user = ? order by id desc limit "+pageSize +" offset "+((pageIndex-1)*pageSize)+";", new String[]{user});//返回的 cursor 默认是在第一行的上一行
//遍历
while(cursor.moveToNext()){// cursor.moveToNext() 向下移动一行,如果有内容,返回true
String TIME = cursor.getString(cursor.getColumnIndex("time"));
// 获得time 这列的值
String DATE = cursor.getString(cursor.getColumnIndex("date"));
// 获得date 这列的值//将查找到的数据封装到bean中
p_data bean = new p_data(user,DATE,TIME);
//封装的对象添加到集合中
data.add(bean);
}
//关闭cursor
cursor.close();
//SystemClock.sleep(1000);// 休眠2秒,查找出的数据比较多、比较耗时的情况下使用
Log.d(TAG, "getAllData: 查询数据库数据"+data );
return data;
}
/**
* 获得数据的数量
*/
public int getNumCount(String user){
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.query(table_name, new String[] {"count(*)"}, "user = ?",new String[] {user}, null, null, null, null);
cursor.moveToNext();
int count = cursor.getInt(0);// 仅查了一列,count(*) 这一刻列
cursor.close();
return count;
}
}
可被SQLite直接使用的数据结构是ContentValues类,类似于映射Map,提供put和get方法用来存取键值对。区别之处在于ContentValues的键只能是字符串”。ContentValues主要用于记录增加和更新操作,即SQLiteDatabase的insert和update方法。
对于查询操作来说,使用的是另一个游标类Cursor。调用SQLiteDatabase的query和rawQuery方法时,返回的都是Cursor对象,因此获取查询结果要根据游标的指示一条一条遍历结果集合,Cursor的常用方法:
1. 游标控制类方法,用于指定游标的状态。
- close:关闭游标。
- isClosed:判断游标是否关闭。
- isFirst:判断游标是否在开头。
- isLast:判断游标是否在末尾。
2. 游标移动类方法,把游标移动到指定位置。
- moveToFirst:移动游标到开头。
- moveToLast:移动游标到末尾。
- moveToNext:移动游标到下一条记录。
- moveToPrevious:移动游标到上一条记录。
- move:往后移动游标若干条记录。
- moveToPosition:移动游标到指定位置的记录。
3. 获取记录类方法,可获取记录的数量、类型以及取值。
getCount:获取结果记录的数量。
getInt:获取指定字段的整型值。
getFloat:获取指定字段的浮点数值。
getString:获取指定字段的字符串值。
getType:获取指定字段的字段类型。
在Activity、fragment中使用SQLite
创建数据库(onCreateView或onCreate中):
private DbManger dbManger;
dbManger = DbManger.getInstance(view.getContext());//fragment
dbManger = DbManger.getInstance(this);//activity
然后通过dbManger调用所需的操作函数即可。
补充:保存数据的类
public class p_data {
private String USER; private String DATE; private String TIME; public Nbp_data( String USER, String DATE, String TIME) { this.USER = USER; this.DATE = DATE; this.TIME = TIME; } public void setDATE(String DATE) { this.DATE = DATE; } public void setUSER(String USER) { this.USER = USER; }
public String getUSER() { return USER; } public String getDATE() { return DATE; } public String getTIME() { return TIME; } }
补充:保存常量的类
public class Constant {
public static final String DATABASE_NAME = "info.db"; // 数据库名称 public static final int DATABASE_VERSION = 1; //数据库版本 public static final String TABLE_NAME = "p_data"; //数据库表名 /** * id、user、date以下是数据库表中的字段 */ public static final String ID = "id"; //id主键 public static final String USER = "user"; //用户 public static final String DATE = "date"; //日期 public static final String TIME = "time"; //时间
}
参考:
Android Studio开发实战:从零基础到App上线 欧阳燊著 清华大学出版社
CSDN博主:「快乐的金豆」 Android 数据储存的方式之本地数据库储存 https://blog.csdn.net/lijinweii/java/article/details/73930260