请尊重他人的劳动成果,转载请注明出处:Android开发之SQLite数据库详解
http://blog.csdn.net/fengyuzhengfan/article/details/40194393
Android系统集成了一个轻量级的数据库:SQLite, SQLite并不想成为像Oracle、MySQL那样的专业数据库。SQLite只是一个嵌入式的数据库引擎,专门适用于资源有限的设备上(如手机、PDA等)适量数据存取。
虽然SQLite支持绝大部分SQL92语法,也允许开发者使用SQL语句操作数据库中的数据,但SQLite并不像Orade、MySQL数据库那样需要安装、启动服务器进程,SQLite数据库只是一个文件。
从本质上来看,SQLite的操作方式只是一种更为便捷的文件操作。后面我们会看到,当应用程序创建或打开一个SQLite数据库时,其实只是打开一个文件准备读写,因此有人说SQLite有点像Microsoft的Access (实际上SQLite功能要强大得多)。
Android提供了SQLiteDatabase 代表一个数据库(底层就是一个数据库文件>,一旦应用程序获得了代表指定数据库的SQLiteDatabase 对象,接下来就可通过SQLiteDatabase 对象来管理、操作数据库了。
1)staticSQLiteDatabase openDatabase(Stringpath,SQLiteDatabase .CursorFactory factory, intflags):打开path文件所代表的SQLite数据库。
2)staticSQLiteDatabase openOrCreateDatabase(File file,SQLiteDatabase .CursorFactory factory):打开或创建(如果不存在)file文件所代表的SQLite数据库。
3)staticSQLiteDatabase openOrCreateDatabase(String path,SQLiteDatabase .CursorFactory factory):打开或创建(如果不存在)path文件所代表的SQLite数据库。
1)execSQL(Stringsql, Object[] bindArgs):执行带占位符的 SQL语句。
2)execSQL(String sql):执行 SQL语句。
3)insert(Stringtable, String nullColumnHack,ContentValues values):向执行表中插入数据。
4)update(Stringtable, ContentValues values, String whereClause, String[] whereArgs):吏新指定表中的特定数据。
5)delete(Stringtable, String whereClause, String[] whareArgs):删除指定表中的特定数据。
6)Cursorquery(String table, String[]columns, String selection, String[] selection Args,String groupBy, String having,String orderBy):对执行数据表执行査询。
7)Cursorquery(String table, String[] columns, String selection, String[] selectionArgs,String groupBy, String having, String orderBy, String limit}:对执行数据表执行査询。Limit参数控制最多査询几条记录(用于控制分页的参数)。
8)Cursorquery(boolean distinct, String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having, String orderBy, String limit): 对指定表执行査询语句。其中第一个参数控制是否去除重复值。
9)rawQuery(Stringsql, String[] selectionArgs):执行带占位符的 SQL查询。
10)beginTransaction():开始事务。
11)endTransaction():结束事务。
从上面的方法不难看出,其实SQLiteDatabase的作用有点类似于JDBC的Connection接口,但SQLiteDatabase提供的方法更多:比如insert、update、delete、query等方法,其实这些方法完全可通过执行SQL语句来完成,但Android考虑到部分开发者对SQL语法不熟悉,所以提供这些方法帮助开发者以更简单的方式来操作数据表的数据。
上面査询方法都是返回一个Cursor对象,Android中的Cursor类似干JDBC的ResultSet, Cursor同样提供了如下方法来移动査询结果的记录指针。
1)move(int offset):将记录指针向上或向下移动指定的行数。offset为正数就向下移动;为负数就是向上移动。
2)booleanmoveToFirst():将记录指针移动到第一行,如果移动成功则返回true。
3)booleanmoveToLast():将记录指针移动到最后一行,如果移动成功则返回true。
4)booleanmoveToNext():将记录指针移动到下一行,如果移动成功则返回true。
5)booleanmoveToPosition(int position):将记录指针移动到指定的行,如果移动成功则返回true。
6)booleanmoveToPrevious():将记录指针移动到上一行,如果移动成功则返回true。
—旦将记录指针移动到指定行之后,接下来就可以调用Cursor的getXxx()方法获取该行的指定列的数据。
其实如果大家具有JDBC编程的经验,完全可以把SQLiteDatabase当成JDBC :中Connection和Statement的混合体因为SQLiteDatabase 既代表了与数据库的连接,也可直接用于执行SQL操作;而Android中Cursor则可当成ResultSet,而且Cursor提供了更多便捷的方法来操作结果集。
前面已经讲到,使用SQLiteDatabase的静态方法即可打开或创建数据库,例如如下代码:
SQLiteDatabase.openOrCreateDatabase(“/mnt/db/temp.db3”,null);
上面的代码就用于打开或创建一个SQLite数据库,如果/mnt/db/目录下的temp.db3文件 (该文件就是一个数据库)存在,那么程序就是打开该数据库:如果该文件不存在,则上面的代码将会在该目录下创建temp.db3文件(即对应于数据库)。
上面的代码中没有指定SQLiteDatabase.CursorFactory参数,该参数是一个用于返回 Cursor的工厂,如果指定该参数为null,则意味着使用默认的工厂。
上面的代码即可返回一个SQLiteDatabase对象,该对象的execSQL可执行任意的SQL语句。
通过如下代码在程序中创建数据表:
//定义建表语句
create tabletb_news(
id integer primarykey autoincrement,
title varchar(100)not null,
content varchar(2000));
在程序中执行上面的代码即可在数据库中创建一个数据表。
正如前面提到的,SQLiteDatabase的execSQL方法可执行任意SQL语句,包括带占位符的SQL语句。但由于该方法没有返回值,一般用于执行DDL语句或DML语句;如果需要执行査询语句,则可调用SQLiteDatabase 的 rawQuery(String sql,String[] selectionArgs)方法。例如如下代码可用于执行DML语句,
//执行插入语句
String sql ="insert into tb_news(title,content,publishDate)values(?,?,?)";
db.execSQL(sql,new Object[]{news.getTitle(),news.getContent(),news.getPublishDate()});
提示:SQLite允许把各种类型的数据保存到任何类型字段中,开发者可以不用关心声明该字段所使用的数据类型。例如程序可以把字符串类型的值存INTEGER类型的字段中,也可以把数值类型的值存入布尔类型的字段中……但有一种情况例外:定义为INTEGERPRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数以外的其他类型的数据时,SQLite会产生错误。
由于SQLite允许存入数据时忽略底层数据列实际的数据类型,因此在编写建表语句时可以柯略数据列后面的类型声明,例如如下SQL语句对于SQLite也是正确的。
create table my_test
(_id integer primary key autoincrement,
name,pwd)
Android的SQLiteDatabase 提供了 insert、upate、delete或 query 语句来操作数据库。
1.使用insert方法插入记录
SQLiteDatabase 的 insert方法的签名为 longinsert (String table, String nullColumnHack, ContentValuesvalues),这个插入方法的参数说明如下。
table:代表想插入数据的表名。
nullColumnHack:代表强行插入null值的数据列的列名。
values:代表一行记录的数据。
insert方法插入的一行记录使用ComentValues存放,ContentValues类似于Map,它提供了 put<Stringkey,Xxxvalue>其中key为数据列的列名,该方法用于存入数据、getAsXxx(String key)方法用于取出数据。
例如如下语句:
ContentValues values = new ContentValues();
values.put ("name” , “孙悟空”);
values.put(“age”, 500);
//返回新添记录的行号,该行号是一个内部值,与主键1^1无关,发生铕误返回一1
long rowid = db.insert("person_in”,null,values);
不管第三个参数是否包含数据,执行insert()方法总会添加一条记录,如果第三个参数为空,会添加一条除主键之外其他宇段值都为null的记录。
insert()方法的底层实际上依然是通过构造insert SQL语句来进行插入的,因此它生成的 SQL语句总是形如下面的语句:
//ContentValue 里 key-value对的数值决定了下面的key-value对.
insert into <表名>(key1,key 2...) values(valuel , value2 ...)
此时如果第三个参数为null或其中key-value对的数量为0,由于insert方法还会按此方式生成一条insert语句,此时的insert语句为:
insert into <表名>()values()
上面的SQL语句显然有问题,为了满足SQL语法的需要,insert语句必须给定一个列名,如:insert intoperson(name)values(null),这个name列名就由第二个参数来指定。由此可见,当ComentValues为null或它包含的key-value对的数量为()时,第二个参数就会起作用了。
一般来说,第二个参数指定的列名不应该是主键列的列名,也不应该是非空列的列名,否则强行往这些数据列插入nul会引发异常。
2.使用update方法更新记录
SQLiteDatabase 的 update方法的签名为update(String table, ContentValues values, String whereClause, String[]whereArs),这个更新方法的参数说明如下:
table:代表想更新数据的表名。
values:代表想更新的数据。
whereClause:满足该whereClause子句的记录将会被更新。
whereArgs:用于为whereClause子句传入参数。
该方法返回受此update语句影响的记录的条数。
实例:
ContentValues values=new ContentValues();
values.put("title", news.getTitle());
values.put("content", news.getContent());
db.update("tb_news", values, "id=?",new String[]{String.valueOf(news.getId())});
3.使用delete方法删除记录
SQLiteDatabase 的 delete方法的签名为delete(String table , String whereClause, String[]whereArgs),这个删除的参数说明如下。
table:代表想删除数据的表名。
whereClause:满足该whereClause子句的记录将会被删除。
whereArgs:用于为whereClause子句传入参数。
该方法返回受此delete语句影响的记录的条数。
实例:
db=helper.getWritableDatabase();
db.execSQL("delete from tb_news where id=?",new String[]{String.valueOf(newsId)});
使用query方法查询记录
SQLiteDatabase 的 query方法的签名为 Cursorquery(boolean distinct, String table,String[]
columns, String selection, Stringl]selecrionArgs, String groupBy, String having. String orderBy, String limit),这个query方法的参数说明如下,
distinct:指定是否去除重复记录,
table:执行査询数据的表名。
columns:要査询出来的列名。相当于select语句select关键字后面的部分s
selection:査询条件子句,相当于select语句where关键字后面的部分,在条件子
句中允许使用占位符。
selectionArgs:用于为selection子句中占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
groupBy:用于控制分组?相当于select语句group by关键字后面的部分
having:用于对分组进行过滤。相当于select语句having关键字后面的部分
orderBy:用于对记录进行排序。相当于select语句order by关键字后面的部分,如:personid desc, age asc;
limit:用于进行分页,相当于select语句limit关键字后面的部分。
实例:
/**
*获取分页数据
*@param currentPage当前页码
*@param pageSize每页显示的数据量
*@return
*/
public List<News> getNewsByPage(int currentPage,int pageSize) {
db=helper.getReadableDatabase();
List<News>list=newArrayList<News>();
String start=String.valueOf((currentPage-1)*pageSize);
Cursor cursor=db.query(true,"tb_news",null,null,null,null,null,"id asc",start+","+String.valueOf(pageSize));
// String sql="select* from tb_news order by id asc limit ?,?";
// Cursorcursor=db.rawQuery(sql, new String[]{start,String.valueOf(pageSize)});
while(cursor.moveToNext()){
intid=cursor.getInt(cursor.getColumnIndex("id"));
Stringtitle=cursor.getString(cursor.getColumnIndex("title"));
Stringcontent=cursor.getString(cursor.getColumnIndex("content"));
StringdateString=cursor.getString(cursor.getColumnIndex("publishDate"));
Date publishDate=null;
try {
publishDate= Utils.convertStr2Date(dateString);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.add(new News(id, title,content, publishDate));
}
return list;
}
SQLiteDatabase中包含如下两个方法来控制事务。
beginTransaction():开始事务。
endTransaction():结束事务。
除此之外,SQLileDatabase还提供了如下方法来判断当前上下文是否处于事务环境中》
inTransaction():如果当前上下文处于事务中,则返回true:否则返回false。
当程序执行endTiansaction()方法时将会结束事务——那到底是提交事务呢,还是回滚事务呢?这取决于SQLiteDatabase是否调用了 setTransactionSuccessful()方法来设置事务标志, 如果程序事务执行中调用该方法设置了事务成功则提交事务,否则程序将会回滾事务。示例代码如下:
//事务处理
publicvoid tran(int id1,int id2,int des){
SQLiteDatabase db =helper.getWritableDatabase();
//按照这个语法格式写事务
db.beginTransaction();//开始事务
try{
db.execSQL("update tb_news set account=account - ? whereid=?",new Integer[]{des,id1});
// inti = 1 / 0;
db.execSQL("update tb_news set account=account + ? whereid=?",new Integer[]{des,id2});
db.setTransactionSuccessful();//设置事务成功标志
}finally{
db.endTransaction();//结束事务:看事务是否成功,如果则提交,如果失败则回滚
}
}
SQLiteOpenHelper是Android提供的一个管理数据库的工具类,可用于管理数据库的创建和版木更新。一般的用法是创建SQLiteOpenHelper的子类,并扩展它的onCreate (SQLiteDatabasedb)和 onUpgrade (SQLiteDatabasedb,intoldVersion,intnewVersion)方法。
SQLiteOpenHelper包含如下常用的方法。
synchronized SQLiteDatabase getReadableDatabase():以读写的方式打开数据库对应的SQLiteDatabase对象。
synchronized SQLiteDatabase getWritableDatabase():以写的方式打开数据库对应的 SQLiteDatabase 对象。
abstract void onCreate (SQLiteDatabase db):当第一次创建数据库时回调该方法。
abstract void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion):当数据库版本更新时回调该方法。
synchronized void close():关闭所有打开的SQLiteDatabase 。
从上面的方法介绍中不难看出,SQLiteOpenHelper提供了getReadableDatabase()、 getWritableDatabase()两个方法用于打开数据库连接,并提供了close方法来关闭数据库连接,而开发者需要做的就是重写它的两个抽象方法。
onCreate (SQLiteDatabase db):
用于初次使用软件时生成数据库表,当调用SQLiteOpenHelper的 getWritableDatabase()或者 getReadableDalabase()方法获取用于操作数据库的SQLiteDatabase实例时,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreateO方法,onCreateO方法在初次生成数据库时才会被调用,在onCreateO方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):
用于升级软件时更新数据库表结构,方法在数据库的版本发生变化时会被调用,该方法调用时oldVersion代表数据库之前的版本号,newVersion代表当前数据库当前的版本号。那么在哪里指定数据库的版本号呢?当程序创建SQLiteOpenHelper对象时,必须指定一个version参数,该参数就决定了所使用的数据库的版本——也就是说,数据库的版本是由程序员控制的。只要某次创建 SQLiteOpenHdper时指定的数据库版本号高于之前指定的版本号,系统就会自动触发 onUpgrade(SQLiteDatabase db, int oldVersion, int new Version)方法,程序就可以在onUpgrade()方法里面根据原版号和目标版本号进行判断,即可根据版本号进行必需的表结构更新。
提示:实际上,当应用程序升级表结构时,完全可能因为已有的数据导致升级失败,在这种时候程序可能需要先对数据进行转姑,清空数据表中的记录,接着对数据!表进行更新,当教据表更新完成后再将教据保存回来。
一旦得到了SQLiteOpenHelper对象之后,程序无须使用SQLiteDatabase的静态方法创建SQLiteDatabase 实例,而且可以使用getWritableDatabase()或 getReadableDatabase()方法来获取一个用于操作数据库的SQLiteDatabase实例。
其中getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。 getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失敗后会继续尝试以只读方式打开数据库。
请尊重他人的劳动成果,转载请注明出处:Android开发之SQLite数据库详解
http://blog.csdn.net/fengyuzhengfan/article/details/40194393
原文地址:http://blog.csdn.net/fengyuzhengfan/article/details/40194393