06数据存储-SQlite

前面所学的文件存储和SharedPreferences存储只适用用于保存一些见到那的数据,当需要存储大量复杂的关系型数据库的时候,这两种存储方式就不行了,下面介绍SQLite数据库

创建数据库

Android中提供了一个SQLiteOpenHelper帮助类,借助个类就可以非常简单的对数据库进行操作

  1. 要知道SQLiteOpenHelper是一个抽象类,要使用它就必须自己定义一个类继承它,必须还的重写两个方法,onCreate()和onUpgtade(),然后分别在这两个方法中去实现创建,升级数据库的逻辑
  2. SQLiteOpenHelper中还有两个非常重要的实例方法,相同的是都可以创建或者打开一个现有的数据库,如果数据库已经存在的就直接打开,没有存在就新建一个数据路,并返回一个可以对数据库进行读写操作的对象,不同的是当数据库不可写入的时候(磁盘空间满)
    • getReadableDatabese()返回的对象将以只读的方式去打开数据库
    • getWritableDatabase()方法则会出现异常
  3. SQLiteOpenHelper中有两个构造方法可以重写,一般使用参数少的那个构造函数,这个构造方法接收四个参数,
    • 第一个参数是Context,必须要有它才能对数据库进行操作,
    • 第二个参数数据库名,创建数据库时使用的就是这个参数指定名称
    • 第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般传入的unll
    • 第四个参数表示当前的数据库版本号,可以用于对数据库进行升级操作
      构建SQLiteOpenHelper的实例后,在调用getReadableDatabese()或者getWritableDatabase()方法就可以创建数据库了,数据库的文件会放在/data/data/<package name>/databases/目录下,此时重写的onCreate()方法就会得到执行,在这去处理一些创建表的逻辑
  4. 在代码中实现,在MyDatabaseHelper类中继承SQLiteOpenHelper
public class MyDatabaseHelper extends SQLiteOpenHelper {

    // 要创建的数据库
    public static final String CREATE_BOOK = "create table Book(" +
            "id integer primary key autoincrement," +
            "author text," +
            "price real," +
            "pages integer," +
            "name text)";

    private Context mContent;
    // 重写构造方法,接收四个参数
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContent = context;
    }

    // 创建数据库
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        // 调用方法
        sqLiteDatabase.execSQL(CREATE_BOOK);
        Toast.makeText(mContent,"创建成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    }
}


  • 这里把建表的语句定义成一个字符串,然后onCreate()方法中通过execSQL()创建表
  1. 修改activity_main.xml中的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <Button
        android:id="@+id/carete_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database"/>

</LinearLayout>

  • 点击这个按钮的时候就会创建一个数据库
  1. 在MainActivity中

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取到这个类的对象
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,1);
        Button createDatabese = (Button)findViewById(R.id.carete_database);
        createDatabese.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 点击按钮的时候就创建这个数据库
                dbHelper.getWritableDatabase();
            }
        });

    }
}

  • 获取到自定类的对象,数据库名为BookStore.db,版本为1,第一次点击的时候,先创建数据库,再创建表


    数据库创建成功.png
  • 问题来了,该怎么查看呢,这个时候我们使用adb shell进行查看,adb在sdk/platform-tools目录下,把它添加到path环境中


    环境配置.png
  • 环境配置好后,打开命令行,输入adb shell进入(我是用夜神进入的)


    进入.png
  • 然后使用cd命令进入到/data/data/项目名/databases/目录下,然后使用ls命令查看到该目录中的文件

  • 这个时候,这个目录下出现了两个数据库,一个就是创建的BookStore.db,另一个就是一个临时的日志文件,借助sqlite命令打开数据库,输入sqlite3,然后后面加上数据库名

  • 这个时候已经打开了BookStore.db数据库,现在就可以对这个数据库进行管理了,查看当前的数据库中有那些表,输入.table命令

  • 此时数据库中会有两个表,一个android_metadata表是每个数据库中都自动生成的,另一个就是我们自己创建的,可以通过.schema命令来查看他们的建表语句,.exit退出上一层


    查看.png

升级数据库

这个时候你会发现,在MyDatabaseHelper中还有一个空方法,就是onUpgrade()方法用于对数据库进行升级,

  1. 这个时候,如果想要添加一个Category表用于记录图书的分类该怎么办?

public class MyDatabaseHelper extends SQLiteOpenHelper {

    // 要创建的数据库
    public static final String CREATE_BOOK = "create table Book(" +
            "id integer primary key autoincrement," +
            "author text," +
            "price real," +
            "pages integer," +
            "name text)";
    // 新建的数据表
    public static final String CREATE_CATEGORY = "create table Category(" +
            "id integer primary key autoincrement," +
            "category_name text," +
            "category_code integer)";

    private Context mContent;
    // 重写构造方法,接收四个参数
    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContent = context;
    }

    // 创建数据库
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        // 调用方法
        sqLiteDatabase.execSQL(CREATE_BOOK);
        // 再创建一个表
        sqLiteDatabase.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContent,"创建成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    }
}

  • 这个时候又通过字符串的方法新建了一个表,运行程序,这个时候你会发现并没有弹创建成功,这是为什么呢?
  • 因为数据库已经存在了,而onCreate()方法就不会得到执行了,所有第二个就会创建不成功
  1. 这个时候就该使用onUpgrade()方法了,利用它进行数据库的升级,在MyDatabaseHelper中

public class MyDatabaseHelper extends SQLiteOpenHelper {

   //和上面一样
    ...
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        sqLiteDatabase.execSQL("drop table if exists Book");
        sqLiteDatabase.execSQL("drop table if exists Category");
        onCreate(sqLiteDatabase);
    }
}

  • 在这个方法中,执行了两条DROP语句,如果发现数据库中存在Book表和Catagory表,就把这两个表删除掉,再调用onCreate()方法重新创建
  • 这里先把已经存在的表删除掉,因为如果创建的时候发现这个表存在的话,就会报错
  1. 接下来就是怎么让这个方法执行,还记得在SQLiteOpenHelper的构造方法中接收的第四个参数,它代表当前的版本号,之前传入的是1,此时传入一个比1大的数字,就可以让这个onUpgrade()方法得到执行了

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取到这个类的对象,此时把版本号改成2
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        Button createDatabese = (Button)findViewById(R.id.carete_database);
        createDatabese.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 点击按钮的时候就创建这个数据库
                dbHelper.getWritableDatabase();
            }
        });

    }
}

  • 版本号指定为2,表示对数据库进行升级,运行程序,这个时候还是使用上面的命令进行查看


    2018-03-22_19-53-45.png

添加数据

对数据表中的数据操作无非有四种,增删查改,和sql一样,前面说getReadableDatabese()或者getWritableDatabase()方法可以用于创建和升级数据库,但是这两个方法都会返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行增删查改

  1. 增,使用insert()方法,它接收3个参数,第一个参数是表名,第二个参数用于在末指定添加数据的情况下给某些可为空的列自动赋值NULl,一般不用,直接传入null,第三个参数是ContentValues对象,它提供了一些put()方法重载,用于向ContentValues中添加数据,只需将表中的每个列名以及相应的待添加数据传入即可
    修改activity.xml代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:text="Add data"/>
    
</LinearLayout>

  • 新增一个按钮,用于添加数据
    在MainActivity中修改代码

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      
        ......
        
        Button addData = (Button)findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name","The Da Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages","454");
                values.put("price","17.89");
                // 插入进去
                db.insert("Book",null,values);
                values.clear();
                // 开始组装第二条数据
                values.put("name","The Lost Symbol");
                values.put("author","Dan Brown");
                values.put("pages","890");
                values.put("price","175.89");
                db.insert("Book",null,values);
            }
        });

    }
}


  • 添加点击事件,先获取SQLiteDatabase对象,然后使用ContentValues来对进行添加的数据进行组装,调用insert()方法把数据插入到表中,这里添加了两条数据
  • 运行程序,点击按钮,进入到数据库中,最后有;号


    点击四次后的效果.png

更新数据

会添加后,还有对数据进行更新,使用updata()方法,这个方法接收四个参数,第一个还是表名,第二个是ContentValues对象,把要更新的数据组装进去,第三、第四参数用于约束更新莫一行或者某几行的数据,不指定的话就是默认更新所有的

  1. 还是在上面的基础上进行修改
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    ...
    <Button
        android:id="@+id/updata_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:text="Updata data"/>
    
</LinearLayout>

  • 给这个按钮添加绑定事件用于更改数据
  1. 在MainActivity中


public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...

        Button updataData = (Button)findViewById(R.id.updata_data);
        updataData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",100);
                db.update("Book",values,"name = ?",new String[]{"The Da Vinci Code"});
            }
        });

    }
}


  • 这里调用了updata()方法执行具体的操作,在第三个,第四个参数来指定更新的具体行数,第三个参数是对应的where部分,表示更新所有的name等于?的,而?是一个占位符,通过第四个参数提供的字符串数组作为第三个参数的占位符指定相应的内容,就是把名字等于The Da Vinci Code的价格改成100
  • 运行程序,点击按钮
  • 输入命令进行查看


    2018-03-22_21-16-22.png

    可以看到名字为The Da Vinci Code的价格都是100

删除数据

使用的是delete()方法,第一个参数还是表名,第二个、第三个参数用于约束删除某一行或者莫几行的数据,不指定的话默认删除所有的行

  1. 修改acticity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    ...
    <Button
        android:id="@+id/dalete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete data"/>

</LinearLayout>


  1. 在MainActivity中


public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ...
        
        // 删除数据
        Button deleteData = (Button)findViewById(R.id.dalete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book","price = ?",new String[]{"100"});
            }
        });
    }
}

  • 这里只当price等于100的删除掉
  • 运行程序,点击删除按钮


    2018-03-22_21-24-40.png
  • 查看数据库中的数据


    删除后的数据.png

查询数据

这个是最复杂的一个操作,使用的是query()方法,最短的一个方法重载也要传入7个参数、


参数.png

但是多数的情况下只需要传入几个参数就可以了,调用query()方法后会返回一个Cursor对象,查询到的所有数据都将从这个对象中取出

  1. 在activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:id="@+id/carete_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database"/>

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add data"/>

    <Button
        android:id="@+id/updata_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Updata data"/>

    <Button
        android:id="@+id/dalete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete data"/>

    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query data"/>

</LinearLayout>

  • 添加按钮用于查询数据,
  1. 修改MainActivity中的代码

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 获取到这个类的对象 数据库建立
        dbHelper = new MyDatabaseHelper(this,"BookStore.db",null,2);
        final Button createDatabese = (Button)findViewById(R.id.carete_database);
        createDatabese.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 点击按钮的时候就创建这个数据库
                dbHelper.getWritableDatabase();
            }
        });

        // 添加一条数据
        Button addData = (Button)findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name","The Da Vinci Code");
                values.put("author","Dan Brown");
                values.put("pages","454");
                values.put("price","17.89");
                // 插入进去
                db.insert("Book",null,values);
                values.clear();
                // 开始组装第二条数据
                values.put("name","The Lost Symbol");
                values.put("author","Dan Brown");
                values.put("pages","890");
                values.put("price","175.89");
                db.insert("Book",null,values);
                Toast.makeText(MainActivity.this,"aaaaaa",Toast.LENGTH_SHORT).show();
            }
        });

        // 更新一条数据
        Button updataData = (Button)findViewById(R.id.updata_data);
        updataData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price",100);
                db.update("Book",values,"name = ?",new String[]{"The Da Vinci Code"});
            }
        });

        // 删除数据
        final Button deleteData = (Button)findViewById(R.id.dalete_data);
        deleteData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book","price = ?",new String[]{"100"});
            }
        });


        // 查询数据
        Button queryButton = (Button)findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查询Book表中的所有数据
                Cursor cursor = db.query("Book",null,null,null,null,null,null);
                if(cursor.moveToFirst()){
                    do{
                        // 遍历Cursor对象,取出数据并打印
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("Mainactivity","book name is "+name);
                        Log.d("Mainactivity","book author is "+author);
                        Log.d("Mainactivity","book pages is "+pages);
                        Log.d("Mainactivity","book price is "+price);
                    }while (cursor.moveToNext());
                }
                // 最后记着关闭
                cursor.close();
            }
        });

    }
}

  • 运行程序,点击按钮,可以看到
  • 2018-03-22_21-53-38.png
  • 当然了,这只是一个最简单的例子

直接使用SQL操作数据库,

SQL操作数据库.png

除了查询使用的是rawQuery()方法,其他的操作都是调用execSQl()方法,操作的结果和上面演示的一行,对SQL熟练的话,可以使用这种操作,更加的方便

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,944评论 6 13
  • 周末是睡懒觉的不二选择,睡到自然醒是多么地快乐。周末就是这样的美好,如果所有的日子都是这样的让人踏实该是多么的好...
    whb3246阅读 202评论 0 0
  • 在创业的过程中,有一个非常好的兄弟,我们是合伙人,但是他的成长速度特别快,短短几年的时间就从一个非常稚嫩的人变成了...
    投资进化营阅读 843评论 0 2
  • 你喜欢二人世界 这样 你和我 可以 无拘无束的生活 婚姻终结了 你的梦 爱情都有附加值 守护着一潭死水 不如 走过...
    靖哥哥利涉大川阅读 220评论 0 0