SQL数据库主要概念之一Schema----一个关于如何组织数据库的定义
Schema反映在你用SQL语句定义数据库的时候。
抽象类是一个容器,里面装着定义URI、表、列的常量。
抽象类允许在同一个包内不同的类里使用相同的变量。
组织抽象类的最好的方法是:把这些用来定义的常量在最上层父类里设置为整个数据库的全局常量。然后把每一个表创建为一个内部类,用这个内部类“包裹”出每一个表,列举出每个表所有的列。
实现BaseColumns接口以后,内部类就可以继承一个主键字段_ID,这也是很多android里的类所需要的,比如游标适配器(cursor adaptor)。这虽然不是必须,但是可以使数据库和android的框架协调工作。
BaseColumns接口有两个常量:1.总行数_count
以下是一个为单表定义表名和列名的代码片段:
//定义一个合同类的子类,实现BaseColumns接口,父类是FeedReaderContract
//这个inner类就代表了数据库很多表的其中之一
public static abstract class FeedEntry implements BaseColumns {
//定义表名
public static final String TABLE_NAME = "entry";
//定义列名
public static final String COLUMN_NAME_ENTRY_ID = "entryid";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
...
}
其中,抽象类会定义出所有的表名和所有的列名,分属不同的表,然后用内部类来实现区分。
为了避免有人实例化抽象类FeedReaderContract,定义了一个私有构造器:
private FeedReaderContract() {}
Create a Database Using a SQL Helper
定义好数据库大体的样子以后,你需要实现创建和维护数据库和表的方法,以下是创建表和删除表的典型的语句:
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedReaderContract.FeedEntry.TABLE_NAME + " (" +
FeedReaderContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
... // Any other options for the CREATE command
" )";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + TABLE_NAME_ENTRIES;
android系统里,数据库存储在private空间里,很安全,其他app无法访问。
SQLiteOpenHelper类里有很多有用的API,当你使用这个类获取数据库的引用的时候,只有当你需要的时候,系统才有可能进行耗时较长的操作,比如创建和更新数据库。你只要调用getWritableDatabase()
注意,因为有些操作可能是耗时操作,所以务必在后台进程调用getWritableDatabase()
要使用SQLiteOpenHelper类(抽象类),就需要创建一个子类,并且覆写 onCreate(), onUpgrade()
下是使用以上方法的代码示例:
//创建SQLiteOpenHelper的子类
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// 如果要改变数据库模式,则要升级数据库版本.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
//子类构造器调用父类SQLiteOpenHelper的构造器
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//覆写方法
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
//删除数据并重新建库
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
要使用数据库,就必须要实例化SQLiteOpenHelper类的子类:
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
Put Information into a Database
把 ContentValues对象当参数传给insert()方法,就可以把数据存入数据库。代码如下:
//调用SQLiteOpenHelper的子类的对象的方法
SQLiteDatabase db = mDbHelper.getWritableDatabase();
//创建值的键值对, 列名是key
//新建ContentValues类的对象values
ContentValues values = new ContentValues();
//调用values的put()方法,这个values装了一个row
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, content);
//插入新的一行,返回这行的主键
//insert()方法参数:
参数1:表名table_name
参数2:指定是否可以可空,nullable可插入空数据,null不可插入空数据
参数3:插入的键值对,也就是一个row
long newRowId;
newRowId = db.insert(
FeedReaderContract.FeedEntry.TABLE_NAME,
FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,
values
);
从数据库读取信息使用 query()方法,查询返回值在一个Cursor对象里。
//获取可读数据库,赋给SQLiteDatabase对象
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// 定义一个projection
String[] projection = {
FeedReaderContract.FeedEntry._ID,
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,
...
};
//查询结果在cursor里的排序方式
String sortOrder =
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + " DESC";
//查询结果赋给Cursor对象
Cursor c = db.query(
FeedReaderContract.FeedEntry.TABLE_NAME, //表名
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // 排序方式
);
查看cursor里一个row的方法:在读数值之前,必须要调用move方法,首先调用 moveToFirst()方法,这样游标就到了第一个位置,取值就用get系方法,比如getString()和getLong()
//指针置首
cursor.moveToFirst();
//根据给定的列名,取值
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID)
);
Delete Information from a Database
要是想删除一个表里的行,就要提供筛选标准来确定要删除的行。
数据库API提供了一个机制来创建筛选标准,来防止SQL注入攻击。
// 定义查询的WHERE部分
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selelectionArgs = { String.valueOf(rowId) };
// 组装SQL语句
//delete()方法中
参数1:表名
参数2:WHERE语句
参数3:要查的字段
db.delete(table_name, selection, selectionArgs);
Update a Database
要修改数据库值的子集时,使用 update()方法。
语法其实是把insert()里的values和delete()里的where子句结合了起来。
SQLiteDatabase db = mDbHelper.getReadableDatabase();
//列的新值
ContentValues values = new ContentValues();
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
//根据ID,确定需要update的列
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selelectionArgs = { String.valueOf(rowId) };
//执行update
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);