Android SQlite数据库 SQLiteOpenHelper类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android SQlite数据库 SQLiteOpenHelper类相关的知识,希望对你有一定的参考价值。

insert插入数据程序崩溃,但SQL语句Sqlitestudio可执行

SQLiteOpenHelper是一个辅助类来管理数据库的创建和版本。
可以通过继承这个类,实现它的一些方法来对数据库进行一些操作。
所有继承了这个类的类都必须实现下面这样的一个构造方法:
public DatabaseHelper(Context context, String name, CursorFactory factory, int version)
第一个参数:Context类型,上下文对象。
第二个参数:String类型,数据库的名称
第三个参数:CursorFactory类型
第四个参数:int类型,数据库版本
参考技术A 没有叫做nameString的列。追问

我也知道啊= =,但我数据表有设计该列啊,该怎么改呢

追答

你只有一个列名叫做name,没有nameString

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

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

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:

技术分享

新建后会报错,由于没有加入构造方法,加入构造方法:

    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()打开某个数据库时。传入的版本号号不应比之前创建这个数据库的时候绑定的版本号号低。否则会出现以下的错误,版本号号仅仅能递增

技术分享

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

技术分享

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

技术分享

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

技术分享

能够看到,数据库和表都被正确创建。

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 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文件,刷新:

技术分享

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 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"});
        }

查看结果:

技术分享

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 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岁

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

技术分享

假设事务运行成功后。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数据库 SQLiteOpenHelper类的主要内容,如果未能解决你的问题,请参考以下文章

如何在Android设备中用NDK编译SQLite并且对SQLite进行操作

Android SQLite使用

Android SQLite详解

Android SQLite详解

Android数据库代码优化 - 从SQLite说起

android 怎么查看sqlite数据库