SQLite数据库,和其他的SQL数据库不同, 我们并不需要在手机上另外安装一个数据库软件,Android系统已经集成了这个数据库。
SQLite有什么特点
SQlite通过文件来保存数据库,一个文件就是一个数据库,数据库中又包含多个表格,表格里又有 多条记录,每个记录由多个字段构成,每个字段有对应的值,每个值我们可以指定类型,也可以不指定 类型(主键除外)
为什么要用SQLite:
SP是一种轻量级数据存储方式,存储一些跟账号密码个人信息相关的数据,如果数据繁杂这时候就要用到SQLite存储以提高数据存取得效率。
几个相关的类:
SQLiteOpenHelper
:抽象类,我们通过继承该类,然后重写数据库创建以及更新的方法, 我们还可以通过该类的对象获得数据库实例,或者关闭数据库!
SQLiteDatabase:数据库访问类:我们可以通过该类的对象来对数据库做一些增删改查的操作
Cursor:游标,有点类似于JDBC里的resultset,结果集!可以简单理解为指向数据库中某 一个记录的指针!可以通过Cursor对数据进行一行一行查询的操作
使用SQLiteOpenHelper类创建数据库与版本管理
安卓给我们提供了SQLiteOpenHelper的两个方法, onCreate( )与onUpgrade( )来实现
onCreate(database)
:首次使用软件时生成数据库表
onUpgrade(database,oldVersion,newVersion)
:在数据库的版本发生变化时会被调用, 一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的 版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望 更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2 或者其他与旧版本号不同的数字即可!
public class MyDBOpenHelper extends SQLiteOpenHelper {
public MyDBOpenHelper(Context context, String name, CursorFactory factory,
int version) {super(context, "my.db", null, 1); }
@Override
//数据库第一次创建时被调用
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE person(personid INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20))");
}
//软件版本号发生改变时调用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD phone VARCHAR(12) NULL");
}
}
我们会创建这个my.db的文件,并且会执行onCreate()里的方法, 创建一个Person的表,他又两个字段,主键personId和name字段;接着如我我们修改db的版本 号,那么下次启动就会调用onUpgrade()里的方法,往表中再插入一个字段!另外这里是插入 一个字段,所以数据不会丢失,如果是重建表的话,表中的数据会全部丢失(下面数据库更新解决)
流程:
Step 1:自定义一个类继承SQLiteOpenHelper类
Step 2:在该类的构造方法的super中设置好要创建的数据库名,版本号
Step 3:重写onCreate( )方法创建表结构
Step 4:重写onUpgrade( )方法定义版本号发生改变后执行的操作
使用Android提供的API操作SQLite
db = myDBHelper.getWritableDatabase();
switch (v.getId()) {
case R.id.btn_insert:
ContentValues values1 = new ContentValues();
values1.put("name", "呵呵~" + i);
i++;
//参数依次是:表名,强行插入null值得数据列的列名,一行记录的数据
db.insert("person", null, values1);
Toast.makeText(mContext, "插入完毕~", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_query:
sb = new StringBuilder();
//参数依次是:表名,列名,where约束条件,where中占位符提供具体的值,指定group by的列,进一步约束
//指定查询结果的排序方式
Cursor cursor = db.query("person", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
sb.append("id:" + pid + ":" + name + "\n");
} while (cursor.moveToNext());
}
cursor.close();
Toast.makeText(mContext, sb.toString(), Toast.LENGTH_SHORT).show();
break;
case R.id.btn_update:
ContentValues values2 = new ContentValues();
values2.put("name", "嘻嘻~");
//参数依次是表名,修改后的值,where条件,以及约束,如果不指定三四两个参数,会更改所有行
db.update("person", values2, "name = ?", new String[]{"呵呵~2"});
break;
case R.id.btn_delete:
//参数依次是表名,以及where条件与约束
db.delete("person", "personid = ?", new String[]{"3"});
break;
}
使用SQL语句操作数据库
不想用Android提供的这些API, 你可以直接使用SQLiteDatabase给我们提供的相关方法:
execSQL(SQL,Object[]):使用带占位符的SQL语句,这个是执行修改数据库内容的sql语句用的
rawQuery(SQL,Object[]):使用带占位符的SQL查询操作 另外前面忘了介绍下Curosr这个东西以及相关属性,这里补充下: ——
Cursor:对象有点类似于JDBC中的ResultSet,结果集!使用差不多,提供一下方法移动查询结果的记录指针:
move(offset):指定向上或者向下移动的行数,整数表示向下移动;负数表示向上移动!
moveToFirst():指针移动到第一行,成功返回true,也说明有数据
moveToLast():指针移动到最后一样,成功返回true;
moveToNext():指针移动到下一行,成功返回true,表明还有元素!
moveToPrevious():移动到上一条记录
getCount( )获得总得数据条数
isFirst():是否为第一条记录
isLast():是否为最后一项
moveToPosition(int):移动到指定行
使用代码示例:
//插入数据
public void save(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("INSERT INTO customer(customerName,deliveryPhone) values(?,?)",new String[]{customer.getCustomerName(),customer.getDeliveryPhone()});
}
//删除数据
public void delete(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("DELETE FROM customer WHERE customerid=?",new Integer[]{customerid});
}
//更新数据
public void updata(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("UPDATA customer SET customerName=?,deliveryPhone=? WHERE customerid=?",new String[]{customer.getCustomerName(),customer.getDeliveryPhone(), String.valueOf(customer.getCustomerId())});
}
//查询数据
public Customer select(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT * FROM customer WHERE customerid=?",new String[]{customerid.toString()});
//存在数据才返回true
if(cursor.moveToFirst()){
int id=cursor.getInt(cursor.getColumnIndex("customerid"));
String name=cursor.getString(cursor.getColumnIndex("customerName"));
String phone=cursor.getString(cursor.getColumnIndex("deliveryPhone"));
return new Customer(id,name,phone);
}
cursor.close();
return null;
}
//.数据分页查询
public List<Customer> getScrollData(int offset, int maxResult)
{
List<Customer> person = new ArrayList<Customer>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM person ORDER BY personid ASC LIMIT= ?,?",
new String[]{String.valueOf(offset),String.valueOf(maxResult)});
while(cursor.moveToNext())
{
int id = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
person.add(new Customer(id,name,phone)) ;
}
cursor.close();
return person;
}
//查询记录数
public long getCount()
{
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT COUNT (*) FROM customer",null);
cursor.moveToFirst();
long result = cursor.getLong(0);
cursor.close();
return result;
}
public void save(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("INSERT INTO customer(customerName,deliveryPhone) values(?,?)",new String[]{customer.getCustomerName(),customer.getDeliveryPhone()});
}
//删除数据
public void delete(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("DELETE FROM customer WHERE customerid=?",new Integer[]{customerid});
}
//更新数据
public void updata(Customer customer){
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
sqLiteDatabase.execSQL("UPDATA customer SET customerName=?,deliveryPhone=? WHERE customerid=?",new String[]{customer.getCustomerName(),customer.getDeliveryPhone(), String.valueOf(customer.getCustomerId())});
}
//查询数据
public Customer select(Integer customerid){
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT * FROM customer WHERE customerid=?",new String[]{customerid.toString()});
//存在数据才返回true
if(cursor.moveToFirst()){
int id=cursor.getInt(cursor.getColumnIndex("customerid"));
String name=cursor.getString(cursor.getColumnIndex("customerName"));
String phone=cursor.getString(cursor.getColumnIndex("deliveryPhone"));
return new Customer(id,name,phone);
}
cursor.close();
return null;
}
//.数据分页查询
public List<Customer> getScrollData(int offset, int maxResult)
{
List<Customer> person = new ArrayList<Customer>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM person ORDER BY personid ASC LIMIT= ?,?",
new String[]{String.valueOf(offset),String.valueOf(maxResult)});
while(cursor.moveToNext())
{
int id = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
person.add(new Customer(id,name,phone)) ;
}
cursor.close();
return person;
}
//查询记录数
public long getCount()
{
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT COUNT (*) FROM customer",null);
cursor.moveToFirst();
long result = cursor.getLong(0);
cursor.close();
return result;
}
除了上面获取条数的方法外还可以使用cursor.getCount()方法获得数据的条数, 但是SQL语句要改改!比如SELECT * FROM customer;
SQLite事务
多个操作捆绑在一起,只有所有操作都执行完毕,事务才会生效,如果其中有一个操作未执行完毕,之前所有操作都会撤销。
方法:
beginTransaction():开启事务
endTransaction():结束事务
setTransactionSuccessful():结束事务有两张方式,事务回滚或者事务 提交,默认为false撤销,如果提交设置为true.
简单点说就是:写在事务里的所有数据库操作都成功,事务提交,否则,事务回滚到原始状态
SQLite存储大二进制文件
一般我们很少往数据库中存储大二进制文件,比如图片,音频,视频等,对于这些我们一般 是存储文件路径,但总会有些奇葩的需求。以图片为例子,将图片保存到SQLite中,以及读取SQLite中的图片!
1.保存图片到Sqlite中:
(1)创建数据库表的时候,需要创建一个BLOB的字段,用于存储二进制值。
sqLiteDatabase.execSQL("CREATE TABLE test(_id INTEGER PRIMARY KEY AUTOINCREAMENT,head_img BLOB)");
(2)将图片转换成BLOB格式(这里是ImageView为例,如果是普通图片只需要转换成Bitmap再调用即可)
try {
SQLiteDatabase sqLiteDatabase=dbHelper.getWritableDatabase();
ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
//压缩为PNG格式,100标示跟原图大小一致
(BitmapDrawable)imageView.getDrawable().getBitmap().compress(Bitmap.CompressFormat.PNG,100,byteArrayOutputStream);
Object[] objects=new Object[]{byteArrayOutputStream.toByteArray()};
sqLiteDatabase.execSQL("INSERT INTO test(head_img) values(?)",objects);
byteArrayOutputStream.close();
sqLiteDatabase.close();
} catch (IOException e) {
e.printStackTrace();
}
读取SQLite中的图片
//读取SQLIte中的图片
SQLiteDatabase sqLiteDatabase=dbHelper.getReadableDatabase();
Cursor cursor=sqLiteDatabase.rawQuery("SELECT head_img FROM text",null);
if(cursor!=null){
if(cursor.moveToFirst()){
//取出图片保存到字节数组中
byte[] img=cursor.getBlob(cursor.getColumnIndex("head_img"));
//将图片显示到Imageview上面
if(img!=null){
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(img);
imageView.setImageDrawable(Drawable.createFromStream(byteArrayInputStream,"img"));
}
}
cursor.close();
}
数据库升级
假如我们已经升级到第三个版本了,我们在第二个版本增加了一个表,
然后第三个版本也增加了一个表,加入用户直接从第一个版本升级到第三个版本,这样
没经过第二个版本,就没有增加的那个表,这可怎么破?
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
upgrade(db, oldVersion, newVersion);
}
private void upgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion) {
if (oldVersion + 1 == newVersion) {
switch (oldVersion) {
case 1:
upgrade1_2(db);
break;
case 2:
upgrade2_3(db);
break;
case 3:
upgrade3_4(db);
case 4:
upgrade4_5(db);
case 5:
upgrade5_6(db);
case 6:
upgrade6_7(db);
case 7:
upgrade7_8(db);
case 8:
upgrade8_9(db);
default:
break;
}
return;
}
upgrade(db, oldVersion, newVersion - 1);
upgrade(db, newVersion - 1, newVersion);
}
}
private void upgrade1_2(SQLiteDatabase db) {
String sql = "drop table storage;";
db.execSQL(sql);
db.execSQL(storageSQL);
}