获得了SQLiteDatabase对象以后,我们就可以通过调用SQLiteDatabase的实例方法来对数据库进行操作了。SQLiteDatabase除了提供像execSQL()和rawQuery()这种直接对SQL语句解析的方法外,还针对INSERT、UPDATE、DELETE和SELECT等操作专门定义了相关的方法。下面是对常用的数据库操作方法的总结。
public void execSQL (String sql),public void execSQL (String sql, Object[]bindArgs),执行一条非查询SQL语句,执行期间会获得该SQLite数据库的写锁,执行完毕后锁释放。不支持用;隔开的多条SQL语句。若SQL语句执行失败会抛出SQLException异常。
参数:sql,需要执行的SQL语句字符串。
bindArgs,SQL语句中表达式的?占位参数列表,仅仅支持String、byte数组、long和double型数据作为参数。
返回值:无。
public Cursor rawQuery (String sql, String[] args),public Cursor rawQuery-WithFactory(SQLiteDatabase.CursorFactory factory, String sql, String[]args, String editTable),执行一条SQL查询语句,并把查询结果以Cursor的子类对象的形式返回。
参数:sql,需要执行的SQL语句字符串。
args,SQL语句中表达式的?占位参数列表,参数只能为String类型。
factory,CursorFactory对象,用来构造查询完毕时返回的Cursor的子类对象,为null时使用默认的CursorFactory构造。
editable,第一个可编辑的表名。
返回值:指向第一行数据之前的Cursor子类对象。
public long insert (String table, String nullColumnHack, ContentValuesinitialValues),public long insertOrThrow (String table, String nullColumnHack,
ContentValues initialValues),向指定表中插入一行数据。
参数:table,需要插入数据的表名。
nullColumnHack,这个参数需要传入一个列名。SQL标准并不允许插入所有列均为空的一行数据,所以当传入的initialValues值为空或者为0时,用nullColumnHack参数指定的列会被插入值为NULL的数据,然后再将此行插入到表中。
initalValues,用来描述要插入行数据的ContentValues对象,即列名和列值的映射。
返回值:新插入行的行id。如果有错误发生返回-1。
public int update (String table, ContentValues values, String whereClause,String[] whereArgs),更新表中指定行的数据。
参数:table,更新数据的表名。
values,用来描述更新后的行数据的ContentValues对象,即列名和列值的映射。whereClause,可选的where语句(不包括WHERE关键字),用来指定需要更新的行。若传入null则表中所有的行均会被更新。
whereArgs,where语句中表达式的?占位参数列表,参数只能为String类型。返回值:被更新的行的数量。
public int delete (String table, String whereClause, String[] whereArgs),删除表中指定的行。
参数:table,需要删除行的表名。
whereClause,可选的where语句(不包括WHERE关键字),用来指定需要删除的行。
若传入null则会删除所有的行。
whereArgs,where语句中表达式的?占位参数列表,参数只能为String类型。
返回值:若传入了正确的where语句则被删除的行数会被返回。若传入null,则会返回0。若要删除所有行并且返回删除的行数,则需要在where语句的地方传入字符串1。
public Cursor query (String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having, String orderBy,String limit)public Cursor query (boolean distinct, String table, String[] columns,String selection, String[] selectionArgs, String groupBy, String having,String orderBy, String limit)public Cursor query (String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having, String orderBy)public Cursor queryWithFactory (SQLiteDatabase.CursorFactory cursorFactory,boolean distinct, String table, String[] columns, String selection, String[]selectionArgs, String groupBy, String having, String orderBy, String limit)
根据检索条件检索指定表并把满足条件的行以Cursor的子类对象返回。参数:table,检索的表名。
columns,由需要返回列的列名所组成的字符串数组,传入null会返回所有的列。selection,指定需要返回的行的where语句(不包括WHERE关键字)。传入null则返回所有行。
selectionArgs,where语句中表达式的?占位参数列表,参数只能为String类型。
groupBy,对结果集进行分组的group by语句(不包括GROUP BY关键字)。传入null将不对结果集进行分组。
having,对分组结果集设置条件的having语句(不包括HAVING关键字)。必须配合groupBy参数使用,传入null将不对分组结果集设置条件。
orderBy,对结果集进行排序的order by语句(不包括ORDER BY关键字)。传入null将对结果集使用默认的排序。
limit,对返回的行数进行限制的limit语句(不包括LIMIT关键字)。传入null将不限制返回的行数。
distinct,如果希望结果集没有重复的行传入true,否则传入false。
cursorFactory,使用这个CursorFactory来构造返回的Cursor子类对象,传入null使用默认的CursorFactory。
返回值:指向第一行数据之前的Cursor子类对象。
了解了这些函数,下面让我们来把数据库的操作填充到之前的MyHelper骨架中,并且在程序中利用MyHelper创建并打开数据库名为code.db的数据库,最后向数据库中的countrycode表插入数据,如表9-1所示。
表9-1 countrycode表中包含的数据
TB_NAME指定了表名,而ID、COUNTRY和CODE则分别指定了各个列的列名。
然后在onCreate()和onUpgrade()方法中加入创建表和删除表的操作。
- @Override
- public void onCreate(SQLiteDatabase db) {
- // 创建表countrycode
- db.execSQL("CREATE TABLE IF NOT EXISTS "
- + TB_NAME + " ("
- + ID + " INTEGER PRIMARY KEY,"
- + COUNTRY + " VARCHAR,"
- + CODE + " INTEGER)");
- }
调用了execSQL()方法来创建如表9-1所示的表。
- @Override
- public void onUpgrade(SQLiteDatabase db,
- int oldVersion, int newVersion) {
- //删除以前的旧表,创建一张新的空表
- db.execSQL("DROP TABLE IF EXISTS "+TB_NAME);
- onCreate(db);
- }
每次需要更新数据库版本时,将以前的表删除,重新创建空表。这是很极端的一种做法,会删除以前数据库内的所有数据。其实在对数据库进行改变时,若需要保留之前数据库中的数据,可以使用ALERT TABLE语句来直接修改表。
接下来就是在Activity中程序的运行部分了,编辑SQLite2.java,代码如下所示。
- 1 package com.studio.android.chp9.ex3;
- 2
- 3 import android.app.Activity;
- 4 import android.content.ContentValues;
- 5 import android.database.sqlite.SQLiteDatabase;
- 6 import android.os.Bundle;
- 7
- 8 public class SQLite2 extends Activity {
- 9
- 10 public static final String DB_NAME = "code.db";
- 11 public static final int VERSION = 1;
- 12
- 13 MyHelper helper;
- 14 SQLiteDatabase db;
- 15
- 16 /** Activity第一次创建时调用 */
- 17 @Override
- 18 public void onCreate(Bundle savedInstanceState) {
- 19 super.onCreate(savedInstanceState);
- 20 setContentView(R.layout.main);
- 21
- 22 //初始化数据库辅助对象
- 23 helper = new MyHelper(this, DB_NAME, null, VERSION);
- 24
- 25 //获得可读写的SQLiteDatabase对象
- 26 db = helper.getWritableDatabase();
- 27
- 28 //用insert方法像数据库中插入"中国 86"
- 29 ContentValues values = new ContentValues();
- 30 values.put(MyHelper.COUNTRY, "中国");
- 31 values.put(MyHelper.CODE, 86);
- 32 db.insert(MyHelper.TB_NAME, MyHelper.ID, values);
- 33
- 34 //使用insert方法
- 35 //插入完全为空的ContentValues,
- 36 //再使用update方法修改行数据为"意大利 39"
- 37 db.insert(MyHelper.TB_NAME, MyHelper.ID,null);
- 38 values.clear();
- 39 values.put(MyHelper.COUNTRY, "意大利");
- 40 values.put(MyHelper.CODE, 39);
- 41 db.update(MyHelper.TB_NAME, values, MyHelper.ID + " = 2",null);
- 42
- 43 //使用execSQL方法插入数据"洪都拉斯 504"
- 44 db.execSQL("INSERT INTO "
- 45 + MyHelper.TB_NAME + "("
- 46 + MyHelper.COUNTRY + ","
- 47 + MyHelper.CODE + ") VALUES "
- 48 + "('洪都拉斯',504)");
- 49 }
- 50
- 51 @Override
- 52 public void onDestroy() {
- 53 //程序退出时删除所有行
- 54 db.delete(MyHelper.TB_NAME,null,null);
- 55 super.onDestroy();
- 56 }
- 57 }
首先在为数据库名和版本分别定义两个静态常量。
- 10 public final String DB_NAME = "code.db";
- 11 public final int VERSION = 1;
DB_NAME指定了要创建/打开的数据库的名字,VERSION则指定了数据库的版本。
这里为了演示方法的使用,在Activity的onCreate()方法中分别用了三种不同的方式来向数据库中插入、更新数据。在实际的应用程序编写过程中请读者根据情况,自行选择操作数据库的方式。首先是构造一个ContentValues的对象,然后用insert方法将数据插入到数据库。
- 28 //用insert方法向数据库中插入"中国 86"
- 29 ContentValues values = new ContentValues();
- 30 values.put(MyHelper.COUNTRY, "中国");
- 31 values.put(MyHelper.CODE, 86);
- 32 db.insert(MyHelper.TB_NAME, MyHelper.ID, values);
细心的读者可能会注意到,这里我们并没有指定_id列的值。这是因为SQLite数据库中将所有声明为“INTEGER PRIMARY KEY”的列自动识别成自增列。在插入一行数据的时候,若不指定自增列的数据或给自增列传入NULL值时,会自动给自增列赋一个所有行中此列里的最大值加1的数。若添加的是第一行则从数字1开始。而这里的_id就是一个自增列,所以在插入这行数据后,此行数据_id列的值为1。
而第二种方式是,先用insert方法插入一个为null的ContentValues,然后再用update方法修改刚才所插入的行。
- 34 //使用insert方法
- 35 //插入完全为空的ContentValues,
- 36 //再使用update方法修改行数据为"意大利 39"
- 37 db.insert(MyHelper.TB_NAME, MyHelper.ID,null);
- 38 values.clear();
- 39 values.put(MyHelper.COUNTRY, "意大利");
- 40 values.put(MyHelper.CODE, 39);
- 41 db.update(MyHelper.TB_NAME, values, MyHelper.ID + " = 2",null);
由于传入的ContentValues对象为null,所以将会把由第二个参数设置的列赋值为NULL。这里需要分清NULL列和空列:空列是没有任何值的列,而NULL列的意思是值为NULL的列。这里我们第二个参数设置的是_id列,又由于_id列是自增列,传入NULL会自增赋值,所以最终_id列的值为2。然后再使用update方法,更新_id为2的行,把国家信息和区号信息填入。
- 43 //使用execSQL方法插入数据"洪都拉斯 504"
- 44 db.execSQL("INSERT INTO "
- 45 + MyHelper.TB_NAME + "("
- 46 + MyHelper.COUNTRY + ","
- 47 + MyHelper.CODE + ") VALUES "
- 48 + "('洪都拉斯',504)");
最后使用的是直接执行SQL语句字符串的方式插入行。
程序退出时清空表中数据,避免下次启动程序时重复添加数据。
- 51 @Override
- 52 public void onDestroy() {
- 53 //程序退出时删除所有行
- 54 db.delete(MyHelper.TB_NAME,null,null);
- 55 super.onDestroy();
- 56 }
- public static final String TB_NAME = "countrycode";
- public static final String ID = "_id";
- public static final String COUNTRY = "country";
- public static final String CODE = "code";