6.3 数据储存-SQLite数据库一

标注:本文为个人学习使用,仅做自己学习参考使用,请勿转载和转发
2018-08-13: 初稿,最近不开心,不开心,参考博主coder-pig

0. 引言

  • 主要学习关于android的数据储存的第三种访问方式:Sqlite数据库,该数据库和其他的数据库不同,不需要在手机上安装数据库软件,android已经集成了这个数据库,不需要其他的数据库软件安装,完成相关配置。

1. 基本概念

1.1 Sqlite基本介绍

1)Sqlite是一个轻量级的关系型的数据库,运算速度快,占用资源少,很适合在移动设备上使用,不仅支持SQL语法,还遵循ACID(数据库事务)的原则,无需账号,使用起来非常方便!
2)前面学习了使用文件SharedPerference来保存数据,在很多情况下,文件并不一定是有效的,如付哦线程并发访问是相关的,app要处理可能变化的复杂数据结构等等,比如银行的存钱和曲线,使用前两则和会显得很无力或者繁琐,但数据库可以解决这个问题,android还提供了一个原声的sqlite
3)sqlite支持了五种数据类型,NULL、INTEGER、REAL(浮点数)、TEXT(字符串文本)和BLOB(二进制对象),虽然只是又5中,但是对于varchar、char等其他的数据类型都是可以保存的,因为Sqlite有个最大的特点,你可以各种数据类型的数据保存到任何字段中而不用管子你字段声明的数据类型是什么,拨入你可以在interger类型中的字段中存放字符串,当然除了声明为主键INTEGER PRIMARY的字段只能够储存64位整数!
4)另外sqlite在解析CREATE TABLE语句的时候,会忽略CREATE TABLE语句跟在字段后面的数据类型信息,如下面语句会忽略name字段的类型信息:CRATE TABLE person (personid integer primary key autoincrement, name varchar(20))
5)android内置的Sqlite是Sqlite3版本的

1.2 几个相关的类
  • 数据库使用的时候用到的三个类
  1. SQLiteOpenHelper:抽象类,我们通过集成该类,然后重写数据库创建以及更新的方法,我们还可以通过该类的对象获得数据库实例,或者关闭数据库!
  2. SQLiteDatabase:数据库访问类,我们可以通过该类的对象来对数据库做一些增删改查的操作
  3. Cursor: 游标,有点类似于JDBC里的resultset,结果集!可以简单理解为指向数据库中的某一个记录的指针!

2. 使用SQLiteOpenHelper类创建数据库与版本管理

  • 对于设计数据库的app,我们不可能手动地去给他创建数据库文件,所以需要在第一次启动app的时候就创建好数据库表;
  • 而当我们的应用进行升级需要修改数据库表的结构时,这个时候就需要对数据库表进行更新了;对于这两个操作,android给外面提供另外SQLiteOpenHelper的两个方法,onCreate()与onUpgrade()来实现

方法解析:

  • onCreate(datebase): 首次使用软件时生成数据库表
  • onUpgrade(database, oldVersion, newVersion): 在数据库的版本发生变化时会被调用,一般是软件升级时才需要改变版本号,而数据库的版本是由程序员控制的,假设数据库的现在的版本是1,由于业务的变更,修改了数据库表结构,这个时候就需要升级软件,升级软件时希望更新用户手机里的数据库的表的结构,为了实现这一目的,可以吧原来的数据库斑斑设置为2或者其他与旧版本号不同的数字即可!

代码示例:

public class MyDBOpenHelper extends SQLiteOpenHelper {
    public MyDBOpenHelper(Context context, String name, CursorFactory factory,
            int version) {super(context, "my.db", null, 1); }
    @Override
    //数据库第一次创建时被调用
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE person(personid INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20))");
        
    }
    //软件版本号发生改变时调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("ALTER TABLE person ADD phone VARCHAR(12) NULL");
    }
}

代码解析:

  • 上述代码第一次启动应用,我们会创建这个my.db的文件,并且会执行onCreate()里的方法, 创建一个Person的表,他又两个字段,主键personId和name字段;接着如我我们修改db的版本 号,那么下次启动就会调用onUpgrade()里的方法,往表中再插入一个字段!另外这里是插入 一个字段,所以数据不会丢失,如果是重建表的话,表中的数据会全部丢失,下一节我们会 来教大家如何解决这个问题!

流程小结:

  1. 自定义一个类集成SQLiteOpenHelper类
  2. 在该类的构造方法的super中设置好要创建的数据库名、版本号
  3. 重写onCreate()方法创建表结构
  4. 重写onUpgrade()方法定义版本号发生改变后执行的操作

3. 如何查看我们生成的db文件

  • 当我们调用上面的MyDbOpenHelper的对象的getWriteableDatabase()就会在下述目录下创建我们的db数据库文件:



    我们发现数据库又两个,前者是我们创建的数据库,而后者是为了能让数据库支持事务而产生的临时日志文件,一般的大小都是0字节!而在File Explorer里我们确实是打不开文件的,连txt文件都打不开,何况是.db,所以下面有两种选择方式

  1. 先导出来,然后用SQLite的图形化工具查看
  2. 配置adb环境变量后,通过adb shell 来查看

其中adb的查看方式,当前的设备最好可以root,这样查看database比较方便

// 第一步
adb shell
// 第二步, root之后可以对文件夹进行联想
su
// 第三步
cd data/data/包名/databases
// 第四步,打开数据库文件
sqlite3 my.db
// 第五步,查看数据库中的表
.table
// 然后就可以对数据库中的表格进行操作了

4. 使用Android提供的API操作SQLite

  • android还提供了一些关于数据库的相关语法,也就是API相关方法的使用
    代码示例

运行效果图

实现代码

布局过于简单,就四个Button,就不贴了,直接贴MainActivity.java的代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Context mContext;
    private Button btn_insert;
    private Button btn_query;
    private Button btn_update;
    private Button btn_delete;
    private SQLiteDatabase db;
    private MyDBOpenHelper myDBHelper;
    private StringBuilder sb;
    private int i = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        myDBHelper = new MyDBOpenHelper(mContext, "my.db", null, 1);
        bindViews();
    }

    private void bindViews() {
        btn_insert = (Button) findViewById(R.id.btn_insert);
        btn_query = (Button) findViewById(R.id.btn_query);
        btn_update = (Button) findViewById(R.id.btn_update);
        btn_delete = (Button) findViewById(R.id.btn_delete);

        btn_query.setOnClickListener(this);
        btn_insert.setOnClickListener(this);
        btn_update.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        db = myDBHelper.getWritableDatabase();
        switch (v.getId()) {
            case R.id.btn_insert:
                ContentValues values1 = new ContentValues();
                values1.put("name", "呵呵~" + i);
                i++;
                //参数依次是:表名,强行插入null值得数据列的列名,一行记录的数据
                db.insert("person", null, values1);
                Toast.makeText(mContext, "插入完毕~", Toast.LENGTH_SHORT).show();
                break;
            case R.id.btn_query:
                sb = new StringBuilder();
                //参数依次是:表名,列名,where约束条件,where中占位符提供具体的值,指定group by的列,进一步约束
                //指定查询结果的排序方式
                Cursor cursor = db.query("person", null, null, null, null, null, null);
                if (cursor.moveToFirst()) {
                    do {
                        int pid = cursor.getInt(cursor.getColumnIndex("personid"));
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        sb.append("id:" + pid + ":" + name + "\n");
                    } while (cursor.moveToNext());
                }
                cursor.close();
                Toast.makeText(mContext, sb.toString(), Toast.LENGTH_SHORT).show();
                break;
            case R.id.btn_update:
                ContentValues values2 = new ContentValues();
                values2.put("name", "嘻嘻~");
                //参数依次是表名,修改后的值,where条件,以及约束,如果不指定三四两个参数,会更改所有行
                db.update("person", values2, "name = ?", new String[]{"呵呵~2"});
                break;
            case R.id.btn_delete:
                //参数依次是表名,以及where条件与约束
                db.delete("person", "personid = ?", new String[]{"3"});
                break;
        }
    }
}

5.使用SQL语句操作数据库

  • 当然,你可可能学习过SQL语句,但不想使用android的这些API,也可以直接使用SQLiteDatabase给我们提供的相关方法:
  • execSQL(SQL, Object[]): 使用带占位符的SQL语句,这个是执行修改数据库内容的sql语句用的
  • rawQuery(SQL, Object[]): 使用带占位符的SQL查询操作,另外前面忘了介绍下Cursor这个东西以及相关属性,这里补充下:
    Cursor对象有点类似于JDBC俩面的resultSet,结果集!使用差不多,提供一下方法移动查询结果的记录指针;
  • move(offset): 指定向上或者向下移动的行数,整数表示向下移动,负数表示向上移动!
  • moveToFirst(): 指针移动到第一行,成功返回true,也说明有数据
  • moveToLast(): 指针移动到最后一样,成功返回true;
  • moveToNext(): 指针移动到下一行,成功返回true,表明还有元素!
  • moveToPrevious(): 移动到上一条记录
  • getCount(): 获得总得数据条数
  • isFirst(): 是否为第一条记录
  • isLast(): 是否为最后一项
  • moveToPosition(int): 移动到指定行
  1. 插入数据
public void save(Person p)
{
    SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    db.execSQL("INSERT INTO person(name,phone) values(?,?)",
                new String[]{p.getName(),p.getPhone()});
}
  1. 删除数据
public void delete(Integer id)
{
    SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    db.execSQL("DELETE FROM person WHERE personid = ?",
                new String[]{id});
}
  1. 修改数据
public void update(Person p)
{
    SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
    db.execSQL("UPDATE person SET name = ?,phone = ? WHERE personid = ?",
        new String[]{p.getName(),p.getPhone(),p.getId()});
}
  1. 查询数据
public Person find(Integer id)
{
    SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
    Cursor cursor =  db.rawQuery("SELECT * FROM person WHERE personid = ?",
            new String[]{id.toString()});
    //存在数据才返回true
    if(cursor.moveToFirst())
    {
        int personid = cursor.getInt(cursor.getColumnIndex("personid"));
        String name = cursor.getString(cursor.getColumnIndex("name"));
        String phone = cursor.getString(cursor.getColumnIndex("phone"));
        return new Person(personid,name,phone);
    }
    cursor.close();
    return null;
}
  1. 数据分页
public List<Person> getScrollData(int offset,int maxResult)
{
    List<Person> person = new ArrayList<Person>();
    SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
    Cursor cursor =  db.rawQuery("SELECT * FROM person ORDER BY personid ASC LIMIT= ?,?",
        new String[]{String.valueOf(offset),String.valueOf(maxResult)});
    while(cursor.moveToNext())
    {
        int personid = cursor.getInt(cursor.getColumnIndex("personid"));
        String name = cursor.getString(cursor.getColumnIndex("name"));
        String phone = cursor.getString(cursor.getColumnIndex("phone"));
        person.add(new Person(personid,name,phone)) ;
    }
    cursor.close();
    return person;
}
  1. 查询记录数
public long getCount()
{
    SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
    Cursor cursor =  db.rawQuery("SELECT COUNT (*) FROM person",null);
    cursor.moveToFirst();
    long result = cursor.getLong(0);
    cursor.close();
    return result;      
}   
  • 除了上面获取条数的方法外还可以使用cursor.getCount()方法获得数据的条数, 但是SQL语句要改改!比如SELECT * FROM person;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 转 # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    吕品㗊阅读 9,617评论 0 44
  • 请问如何在屏幕左侧显示目录索引?答:视图——显示——勾选导航窗格 请问如何调出纸张最上方的标尺工具答:视图——显示...
    默写年华Antifragile阅读 103评论 0 0
  • 放松 髂腰肌放松 翻书,画圆,靠墙手上举 动作一,器械推胸 收腹,沉肩,胸挺出来一点,大臂略低于肩膀,小臂垂直向前...
    摇月亮阅读 265评论 0 0
  • 喧嚣的城市里,忙碌了一天的你,过的 还好吗?是不是很久都没有认真的去读过一篇文章了? . 如果你活到88岁,...
    悦落阅读 225评论 0 1