Android开发之利用SQLite开展数据存储

Android开发之利用SQLite进行数据存储

Android开发之利用SQLite进行数据存储

  • Android开发之利用SQLite进行数据存储
    • SQLite数据库简介
    • Android中如何使用SQLite
      • 1 创建SQLiteOpenHelper对象并创建表
      • 2 通过SQLiteDatabase对象执行增删改查操作
      • 3 SQLiteDatabase之事务transaction

1.SQLite数据库简介

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起M
ysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2015年已经有15个年头,SQLite也迎来了一个版本 SQLite 3已经发布。

总结 : SQLite作为移动终端的数据库是非常合适的,占用内存小轻量级处理速度快

2.Android中如何使用SQLite

2.1 创建SQLiteOpenHelper对象,并创建表

新建一个类,命名为MySQLiteOpenHelper,并将其继承自SQLiteOpenHelper:

Android开发之利用SQLite开展数据存储

新建后会报错,因为没有添加构造方法,添加构造方法:

    package com.example.sqllitetest;

    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteDatabase.CursorFactory;
    import android.database.sqlite.SQLiteOpenHelper;

    public class MySQLOpenHelper extends SQLiteOpenHelper {

        public MySQLOpenHelper(Context context, String name, CursorFactory factory,
                int version) {
            super(context, name, factory, version);
            // TODO Auto-generated constructor stub
        }

        /**
         * 数据库创建时会调用,在这里执行创建表的语句
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            // TODO Auto-generated method stub
        }

        /**
         * 数据库升级时,此方法会调用,在这里执行数据库更新操作
         */
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
        }

        /**
         * 数据库打开时,此方法会调用
         */
        @Override
        public void onOpen(SQLiteDatabase db) {
            // TODO Auto-generated method stub
            super.onOpen(db);
        }

    }

在上面的onCreate();方法中执行一条创建表名为person的语句

    db.execSQL("create table person (_id integer primary key autoincrement, name char(10), age integer(3), phone integer(20))");

注意:其实在sqlite中除了id主键以外,所有的字段都没有明确的类型限制,举个列子,我们向integer类型的字段中插入char类型的数据也是可以的

那么既然这样,我们创建数据库时,指定的数据类型意图何在?

这些是为了,让我们程序员了解某个字段的类型限制,实际编码时,还是要指定字段明确类型的,方便日后维护和理解。

新建一个测试类SqliteTestCase.java:

    package com.example.sqllitetest;

    import android.content.ContentValues;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.test.AndroidTestCase;

    public class SqlliteTestCase extends AndroidTestCase {

        private MySQLOpenHelper oh;
        private SQLiteDatabase db;

        public void test() {
            System.out.println("This is test method!");
        }

        /**
         * 测试框架初始化完毕过后,在测试方法调用之前调用此方法
         */
        @Override
        protected void setUp() throws Exception {
            super.setUp();

            // 获得可写的数据库对象(若数据库不存在,先创建数据库,再获取可读可写的数据库对象;如果数据库存在,就直接打开)
            // *********************** 参数说明 ***********************
            // 参数1 : 获取Context对象,AndroidTestCase中为了方便测试,提供了getContext()方法
            // 参数2 : 数据库文件名
            // 参数3 : 游标工厂对象,被用来创建游标对象,默认为空
            // 参数4 : 用来标识数据库的版本,用来与之前创建的时候做对比,当版本大于,则调用onUpgrade()
            oh = new MySQLOpenHelper(getContext(), "person.db", null, 1);

            /**
             * ************** 第一种方法:获取数据库 **************
             *  1.被用来创建或打开一个可读写的数据库,
             *  当它被第一次调用的时候,会根据new SQLOpenHelper()中的数据库名和版本号
             *  当已存在相同数据库文件,并且版本号相同,则直接打开,
             *  反之,则调用创建或更新方法。
             *  
             *  2.数据一旦打开成功,将被缓存起来,当我们在需要录入数据时,可以在任何地方去调用返回
             *  的对象去操作数据库,注意:但不需要使用数据库时,需要关闭数据库
             *  
             *  3.但没有权限时,抑或磁盘满了的时候,这个方法将会被调用失败,但是,若问题得到解决,即可成功调用
             *  
             *  4.调用这个方法,若触发更新操作,你就需要警觉了:
             *  因为数据库的更新是个耗时的操作,我们不应该在应用的主线程中去调用它,包括ContentProvider.onCreate()
             *  
             */
            db = oh.getWritableDatabase();

            /**
             * ************** 第二种方法:获取数据库 **************
             * 不要被名字误导,这个方法同样可获得可读写的数据库对象,
             * 它与上面方法的区别是,当遇到一些问题:(列如:磁盘满了,这个时候调用不会失败,而是将会返回一个只读的数据库对象)
             */
            db = oh.getReadableDatabase();
        }

        /**
         * 测试方法执行完毕过后,调用此方法
         */
        @Override
        protected void tearDown() throws Exception {
            // TODO Auto-generated method stub
            super.tearDown();
            // 关闭数据库
            db.close();
        }

    }

注意:当我们new SQLiteOpenHelper()打开某个数据库时,传入的版本号不应比之前创建这个数据库的时候绑定的版本号低,否则会出现下面的错误,版本号只能递增

Android开发之利用SQLite开展数据存储

运行test()方法,显示为绿色,说明没有错误

Android开发之利用SQLite开展数据存储

通过DDMS–>File Explore,查看data/data/项目包名/databases目录下:

Android开发之利用SQLite开展数据存储

导出文件,在SQLite Expert软件中打开:

Android开发之利用SQLite开展数据存储

可以看到,数据库和表都被正确创建。

2.2 通过SQLiteDatabase对象执行增删改查操作

2.2.1添加数据操作

添加数据有两种方法:

  • 第一种方法 : 通过手写sql语句,执行execSQL();方法;

在SqliteTestCase.java中添加insert()方法

 public void insert() {
            db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"张三", 18, "180199678455"});
            db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"赵四", 16, "180199678455"});
            db.execSQL("insert into person (name, age, phone) values(?, ? , ?)", new Object[]{"Android", 15, "180199678455"});
        }

执行结果,数据成功插入表中:

Android开发之利用SQLite开展数据存储

  • 第二种方法 : 通过Android API,将数据封装到contentValues中;

在SqliteTestCase.java中添加insertByApi()方法:

public void insertApi() {
        // 把所有的数据封装到contentValues中
        ContentValues values = new ContentValues();
        values.put("name", "zhangsan");
        values.put("age", 78);
        values.put("phone", "13812235689");

        // 参数说明:
        // 第一个参数table             : 表名
        // 第二个参数nullColumnHack :可以指定为null,若为null,当你values中无值,则不会插入行
        //                             若你指定了nullColumnHack的值,即便你的values中无值,也会
        //                            插入null值到你的字段下
        // 第三个参数values            : ContentValues对象
        db.insert("person", null, values);
    }

导出db文件,刷新:

Android开发之利用SQLite开展数据存储

2.2.1删除数据操作

删除数据同样有两种方法:

  • 第一种方法 : 通过手写sql语句,执行execSQL();方法;
 public void delete() {
            // 删除id为1的行
            db.execSQL("delete from person where _id = ?", new Object[]{1});
        }
  • 第二种方法 : 通过Android API;
public void deleteApi() {
            // 删除表中age = 78, id = 4的记录
            // 返回值为受影响的行,删除了多少行
            int i = db.delete("person", "age = ? and _id = ?", new String[]{"78", "4"});
        }

2.2.1修改数据操作

修改数据同样有两种方法:

  • 第一种方法 : 通过手写sql语句,执行execSQL()方法:
public void update() {
            // 修改id为2的phone值为110
            db.execSQL("update person set phone = ? where _id = ?", new Object[]{"110", 2});
        }

查看结果:

Android开发之利用SQLite开展数据存储

  • 第二种方法 : 通过Android API;
public void updateApi() {
            // 通过ContentValues来指定修改后的值
            ContentValues values = new ContentValues();
            values.put("phone", "120");
            // 返回值为受影响的行
            int i = db.update("person", values, "_id = ? and age = ?", new String[]{"3", "15"});
        }

查看结果:

Android开发之利用SQLite开展数据存储

2.2.1查询数据操作

查询数据同样有两种方法:

  • 第一种方法 : rawQuery()方法:
public void query() {
            Cursor cursor = db.rawQuery("select name, age, phone from person ", null);

            while (cursor.moveToNext()) {
                // 不推荐用这种下标的方式来获取值,一旦后期字段的位置有所改动,维护起来比较麻烦
                // String name = cursor.getString(0);
                // int age = cursor.getInt(1);
                // String phone = cursor.getString(2);

                // 推荐使用
                String name = cursor.getString(cursor.getColumnIndex("name"));
                int age = cursor.getInt(cursor.getColumnIndex("age"));
                String phone = cursor.getString(cursor.getColumnIndex("phone"));
                System.out.println("name : " + name + "; age = " + age + ";" + " phone = " + phone);
            }
        }

logcat输出结果:

Android开发之利用SQLite开展数据存储

  • 第二种方法 : 通过Android API;
public void queryApi() {
            Cursor cursor = db.query("person", null, null, null, null, null, null);
            while (cursor.moveToNext()) {
                String name = cursor.getString(cursor.getColumnIndex("name"));
                int age = cursor.getInt(cursor.getColumnIndex("age"));
                String phone = cursor.getString(cursor.getColumnIndex("phone"));
                System.out.println("name : " + name + "; age = " + age + ";" + " phone = " + phone);
            }
        }

2.3 SQLiteDatabase之事务transaction

应用场景:当需要保证多条语句同时执行成功,否则,回滚

这里,我们简单的模拟一下,假设我们需要id为2的age加1岁,同时又要保证id为3的age减1岁

原本数据在数据库中是这样:

Android开发之利用SQLite开展数据存储

如果事务执行成功后,name为赵四的age将变为17,而name为Android的age变为14,反之,两条数据的所有属性值不变。

首先,我们人为的导致执行失败:

添加方法:

public void transaction() {
            try {
                // 开启事务
                db.beginTransaction();
                ContentValues values = new ContentValues();
                values.put("age", 17);
                db.update("person", values, "_id = ?", new String[]{"2"});

                values.clear();

                values.put("age", 14);
                db.update("person", values, "_id = ?", new String[]{"3"});

                int i = 1 / 0; // 这里有错,将导致事务执行失败

                // 设置事务执行成功
                db.setTransactionSuccessful();
            } catch (Exception e) {
                // TODO: handle exception
            } finally {
                // 结束事务,同时提交,如果已经设置事务执行成功,则sql语句生效,反之,则回滚
                db.endTransaction();
            }
        }

导出db文件,刷新,看到数据无任何变化:

Android开发之利用SQLite开展数据存储

再将错误去掉,执行方法:

结果如下,执行成功:

Android开发之利用SQLite开展数据存储

版权声明:本文为博主原创文章,未经博主允许不得转载。