在Android中使用最多的就是SQLiteOpenHelper,这篇文章会从SQLiteOpenHelper入手,讲述一下SQLiteOpenHelper的用法,以及相关的调试。

建立数据库

首先需要建立一个类继承SQLiteOpenHelper

public class MySql extends SQLiteOpenHelper {
    /**当数据库不存在时,就会创建数据库,然后打开数据库,再调用onCreate 方法来执行创建表之类的操作。
     * 当数据库存在时,SQLiteOpenHelper 就不会调用onCreate方法了,
     * 若传入的版本号高于当前的,就会执行onUpgrade()方法来更新数据库和版本号。
     * @param context
     * @param name 表示数据库文件名(不包括文件路径,默认路径是/data/data/包名/databases),SQLiteOpenHelper类会根据这个文件名来创建数据库文件。
     * @param factory 数据库进行查询的时候会返回一个cursor,这个cursor就是actory中产生的,factory可以进行自定义
     * @param version 表示数据库的版本号。如果当前传入的数据库版本号比上一次创建的版本高,SQLiteOpenHelper就会调用onUpgrade()方法。
     */
    public MySql(Context context, String name,
                 CursorFactory factory, int version) {
        super(context, name, factory, version);


    }

    /**当数据库首次创建时执行该方法,一般将创建表等初始化操作放在该方法中执行.
     *
     * @param sqLiteDatabase
     */
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table if not exists person("
            + "id integer primary key,"
            + "name text,"
            + "sex text)");
    }

    /**当打开数据库时传入的版本号与当前的版本号不同时会调用该方法
     * @param sqLiteDatabase
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {

    }
}复制代码

每一个参数的含义,可以参照我写的注释。
我在这里通过执行sql语句"create table if not exists person(id integer primary key,name text,sex text)"创建了一个表。表名是person。
我们写一个Activity,用来创建这个表:

MySql mySql ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mySql = new MySql(this,"test.db",null,1);
    }复制代码

表名是test.db 版本号为1。

查看表的结构

如何查看表的结构呢?有以下几种办法(如果是真机,都需要是一个root的手机):

SQLiteStudio

我们可以借助一些pc上的工具查看数据库的表结构。例如SQLiteStudio,当然还有其它软件,这里不再做介绍。
首先需要先将.db文件从手机中取出来,首先可以用adb pull命令进入到手机存储中,切换到指定的文件夹(上面提到过在/data/data/包名/databases),然后将上面建立的test.db文件pull出来。
我一般使用的是Android monitor,点击一个按钮即可pull出来:



然后倒入到SQLiteStudio中进行查看,如下图所示


SQLScout

与上面的方法不同的是,这是一个AndroidStudio的插件,首先需要安装这个插件。然后修改一下工程配置:
首先是在工程的build.gradle中修改如下:

allprojects {
      repositories {
          jcenter()
          maven {
              url 'http://www.idescout.com/maven/repo/'
          }
      }
  }复制代码

然后在module的build.gradle中添加:

compile 'com.idescout.sql:sqlscout-server:2.1'复制代码

或者去然后修改你使用的Activity:

SqlScoutServer.create(this, getPackageName());复制代码

重新运行即可。
在你安装完Android Studio插件后,IDE的右边会多一个:



点开,选择你的app:



操作

插入数据

首先需要获取SQLiteDatabase对象

SQLiteDatabase db = mySql.getWritableDatabase();复制代码

有两种方式可以进行数据插入,一种是执行原生的sql语句:

db.execSQL("insert into person(name,sex) values('deep','man')");复制代码

或者使用SQLiteDatabase提供的插入方法:

ContentValues values = new ContentValues();
                values.put("name", "deep");
                values.put("sex",  "man");
                db.insert("person", "id", values);复制代码

很多时候我们需要批量的向数据库中插入大量数据时,单独的使用添加方法导致应用响应缓慢, 因为sqlite插入数据的时候默认一条语句就是一个事务,有多少条数据就有多少次磁盘操作。
我们可以用beginTransaction()的方式用来标志开启事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。
同时可以配合insertOrThrow方法使用,判断是否插入成功。

db.beginTransaction();
                try {
                    ContentValues cv = new ContentValues();
                    values.put("name", "deep");
                    values.put("sex",  "man");
                    db.insertOrThrow("savedreports", null, cv);
                    db.setTransactionSuccessful();
                } catch (SQLiteConstraintException e) {
                    return false;
                } finally {
                    db.endTransaction();
                }复制代码

选取数据

与上面的插入数据相同,也有如下几种方法
首先就是利用rawQuery方法:

SQLiteDatabase dbselect = mySql.getReadableDatabase();
                Cursor cursor = dbselect.rawQuery("select * from "+"person", null);
                while (cursor.moveToNext()) {
                    int id  = cursor.getInt(0);
                    String name = cursor.getString(1);
                    String sex = cursor.getString(2);
                    Log.e("deep","id = "+id+"  name= "+name+" sex="+sex);
                }复制代码

查看log可以得到:



如果想指定id可以使用:


Cursor cursor = dbselect.rawQuery("select * from person where id=?", new String[]{"1"});复制代码

再有就是利用query方法:

Cursor cursor = dbselect.query("person",new String[]{"name,sex"}, "id=?", new String[]{"1"},null,null,null);
                while (cursor.moveToNext()) {

                    String name = cursor.getString(0);
                    String sex = cursor.getString(1);
                    Log.e("deep","  name= "+name+" sex="+sex);
                }复制代码

这个执行的意思是找到id = 1的一行,取出其中的name,和sex字段的值。
query(table,columns, selection, selectionArgs, groupBy, having, orderBy)方法各参数的含义:

  • table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。
  • columns:要查询出来的列名。相当于select语句select关键字后面的部分。
  • selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”
  • selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
  • groupBy:相当于select语句group by关键字后面的部分
  • having:相当于select语句having关键字后面的部分
  • orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc;

删除数据

  • 删除数据也是有两种,一种是使用原生的sql语句:
SQLiteDatabase dbdelete = mySql.getWritableDatabase();
dbdelete.execSQL("delete from person where id=1");复制代码
  • 或者使用delete方法:
dbdelete.delete("person", "id=?",  new String[]{"2"});复制代码
  • 这个的意思是删除id = 2的一行。这里要注意,不是 new String[]{"2","3"}就是删除id等于2和3的两行,String数组的长度,要与前面的条件的数量对应。这里前面的条件是id=?这一个条件,所以String数组的长度只能为1。

dbdelete.delete("person", "1", null);如果调用这个方法,表示删除所有行。

更新字段

更新字段也是有两种方式进行更新,第一种仍然是原生SQL:

SQLiteDatabase updatedb = mySql.getWritableDatabase();
updatedb.execSQL("update person set sex='woman' where id=4");复制代码

或者使用update方法:

ContentValues aaa = new ContentValues();
aaa.put("name", "deep");
aaa.put("sex",  "woman");
updatedb.update("person",aaa,"id=?",new String[]{"6"});复制代码