目录
无标题.png
问题&解惑
问题1:为什么要用到sqlite这种本地数据库
答案:结构化的大量数据存储的最好方式就是数据库形式,而现在的app为了给用户好的体验(主要是离线模式),经常会需要本地存储一些数据,供用户使用。
问题2:sqlite的优点
答案:轻量级,使用SQLite一般只需要带上它的一个动态库,只有几百kb,且不用安装,开源。
问题3:用到数据库的例子
答案:聊天记录,新闻类未联网进去后依旧还是有内容item显示,Android系统内联系人应该也是用数据库存储。
Sqlite数据类型
以下来自网络
varchar 可以提供默认值,text 没有
varchar 会有自己设置的上限,优点:可以防止一些错误大数据, 缺点:字符串会被截断
text可变,默认最大上限为 65535
类型 |
含义 |
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 |
包含了 小时、分钟、秒。 |
SQLiteDatabase的常用方法
方法名称 |
方法表示含义 |
openOrCreateDatabase(String path,SQLiteDatabase.CursorFactory factory) |
打开或创建数据库 |
insert(String table,String nullColumnHack,ContentValues values) |
插入一条记录 |
delete(String table,String whereClause,String[] whereArgs) |
删除一条记录 |
query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy) |
查询一条记录 |
update(String table,ContentValues values,String whereClause,String[] whereArgs) |
修改记录 |
execSQL(String sql) |
执行一条SQL语句 |
close() |
关闭数据库 |
helper类
这是一个辅助类,主要功能其实是帮助我们创建数据库,
事实上创建数据库的操作,可以在操作数据库异常的情况下,去创建,但是这个工具类帮我我们完成了这件事情,并且只有第一次创建数据库的时候才会调用onCreate周期,所以如果我们有想要创建的数据库,一定要记得写在里面哦。
public class MySqliteHelper extends SQLiteOpenHelper {
private SQLiteDatabase sqLiteDatabase = null;
public MySqliteHelper(Context context, String name, int version) {
this(context, name, null, version);
}
public MySqliteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
mkTable(User.class);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
基本操作
1.打开或者创建数据库
直接创建时默认在/data/data/<包名>/databases/ 下,也可以自己自由选择位置,但是最好实在默认路径下,
helper创建
MySqliteHelper mySqliteHelper = new MySqliteHelper(this, "info.db", 1);
直接创建
db=SQLiteDatabase.openOrCreateDatabase("/data/data/com.lingdududu.db/databases/stu.db",null);
2.创建表
//创建表SQL语句
String stu_table="create table usertable(_id integer primary key autoincrement,sname text,snumber text)";
//执行SQL语句
db.execSQL(stu_table);
3.插入 insert
方法1
private void insert(SQLiteDatabase db){
//实例化常量值
ContentValues cValue = new ContentValues();
//添加用户名
cValue.put("sname","xiaoming");
//添加密码
cValue.put("snumber","01005");
//调用insert()方法插入数据
db.insert("stu_table",null,cValue);
}
方法2
private void insert(SQLiteDatabase db){
//插入数据SQL语句
String stu_sql="insert into stu_table(sname,snumber) values('xiaoming','01005')";
//执行SQL语句
db.execSQL(sql);
}
4.删除 delete
方法1
private void delete(SQLiteDatabase db) {
//删除条件
String whereClause = "id=?";
//删除条件参数
String[] whereArgs = {String.valueOf(2)};
//执行删除
db.delete("stu_table",whereClause,whereArgs);
}
方法2
private void delete(SQLiteDatabase db) {
//删除SQL语句
String sql = "delete from stu_table where _id = 6";
//执行SQL语句
db.execSQL(sql);
}
5.修改 update
方法1
private void update(SQLiteDatabase db) {
//实例化内容值 ContentValues values = new ContentValues();
//在values中添加内容
values.put("snumber","101003");
//修改条件
String whereClause = "id=?";
//修改添加参数
String[] whereArgs={String.valuesOf(1)};
//修改
db.update("usertable",values,whereClause,whereArgs);
}
方法2
private void update(SQLiteDatabase db){
//修改SQL语句
String sql = "update stu_table set snumber = 654321 where id = 1";
//执行SQL
db.execSQL(sql);
}
6.查询数据
关于query方法
参数 |
含义 |
参数table |
表名称 |
参数columns |
列名称数组 |
参数selection |
条件字句,相当于where |
参数selectionArgs |
条件字句,参数数组 |
参数groupBy |
分组列 |
参数having |
分组条件 |
参数orderBy |
排序列 |
参数limit |
分页查询限制 |
参数Cursor |
返回值,相当于结果集ResultSet |
关于cursor方法
名称 |
含义 |
getCount() |
获得总的数据项数 |
isFirst() |
判断是否第一条记录 |
isLast() |
判断是否最后一条记录 |
moveToFirst() |
移动到第一条记录 |
moveToLast() |
移动到最后一条记录 |
move(int offset) |
移动到指定记录 |
moveToNext() |
移动到下一条记录 |
moveToPrevious() |
移动到上一条记录 |
getColumnIndexOrThrow(String columnName) |
根据列名称获得列索引 |
getInt(int columnIndex) |
获得指定列索引的int类型值 |
getString(int columnIndex) |
获得指定列缩影的String类型值 |
第一种方法
private void query(SQLiteDatabase db) {
//查询获得游标
Cursor cursor = db.query ("usertable",null,null,null,null,null,null);
//判断游标是否为空
if(cursor.moveToFirst() {
//遍历游标
for(int i=0;i<cursor.getCount();i++){
cursor.move(i);
//获得ID
int id = cursor.getInt(0);
//获得用户名
String username=cursor.getString(1);
//获得密码
String password=cursor.getString(2);
//输出用户信息 System.out.println(id+":"+sname+":"+snumber);
}
}
}
第二种方法
Cursor cursor = sqLiteDatabase.rawQuery("select * from User", null);
个人封装的一点想法(只识别int与string)
思路:
1.仿照spring boot的操作,数据表基于bean对象创建,也是给予bean对象去实现一些基本操作。
2.仿照gson形式,通过对于Class 对象的识别与操作,进行基本操作,避免大段大段的增删改查代码
基本变量类
public class User {
public int a;
public String username;
public String password;
public User(int a, String username, String password){
this.a = a;
this.username = username;
this.password = password;
}
public User(){
}
}
建立表的封装
public void mkTable(Class c){
Field[] fields = c.getFields();
StringBuilder mktable = new StringBuilder("create table " +
c.getSimpleName() +
"(_id integer primary key autoincrement");
for (Field field : fields){
switch (field.getType().getName()){
case "int":
mktable.append(',' + field.getName() + " integer");
break;
case "java.lang.String":
mktable.append(',' + field.getName() + " text");
break;
}
}
mktable.append(')');
sqLiteDatabase.execSQL(mktable.toString());
}
//使用
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
mkTable(User.class);
}
辅助查询类 传入:cursor Class 输出:list
private List cursor2list(Cursor cursor, Class c){
List<Object> list = new LinkedList<>();
try {
while (cursor.moveToNext()){
Object o = c.newInstance();
Field[] fields = c.getFields();
for (int i = 1 ; i < cursor.getColumnCount(); i++){
switch (fields[i - 1].getType().getName()){
case "int":
fields[i - 1].setInt(o, cursor.getInt(i));
break;
case "java.lang.String":
fields[i - 1].set(o, cursor.getString(i));
break;
}
}
list.add(o);
User user = (User) o;
System.out.println(user.a + " " + user.username + " " + user.password);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
查询全部的封装
public List getAll(Class c){
Cursor cursor = sqLiteDatabase.rawQuery("select * from " + c.getSimpleName(), null);
return cursor2list(cursor, c);
}
//使用
mySqliteHelper.getAll(User.class);
动态查询的封装
public List query(Class c, String conditions){
String string = "SELECT * from " + c.getSimpleName() + " where ";
string += conditions;
Cursor cursor = sqLiteDatabase.rawQuery(string, null);
return cursor2list(cursor, c);
}
//使用
mySqliteHelper.query(User.class, "username = '18xxxxxxxx7' and password='wewewewe'");
清空数据表的封装
public void clear(Class c){
sqLiteDatabase.execSQL("delete from " + c.getSimpleName());
}
//使用
mySqliteHelper.clear(User.class);
条件删除的封装
public void delete(Class c, String conditions){
String string = "DELETE FROM " + c.getSimpleName() + " where ";
string += conditions;
System.out.println(string);
sqLiteDatabase.execSQL(string);
}
//使用
mySqliteHelper.delete(User.class, "username = '18xxxxxxxx7' and password='wewewewe'");
更新的封装
public void update(Class c, String results, String conditions){
String string = "UPDATE " + c.getSimpleName() + " SET " + results + " WHERE " + conditions;
sqLiteDatabase.execSQL(string);
}
//使用
mySqliteHelper.update(User.class, "username = '18xxxxxxxx7'", "username = '18xxxxxxx6'");
结语
关于数据库,个人一直觉得是一个很大的话题,很重,对我来说,很没有资格写一篇文章去认识它。
很久之前就有过要使用的必要,但是当时做的很差,代码写的很乱,当然,现在依旧不整体。
最近一直在整理Android相关的知识,数据库迟迟不能下手,整理出简单的知识点很容易,但是理解出一种最正确的用法很难。
尤其是最近思考到很多问题,内存泄漏,对象直接存储二进制文件,本地直接存储有格式的文本是否也是一种可用的方式。
思考了很多,感觉很多条路,很多种选择,但是要整理能继续下去,数据库是必须面对的,哪怕自己做的不好,没有自己的理解。
还有Android事件分发,内存泄漏,弱引用的使用,网络知识相关,事件分发感觉自己用起来还行,但是当想要说出来的时间感觉很难,没有一个核心。剩下的东西,感觉真的是一团雾水,这几种东西,想到弄清本质,确实是需要去看看书,阅读一下了,希望几天之后,我就可以有自己对于这些的认识,继续整理下去,这几天轻松整理些基本View相关吧,也写写一些自己感兴趣的小控件。
网友评论