【Android应用开发技术:数据存储】数据库
2015-07-30 16:40
741 查看
作者:郭孝星
微博:郭孝星的新浪微博
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
Schema是一种DB结构的正式声明。schema是从你创建DB的SQL语句中生成的。
一般情况下,创建一个伴随类(companion class)是很有益的,这个类称为合约类(contract class),它用一种系统化并且自动生成文档的方式,显示指定了Schema样式。
Contract Clsss是一些常量的容器。它定义了例如URIs,表名,列名等。这个Contract类允许同一个包下与其他类使用同样的常量。它让我们只需要在一个地方修改列名,然后这个列名就可以自动传递给整个代码。
通过实现BaseColumns的接口,内部类可以继承到一个名为_ID的主键,这个对于Android里面的一些类似Cursor Adaptor类是很有必要的。这么做不是必须的,但这样能够使得DB与Android的Framework能够很好的相容。
就像保存文件到设备的internal storage 一样,Android会保存db到程序的private的空间上。数据是受保护的,因为那些区域默认是私有的,不可被其他程序所访问。
在SQLiteOpenHelper类中有一些很有用的APIs。当使用这个类来做一些与你的db有关的操作时,系统会对那些有可能比较耗时的操作(例如创建与更新等)在真正需要的时候才去执行,而不是在app刚启动的时候就去做那些动作。我们需要做的仅仅是执行getWritableDatabase()或者getReadableDatabase(),因为那些操作可能是很耗时的,所以我们需要在background thread(AsyncTask or IntentService)里面去执行getWritableDatabase()或者getReadableDatabase()。
为了使用SQLiteOpenHelper, 我们需要创建一个子类并重写onCreate(), onUpgrade()与onOpen()等callback方法。有时候还需要实现onDowngrade(), 但是这并不是必需的,如下所示:
实现了SQLiteOpenHelper子类后,我们就可以进行实例化,如下所示:
要查询在cursor中的行,使用cursor的其中一个move方法,但必须在读取值之前调用。一般来说,应该先调用moveToFirst()函数,将读取位置置于结果集最开始的位置。对每一行,我们可以使用cursor的其中一个get方法比如getString()或getLong()获取列的值。对于每一个get方法必须传递想要获取的列的索引位置(index position),索引位置可以通过调用getColumnIndex()或getColumnIndexOrThrow()获得。
从course对象中读取数据信息,如下所示:
SQL Injection:随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。
这个机制把查询语句划分为选项条款与选项参数两部分。条款部分定义了查询的列的特征,参数部分用来测试是否符合前面的条款。(Android官方原文:The clause defines the columns to look at, and also allows you to combine column tests. The arguments are values to test against that are bound into the clause.) 因为处理的结果与通常的SQL语句不同,这样可以避免SQL注入问题。
微博:郭孝星的新浪微博
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
【Android应用开发技术:数据存储】章节列表
SQL中一个中重要的概念是schema。Schema是一种DB结构的正式声明。schema是从你创建DB的SQL语句中生成的。
一般情况下,创建一个伴随类(companion class)是很有益的,这个类称为合约类(contract class),它用一种系统化并且自动生成文档的方式,显示指定了Schema样式。
Contract Clsss是一些常量的容器。它定义了例如URIs,表名,列名等。这个Contract类允许同一个包下与其他类使用同样的常量。它让我们只需要在一个地方修改列名,然后这个列名就可以自动传递给整个代码。
一 定义DB结构
组织Contract类的好方法是在你的类的根层级定义一些全局变量,然后为每一个table来创建内部类,如下所示:public final class FeedReaderContract { // To prevent someone from accidentally instantiating the contract class, // give it an empty constructor. public FeedReaderContract() {} /* Inner class that defines the table contents */ 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"; ... } }
通过实现BaseColumns的接口,内部类可以继承到一个名为_ID的主键,这个对于Android里面的一些类似Cursor Adaptor类是很有必要的。这么做不是必须的,但这样能够使得DB与Android的Framework能够很好的相容。
二 创建DB
当定义好了DB的结构之后,我们实现那些创建与维护DB与table的方法。下面是一些典型的创建与删除table的语句。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;
就像保存文件到设备的internal storage 一样,Android会保存db到程序的private的空间上。数据是受保护的,因为那些区域默认是私有的,不可被其他程序所访问。
在SQLiteOpenHelper类中有一些很有用的APIs。当使用这个类来做一些与你的db有关的操作时,系统会对那些有可能比较耗时的操作(例如创建与更新等)在真正需要的时候才去执行,而不是在app刚启动的时候就去做那些动作。我们需要做的仅仅是执行getWritableDatabase()或者getReadableDatabase(),因为那些操作可能是很耗时的,所以我们需要在background thread(AsyncTask or IntentService)里面去执行getWritableDatabase()或者getReadableDatabase()。
为了使用SQLiteOpenHelper, 我们需要创建一个子类并重写onCreate(), onUpgrade()与onOpen()等callback方法。有时候还需要实现onDowngrade(), 但是这并不是必需的,如下所示:
public class FeedReaderDbHelper extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "FeedReader.db"; 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());
三 DB数据操作
3.1 数据添加
使用insert()方法进行信息的添加, insert()方法的第一个参数是table名,第二个参数会使得系统自动对那些ContentValues没有提供数据的列填充数据为null ,如果第二个参数传递的是null,那么系统则不会对那些没有提供数据的列进行填充,如下所示:// Gets the data repository in write mode SQLiteDatabase db = mDbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); 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 the new row, returning the primary key value of the new row long newRowId; newRowId = db.insert( FeedReaderContract.FeedEntry.TABLE_NAME, FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE, values);
3.2 数据读取
使用query()方法进行数据读取,传递你需要查询的条件。查询后会返回一个Cursor对象。SQLiteDatabase db = mDbHelper.getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { FeedReaderContract.FeedEntry._ID, FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED, ... }; // How you want the results sorted in the resulting Cursor String sortOrder = FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + " DESC"; Cursor c = db.query( FeedReaderContract.FeedEntry.TABLE_NAME, // The table to query 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 // The sort order );
要查询在cursor中的行,使用cursor的其中一个move方法,但必须在读取值之前调用。一般来说,应该先调用moveToFirst()函数,将读取位置置于结果集最开始的位置。对每一行,我们可以使用cursor的其中一个get方法比如getString()或getLong()获取列的值。对于每一个get方法必须传递想要获取的列的索引位置(index position),索引位置可以通过调用getColumnIndex()或getColumnIndexOrThrow()获得。
从course对象中读取数据信息,如下所示:
cursor.moveToFirst(); long itemId = cursor.getLong( cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID) );
3.3 数据删除
和查询信息一样,删除数据同样需要提供一些删除标准。DB的API提供了一个防止SQL注入的机制来创建查询与删除标准。SQL Injection:随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。
这个机制把查询语句划分为选项条款与选项参数两部分。条款部分定义了查询的列的特征,参数部分用来测试是否符合前面的条款。(Android官方原文:The clause defines the columns to look at, and also allows you to combine column tests. The arguments are values to test against that are bound into the clause.) 因为处理的结果与通常的SQL语句不同,这样可以避免SQL注入问题。
// Define 'where' part of query. String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; // Specify arguments in placeholder order. String[] selelectionArgs = { String.valueOf(rowId) }; // Issue SQL statement. db.delete(table_name, mySelection, selectionArgs);
1.4 数据更新
当你需要修改DB中的某些数据时,使用update()方法,更新操作结合了删除和插入的语法,如下所示:SQLiteDatabase db = mDbHelper.getReadableDatabase(); // New value for one column ContentValues values = new ContentValues(); values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title); // Which row to update, based on the ID String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?"; String[] selectionArgs = { String.valueOf(rowId) }; int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME, values, selection, selectionArgs);
相关文章推荐
- 【Android应用开发技术:文件读写】Android文件系统
- Android adb命令唤醒屏幕
- Android adb命令唤醒屏幕
- ADNROID XML图像资源文件详细讲解(三)
- android 消息机制
- android开发中获取系统时间方法
- Android安全研究经验谈
- android 获取 imei号码
- android之针对fragment多次调用onCreateView的问题
- Android Studio常用快捷键
- Android实现双进程守护 (转)
- android 5.1 添加reboot 飞行模式 silent
- Android.mk的用法|静态库|动态库
- 详解Android中的Toast源码
- Android 缓存处理
- Android相对布局的属性
- AndroidMaterialDesign动画之Animate View State Changes
- 【android】利用service监听来电或来信息
- android:服务器与客户端的双向开发
- android 9-Patch图片右边下边效果