Android 数据库知识回顾

加油

一、前言
二、效果预览
三、数据库与框架的基础使用
(1)第一道:原生数据库
(2)第二道:LitePal框架
(3)第三道:GreenDao框架
四、总结
五、Demo地址
六、内容推荐


一、前言

  • 1.菜鸟作者为什么要写这篇呢?——随GitHub上Android数据库框架日新月异,我们应该如何选择一个适合我们的数据库。

当然一个好的数据库框架不仅可以提高我们的开发效率外,还可以提高项目的性能。

  • 2.为什么GitHub上有那么多的开源框架?——不言而喻,应该是原生的开发效率与性能上没有开源来的优秀(哈哈 个人观点)

  • 3.这篇主要写什么?——主要回顾数据库的用法。对比一些开源数据库的使用方法(最基础的使用方式)。因性能弄起来比较麻烦,而且相关博客也很多大家自己百度即可。

二、效果预览

随便给自己写的一个简单Demo,看完UI有没有一种想捏死作者的冲动...

这里只涉及简单的存储操作,复杂的多对多关系这里没有。不瞒大家,想深入理解数据库的同学可以止步了,这里算基础回顾

​三、数据库与框架的基础使用

什么是数据库?什么是SQLite?...就解释到这里。开始上菜了

先说明一下数据库使用基础步骤我把他们分为:1.创建数据库 2.创建表 3.数据库操作(增删改查) 4.更新数据库


(1)第一道:原生数据库

1.首先我们需要创建一个属于自己的数据库管理类来继承SQLiteOpenHelper数据库帮助类实现数据库的创建与更新。

public class MySQLiteHelper extends SQLiteOpenHelper {
    private static final String TAG = "MySQLiteHelper";
    //数据库建表语句
    public static final String sql = "create table SqliteDemo (id integer primary key autoincrement, name text(4),address text(5))";
    public static final String sql1 = "create table test1 (id integer primary key autoincrement, name text(4),address text(5))";
    public MySQLiteHelper(@Nullable Context context, @Nullable String name,  @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);//创建数据库调用方法
    }
    /**
     * 第一次创建数据库时调用 在这方法里面可以进行建表
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(TAG, "onCreate: " );
        db.execSQL(sql);
    }
    /**
     * 版本更新的时候调用
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.i(TAG, "onUpgrade: " );
        switch (oldVersion){
            case 1:
                db.execSQL(sql1);
                break;
        }
    }
}
创建一个数据库:名称Blcs  版本号 1
MySQLiteHelper blcs = new MySQLiteHelper(context, "Blcs", null, 1);

2.基本操作

//(1)打开数据库并进行写入操作
SQLiteDatabase db= blcs.getWritableDatabase();

注:Android提供了两种操作方式:1.执行数据库语句 2.调用封装好的Api方法

增:插入一条语句

//方式一:
String insert = new StringBuilder()
                    .append("insert into SqliteDemo (name,address) values ('")
                    .append(name).append("','").append(address).append("')")
                    .toString();

//或是
//String insert = "insert into SqlteDemo (name,address) values ('"+name+"','"+address+"')";
db.execSQL(insert);

//方式二:
ContentValues contentValues = new ContentValues();
            contentValues.put("name", name);
            contentValues.put("address", address);
            db.insert("SqliteDemo", null, contentValues);

删:删除一条语句

//方式一
String delete = new StringBuilder().append("delete from SqliteDemo where name = '").append(Name).append("' or address = '").append(Address).append("'").toString();

db.execSQL(delete);

//方式二
db.delete("SqliteDemo", "name = ? or address = ?", new String[]{Name, Address});

改:修改一条语句

//根据指定ID修改name 与 address
//方式一
String update = new StringBuilder().append("update SqliteDemo set name = '").append(Name)
                    .append("' , address = '").append(Address)
                    .append("' where id = ").append(Id)
                    .toString();
db.execSQL(update);
//方式二
ContentValues contentValues = new ContentValues();
            contentValues.put("name", Name);
            contentValues.put("address", Address);
db.update("SqliteDemo", contentValues, "id = ?", new String[]{String.valueOf(Id)});

查:查询语句

//方式一
//查询整张表
String query = "select * from SqliteDemo";
//获取表中存在这个地址的数据
String query = new StringBuilder().append("select * from SqliteDemo where address = '")
                    .append(Address).append("'").toString();
//获取表中存在这个地址和姓名的数据
String query = new StringBuilder().append("select * from SqliteDemo where name = '")
                    .append(Name).append("' and address = '").append(Address).append("'").toString();

//执行数据库语句
Cursor cursor = db.rawQuery(query, null);

//方式二
//查询整张表
String selection = null;
String str = null;
//获取表中存在这个地址的数据
String selection = "address = ?";
String str = new String[]{Address};
//获取表中存在这个地址和姓名的数据
String selection = "name = ? and address = ?";
String str = new String[]{Name, Address};
//执行相应的Api
Cursor cursor = db.query("SqliteDemo", null, selection, str, null, null, null);

还没结束 ,当我们拿到Cursor对象后还要进行最后的数据获取

ArrayList<SqliteDemo> dats = new ArrayList<>();

while (cursor.moveToNext()) {
            SqliteDemo sqliteDemo = new SqliteDemo();
            long id = cursor.getLong(cursor.getColumnIndex("id"));
            String name = cursor.getString(cursor.getColumnIndex("name"));
            String address = cursor.getString(cursor.getColumnIndex("address"));
            sqliteDemo.setId(id);
            sqliteDemo.setName(name);
            sqliteDemo.setAddress(address);
            dats.add(sqliteDemo);
        }
return dats;

3.数据库更新

当我们数据库有变化,并且要发布新版本的时候别忘了升级一下数据库版本号。并且还需要在MySQLiteHelper 的 onUpgrade方法中进行处理。

(2)第二道:LitePal框架

简单描述:这是郭神早期对原生数据库封装的一个数据库框架

优点嘛:......用了就知道了哈

GitHub:https://github.com/LitePalFramework/LitePal

guolin:https://blog.csdn.net/sinyu890807/column/info/android-database-pro

1.基本配置

1.添加依赖
dependencies {
    implementation 'org.litepal.android:java:3.0.0'
}
or
dependencies {
    implementation 'org.litepal.android:kotlin:3.0.0'
}

2,创建数据库:在assets 添加litepal.xml //还有另外一种创建数据库的方式 具体可以到GitHub或博客上了解

<?xml version="1.0" encoding="utf-8"?>
<litepal>
      //数据库昵称
    <dbname value="Blcs1" />
    //版本号
    <version value="1" />
    //数据库表
    <list>
        <mapping class="blcs.lwb.utils.bean.SqliteDemo" />
    </list>

</litepal>

3.初始化 AndroidManifest.xml

<manifest>
    <application
        android:name="com.example.MyOwnApplication"
        ...
    >
        ...
    </application>
</manifest>

public class MyOwnApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        LitePal.initialize(this);
    }
    ...
}

4.数据库的操作

这里对象需要继承LitePalSupport,调用里面的api执行相应的数据库处理,可以给属性相应的注解,相对简单,这里就不贴了。一切从简

public class SqliteDemo extends LitePalSupport {
    private Long id;
    private String name;
    private String address;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

//创建要保存的对象,调用save方法直接保存  因为继承了LitePalSupport 里面提供了许多保存的APi ,可以根据需求选择合适的方法
SqliteDemo sqliteDemo = new SqliteDemo();
            sqliteDemo.setName(name);
            sqliteDemo.setAddress(address);
            sqliteDemo.save();
//例:异步保存:开个线程进行保存,处理完监听回调是否保存成功
sqliteDemo.saveAsync().listen(new SaveCallback() {
                @Override
                public void onFinish(boolean success) {
                    List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
                    mAdapter.setNewData(all);
                }
            });

//LitePal.delete();
//LitePal.deleteAll();
//LitePal.deleteAsync()
LitePal.deleteAllAsync(SqliteDemo.class,"name = ? or address = ?",Name,Address).listen(new UpdateOrDeleteCallback() {
                    @Override
                    public void onFinish(int rowsAffected) {
                        List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
                        mAdapter.setNewData(all);
                    }
                });

//LitePal.update();
//LitePal.updateAll();
//LitePal.updateAsync();
//LitePal.updateAllAsync();
 ContentValues contentValues = new ContentValues();
            contentValues.put("name", Name);
            contentValues.put("address", Address);
            LitePal.updateAsync(SqliteDemo.class,contentValues,Id).listen(new UpdateOrDeleteCallback() {
                @Override
                public void onFinish(int rowsAffected) {
                    List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);
                    mAdapter.setNewData(all);
                }
            });

//查询全部 
List<SqliteDemo> all = LitePal.findAll(SqliteDemo.class);

//获取名字和地址对应的数据
String selection = "name = ? and address = ?";
List<SqliteDemo> all = LitePal.where(selection, Name, Address).find(SqliteDemo.class);

//查询里面隐藏着许多有用的Api,有兴趣的同学可以继续深究.这里不解释。否则导致篇幅太长

5.数据库的更新

使用这个框架最大的优点是,我们已经不需要自己去写数据库的更新方法了。只需要提高一下版本号即可,剩下的框架已经都帮我们处理好了。

6.混淆

-keep class org.litepal.** {
    *;
}
-keep class * extends org.litepal.crud.DataSupport {
    *;
}

-keep class * extends org.litepal.crud.LitePalSupport {
    *;
}

(3)第三道:GreenDao框架

greendao :https://github.com/greenrobot/greenDAO

介绍:http://greenrobot.org/greendao/documentation/

参考博客:https://www.jianshu.com/p/53083f782ea2

简单描述:目前GitHub上最热门的数据库框架之一,相对其他数据库框架star也是最多的一个。

1.基本配置

// In your root build.gradle file:
buildscript {
    repositories {
        jcenter()
        mavenCentral() // add repository
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.1'
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // add plugin
    }
}
// In your app projects build.gradle file:
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao' // apply plugin

dependencies {
    implementation 'org.greenrobot:greendao:3.2.2' // add library
}

混淆

-keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties
-dontwarn org.greenrobot.greendao.database.**
-dontwarn rx.**
### greenDAO 2
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao {
public static java.lang.String TABLENAME;
}
-keep class **$Properties

配置数据库信息:

    greendao {
        schemaVersion 1 //数据库版本号
        // 设置DaoMaster、DaoSession、Dao 包名
        daoPackage 'blcs.lwb.utils.greendao'
        targetGenDir 'src/main/java'
    }

2.创建持久化对象

主要:给持久化对象添加@Entity 注解 ,然后Build -- Make Project 重新编译一下 会自动生成DaoMaster、DaoSession、GreenDaoDao

@Entity
public class GreenDao {
    @Id
    private Long id;
    private String name;
    private String address;
    @Generated(hash = 534050545)
    public GreenDao(Long id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }
    @Generated(hash = 766040118)
    public GreenDao() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return this.address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

3.创建数据库

public class MyApplication extends BaseApplication {
     @Override
    public void onCreate() {
        super.onCreate();
        //GreenDao
        initGreenDao();
    }

    private void initGreenDao() {
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "Blcs2.db");
        SQLiteDatabase db = helper.getWritableDatabase();
        DaoMaster daoMaster = new DaoMaster(db);
        daoSession = daoMaster.newSession();
    }
    private static DaoSession daoSession;
    public static DaoSession getDaoSession() {
        return daoSession;
    }
}

4.基本操作

//获取GreenDao数据库操作对象
 DaoSession daoSession = MyApplication.getDaoSession();
//获取指定的操作对象
GreenDaoDao greenDaoDao = daoSession.getGreenDaoDao();

  GreenDao demo = new GreenDao();
            demo.setName(name);
            demo.setAddress(address);
            daoSession.insert(demo);
//或
            greenDaoDao.insert(demo);

//查出需要删除的对象 ,然后进行删除
daoSession.delete(bean);
//或
greenDaoDao.delete(bean);

//根据ID查找某个对象进行更改
List<GreenDao> demos = daoSession.queryRaw(GreenDao.class, "where _id = ?", "" + Id);
            GreenDao demo = demos.get(0);
            demo.setName(Name);
            demo.setAddress(Address);
            daoSession.update(demo);
//或
            greenDaoDao.update(demo);

//查询全部
List<GreenDao> greenDaoBeans = daoSession.loadAll(GreenDao.class);
//根据条件查询
List<GreenDao> greenDaoBeans = daoSession.queryRaw(GreenDao.class, "where NAME = ? and ADDRESS = ?", Name,Address);

大部分daoSession操作方法 ,greenDaoDao也会有

4.数据库更新

GreenDao的OpenHelper下有个 onUpgrade(Database db, int oldVersion, int newVersion)方法,当设置的数据库版本改变时,在数据库初始化的时候就会回调到这个方法,我们可以通过继承OpenHelper重写onUpgrade方法来实现数据库更新操作。

注:如果没有重写更新方法只升级版本号的话:会导致数据丢失。


四、总结

使用原生数据库容易出现语句错误,使用繁琐,提供的Api也比较少。相对于原生数据库,我们可以采用郭神的LitePal框架,主要是基于原生数据库封装的。提供的Api比较丰富,而且使用也方便。

但是从性能方面上来看可能没有GreenDdao框架高,具体可以查看GreenDdao文档。里面有进行详细的描述。

当然还有许多不错的数据框架:DBFlowActiveAndroidORMLiteRealmAfinal ....

最后在推荐一个性能更好的数据库框架objectbox

官网:https://objectbox.io/

GitHub:https://github.com/objectbox/objectbox-java

为什么菜鸟作者不写呢?——还在学习中..


注:AS中并不能直接打开.db文件 所以一般要查看数据库文件需要借助工具

不过那样会很麻烦,需要先找到文件导出后再工具中查看。

所以这里可以引用Android-Debug-Database,在不借助工具的情况下查看数据库。

五、Demo地址

Github:https://github.com/DayorNight/BLCS

码云:https://gitee.com/blcs/BLCS

apk下载体验地址:https://www.pgyer.com/BLCS

六、内容推荐

CSDN: 《Android 数据库知识回顾》
《Android 下载安装应用APK封装(适配8.0)》
《Android Notification通知简单封装(适配8.0)​​​​​​​》​​​​​​​
《Android 仿RxDialog自定义DialogFragment》
《Android 获取App应用、缓存、数据等大小适配8.0(仿微信存储空间)》

如果你觉得写的不错或者对您有所帮助的话

不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈

看在花了这么多时间整理写成文章分享给大家的份上,记得手下留情哈

您的每个举动都是对我莫大的支持

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279

推荐阅读更多精彩内容