【幻化万千戏红尘】qianfeng-Android-Day13_SQLiteDataBases
SQLiteDatabase
一、SQLite:
(一)、简介:
除了可以使用文件或SharedPreferences存储数据,还可以选择使用SQLite数据库存储数据。 在Android平台上,集成了一个嵌入式关系型数据库——SQLite。
SQLite3支持 NULL、INTEGER、REAL(浮点数字)、TEXT(字符串文本)和BLOB(二进制对象)等五种数据类型; 虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)、char(n)、decimal(p,s) 等数据类型。
(二)、SQLite数据库的特点:
Android通过 SQLite 数据库引擎来实现结构化数据的存储。在一个数据库应用程序中,任何类都可以通过名字对已经创建的数据库进行访问,但是在应用程序之外就不可以。
SQLite 数据库是一种用C语言编写的嵌入式数据库,它是一个轻量级的数据库,最初为嵌入式设计的。它是在一些基础简单的语句处理上要比oracle / mysql快很多,而且其对内存的要求很低,在内存中只需要几百KB的存储空间。这是Android中采用 SQLite 数据库的主要原因。
SQLite 支持事务处理功能。Transaction
SQLite 处理速度比MySQL等著名的开源数据库系统更快。它没有服务器进程。
SQLite 通过文件保存数据库,该文件是跨平台的,可以自由复制。一个文件就是一个数据库。数据库名即文件名。
JDBC会消耗太多系统资源,所以JDBC对于手机并不合适,因此Android提供了新的API来使用 SQLite 数据库。
SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。 例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。
【备注:】SQLite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息,如下面语句会忽略 name字段的类型信息:
CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))
二、SQLiteDatabase类:
SQLiteDatabase等同于JDBC中Connection和Statement的结合体。SQLiteDatabase既代表与数据库的连接,又只能用于执行sql语句操作。
(一)、操作 SQLite 数据库的步骤:【重要】
1、创建 SQLiteDatabase 对象,它代表与数据库的连接;
2、创建数据库中的表(执行CREATE);
3、调用SQLiteDatabase 对象执行数据库操作(执行DML);
4、对查询后的结果集Cursor进行处理。
(二)、操作 SQLite 数据库的步骤详细讲解:
1.SQLite的数据类型?
首先你会接触到一个让你惊讶的名词: Typelessness(无类型)。其实SQLite是无类型的。这意味着你可以保存任何类型的数据到数据库表的任何列中, 无论这列声明的数据类型是什么。对于SQLite来说对字段不指定类型是完全有效的。如:
create table dict(_id integer primary key autoincrement , word ,detail);
注意:这里一定要注意,SQLite数据库在一种情况下是要求类型匹配的,当我们建表是如create table table1(id integer primary key),sqlite对应一位integer primary key的列值允许你存储64位的整数。必须是INTEGER PRIMARY KEY AUTOINCREMENT。
诚然SQLite允许忽略数据类型, 但是仍然建议在你的Create Table语句中指定数据类型. 因为数据类型对于你和其他的程序员交流, 或者你准备换掉你的数据库引擎时能起到一个提示或帮助的作用。
2.调用SQLiteDatabase 对象的方法执行数据库操作:【重要】
execSQL(String sql , Object[] args) 执行带占位符的sql语句(update,insert,delete语句)
rawQuery( String sql , String[] args ) 执行带占位符的sql查询(select语句)
beginTransaction() 开始事务
endTransaction() 结束事务
【备注:】除了以上重要的四个方法外,Android考虑到不熟悉sql语句的开发者,提供了进一步封装后的一系列方法。但是以下这几个方法参数众多,但是一定也要掌握,在ContentProvider中会有类似的方法,要注意区分。
private void select6() {
// 1.是否去重
// 2.要查询的表名称
// 3.表示要查询的列名称,null表示查询所有列
// 4.表示查询条件
// 5.查询条件的值
// 6.分组的列
// 7.分组条件
// 8.排序的列
// 9.查询的数目
// 10.取消标记
Cursor query = db.query(true, DBHelper.USERTABLE, null, "username=?", new String[] { "zhangsan" }, null, null,
null, null, null);
while (query.moveToNext()) {
String id = query.getString(0);
String username = query.getString(1);
Log.d("qianfeng", "id:" + id + ";username:" + username);
}
}
private void update() {
// 调用update方法更新数据
ContentValues values = new ContentValues();
values.put("NICKNAME", "王五");
db.update(DBHelper.USERTABLE, values, "username=? and _id=?", new String[] { "zhangsan", "13" });
}
private void delete() {
// 调用delete方法删除数据,第一个参数表示要操作的表的名称,第二个参数表示删除条件,第三个参数表示条件的值
db.delete(DBHelper.USERTABLE, "_id=?", new String[] { "10" });
}
private void insert() {
// 使用ContentValues插入数据
ContentValues values = new ContentValues();
values.put("username", "lisi");
values.put("password", "777");
values.put("nickname", "李四");
// 第一个参数表示表名
// 第二个参数表示当插入数据为空时,系统默认给某一个字段设置值为null,以使数据可以插入成功
// 第三个参数表示要插入的数据
// 返回值表示插入数据的id,返回-1表示插入失败
long insert = db.insert(DBHelper.USERTABLE, null, values);
}
3、对查询结果进行操作。
当执行的是select语句,返回一个Cursor对象。Cursor类似于JDBC中的ResultSet结果集,内置移动游标等方法:
move(int offset) 按偏移量来移动
moveToFirst() 将记录指针移动到第一行
moveToLast () 将记录指针移动到最后一行
moveToNext () 将记录指针移动到下一行
moveToPosition(int position) 将记录指针移动到指定的一行
moveToPrevious() 将记录指针移动到上一行
getCount() 返回Cursor的行数
getColumnName(int index) 根据列的索引返回其相应的列名称
getColumnIndex(String name) 根据列的名字返回其相应的索引
getColumnNames() 返回一个保存有所有列名称的字符串数组
getColumnCount() 返回列的总数
close() 关闭游标结果集,释放资源
getType() 获取字段的数据类型。分别有0、1、2、3、4这几个结果。
0: 代表null
1:代表int
2:代表float
3:代表String
4:代表blob
示例代码:
Cursor cursor = db.rawQuery("select * from " + DBHelper.USERTABLE + " where username=?",
new String[] { "zhangsan" });
while (cursor.moveToNext()) {
String id = cursor.getString(0);
String username = cursor.getString(cursor.getColumnIndex("USERNAME"));
Log.d("qianfeng", "id:" + id + ";username:" + username);
}
(三)、事务:【重要】
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完整地执行,要么完全地不执行。事务的目的是为了保证数据的一致性。 事务通过回滚(RollBack)保存了数据了一致性。
例如:
设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:
一、更新客户所购商品的库存信息
二、保存客户付款信息--可能包括与银行系统的交互
三、生成订单并且保存到数据库中
四、更新用户相关信息,例如购物数量等等
正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。
数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术。
使用SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果程序执行到endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,如果没有调用setTransactionSuccessful() 方法则回滚事务。使用例子如下:
SQLiteDatabase db = ....;
db.beginTransaction();//开始事务
try {
db.execSQL("insert into person(name, age) values(?,?)", new Object[]{"千锋", 4});
db.execSQL("update person set name=? where personid=?", new Object[]{"千锋", 1});
db.setTransactionSuccessful();//调用此方法会在执行到endTransaction() 时提交当前事务,如果不调用此方法会回滚事务
} finally {
db.endTransaction();//由事务的标志决定是提交事务,还是回滚事务
}
db.close();
上面两条SQL语句在同一个事务中执行。