快捷搜索:

Android应用开发入门(三十三)数据持久化之SQL

媒介

对付一个利用法度榜样而言,数据持久化是必弗成少的,Android法度榜样也不例外。这篇博客将先容Android中关于SQLite的应用,SQLite是一种嵌入式的数据库引擎,专门适用于资本有限的设备长进行适量的数据存储,而Android就周全支持标准的SQLite数据库。在本片博客中,将阐明SQLite数据库的创建以及掩护,还有应用SQLite履行CRUD的两种要领,以及SQLite中事务的应用,着末都邑应用示例解说文章中所提到的观点性的内容。

SQLite

Android对SQLite数据库,供给了完全的支持,而所有创建的SQLite数据库,仅限于当前利用造访,假如其他利用必要造访,则必须供给的Content Provider的支持,并且SQLite数据库会跟着Android利用的卸载而被删除。SQLite是一个嵌入式的数据库引擎,着末因此文件的形式保存数据的。从本色上来看,SQLite的操作要领只是一种更为便捷的文件操作,当利用法度榜样创建或打开一个SQLite数据库时,着实只是打开一个文件筹备读写。由于SQLite仅适用于资本有限的小型设备,以是本身就不应该把大年夜量数据存储在设备的SQLite数据库里,SQLite只得当存储一些小型的数据。

为了使SQLite和其他数据库间的兼容性最大年夜化,SQLite支持对列上类型进行“类型近似”,列的类型近似指的是存储在列上的数据进行保举类型存储。以是虽然SQLite内部只支持NULL、INTEGER、REAL(浮点书)、TEXT(文本)和BLOB(大年夜二进制工具)这五种数据类型,但实际上SQLite完全可以吸收varchar(n)、char(n)、decimal(p,s)、date等类型数据,只不过SQLite会在运算或保存时将它们转换为上面五种数据类型中响应的类型。大年夜多半数据库的引擎都是应用静态的、强类型的数据类型,数据的类型是由它的容器抉择的,这个容器是指被寄放的特定列。而SQLite应用的是动态类型,在SQLite中,值的数据类型跟值本身相关,而不是与它的容器相关,以是SQLite容许把各类类型的数据保存到任何类型字段中,开拓者可以不用关心声明该字段说应用的数据类型。然则有一种环境例外,定义为INTEGER PRIMARY KEY的字段只能存储64位整数,当向这种字段保存除整数意外的其他类型的数据时,SQLite会孕育发生差错。

SQLite数据库创建与掩护

从官方文档上懂得到,在Android项目中,创建SQLite数据库保举承袭SQLiteOpenHelper类,然后重写此中的onCreate()措施,在onCreate()措施中,对履行数据库创建的SQL语句。而SQLiteOpenHelper不仅仅用于SQLite数据的创建,还可以对其进行掩护,以及得到SQLiteDatabase这个数据库操作对象。

SQLiteOpenHelper供给了两个构造器,用于通报当前高低文工具以及SQLite数据库版本信息,在SQLiteOpenHelper的承袭类的构造函数中,会调用它,构造器的署名如下:

SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version).

SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactroy factory,int version,DatabaseErrorHandler errorHandler).

上面的构造函数中,都是用于创建一个SQLite数据库,context为一个当前利用的高低文工具;name是数据库名称;factory是一个容许子类在查询时应用的游标,一样平常不用传Null;version是数据库版本号;errorHandler是一个接口,通报当数据库差错的时刻,履行的解救措施。

在SQLiteOpenHelper中,可以进行SQLite数据库的创建、掩护、日志以及获取可读写的数据库工具,经由过程下面几个常用措施获得支持:

String getDatabaseName():获取数据库名。

SQLiteDatabase getReadableDatabase():创建或者打开一个可读的数据库工具。

SQLiteDatabase getWritableDatabase():创建或者打开一个可读/写的数据库工具。

abstract void onCreate(SQLiteDatabase db):当第一次调用SQLiteOpenHelper的时刻履行,之后再次调用将不再履行,一样平常用于完成数据库初始化的事情。

void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向上更新时,被履行。

void onDowngrade(SQLiteDatabase db,int oldVersion,int newVersion):当数据库版本号发生向下更新时,被履行。

下面供给一个简单的SQLiteOpenHelper的承袭类代码,用于创建数据库以及表布局:

package com.example.sqlitedbdemo.db;

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;

public class DbOpenHelper extends SQLiteOpenHelper {

private static String name = "mydb.db";private static int version = 1;

public DbOpenHelper(Context context) {

super(context, name, null, version);}

@Override

public void onCreate(SQLiteDatabase db) {// 只能支持基础数据类型

String sql = "create table person(id integer primary key autoincrement,name varchar(64),address varchar(64))";db.execSQL(sql);

}@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub

String sql="alter table person add sex varchar(8)";db.execSQL(sql);

}}

Tips:当创建好SQLite数据库的之后,可以在/data/data/

/databases目录下找到SQLite数据库文件。

履行CRUD操作

当应用SQLiteOpenHelper的getReadableDatabase()或者getWritableDatabase()措施获取到SQLiteDatabase工具,就可以对这个数据库进行操作了。

对付认识SQL语句的开拓者而言,着实只必要应用两个措施,即可履行所有CRUD操作,以下措施供给多个重载措施:

void execSQL():经由过程SQL语句履行一条非查询语句。

Cursor rawQuery():经由过程SQL语句履行一条查询语句。

下面以一个示例解说一下纯真应用SQL语句实现CRUD操作:

接口代码:

package com.examle.sqlitedbdemo.service;

import java.util.List;

import java.util.Map;

public interface PersonService {

public boolean addPerson(Object[] params);public boolean deletePerson(Object[] params);

public boolean updatePerson(Object[] params);public Map viewPerson(String[] selectionArgs);

public List> listPersonMaps(String[] selectionArgs);}

接口的实今世码:

package com.examle.sqlitedbdemo.dao;

import java.util.ArrayList;

import java.util.HashMap;import java.util.List;

import java.util.Map;

import android.content.Context;import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import com.examle.sqlitedbdemo.service.PersonService;import com.example.sqlitedbdemo.db.DbOpenHelper;

public class PersonDao implements PersonService {

private DbOpenHelper helper = null;

public PersonDao(Context context) {helper = new DbOpenHelper(context);

}

@Overridepublic boolean addPerson(Object[] params) {

boolean flag = false;SQLiteDatabase database = null;

try {// insert一条数据

String sql = "insert into person(name,address,sex) values(?,?,?)";database = helper.getWritableDatabase();

// 履行SQLdatabase.execSQL(sql, params);

flag = true;} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {// finally中关闭数据库

database.close();}

}return flag;

}

@Overridepublic boolean deletePerson(Object[] params) {

boolean flag = false;SQLiteDatabase database = null;

try {// 删除一条数据

String sql = "delete from person where id=?";database = helper.getWritableDatabase();

database.execSQL(sql, params);flag = true;

} catch (Exception e) {e.printStackTrace();

} finally {if (database != null) {

database.close();}

}return flag;

}

@Overridepublic boolean updatePerson(Object[] params) {

boolean flag = false;SQLiteDatabase database = null;

try {// 更新一条数据

String sql = "update person set name=?,address=?,sex=? where id=?";database = helper.getWritableDatabase();

// 履行SQLdatabase.execSQL(sql, params);

flag = true;} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {database.close();

}}

return flag;}

@Override

public Map viewPerson(String[] selectionArgs) {Map map = new HashMap();

SQLiteDatabase database = null;try {

// 查询单笔记录String sql = "select * from person where id=?";

// 以只读的形式打开数据库database = helper.getReadableDatabase();

// 履行SQL语句,返回一个游标Cursor cursor = database.rawQuery(sql, selectionArgs);

int colums = cursor.getColumnCount();

while (cursor.moveToNext()) {for (int i = 0; i

String cols_name = cursor.getColumnName(i);String cols_value = cursor.getString(cursor

.getColumnIndex(cols_name));if (cols_value == null) {

cols_value = "";}

map.put(cols_name, cols_value);}

}} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {database.close();

}}

return map;}

@Override

public List> listPersonMaps(String[] selectionArgs) {List> list = new ArrayList>();

String sql = "select * from person";SQLiteDatabase database = null;

try {database = helper.getReadableDatabase();

Cursor cursor = database.rawQuery(sql, selectionArgs);int colums = cursor.getColumnCount();

while (cursor.moveToNext()) {Map map = new HashMap();

for (int i = 0; iString cols_name = cursor.getColumnName(i);

String cols_value = cursor.getString(cursor.getColumnIndex(cols_name));

if (cols_value == null) {cols_value = "";

}map.put(cols_name, cols_value);

}list.add(map);

}} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {database.close();

}}

return list;}

}

再写一个测试类测试这个数据操作类是否有效,Android下JUnit的设置设置设备摆设摆设拜见别的一篇博客:Android--JUnit单元测试:

package com.example.sqlitedbdemo.db;

import java.util.List;

import java.util.Map;

import com.examle.sqlitedbdemo.dao.PersonDao;import com.examle.sqlitedbdemo.service.PersonService;

import android.test.AndroidTestCase;

import android.util.Log;

public class TestDb extends AndroidTestCase {private final String TAG = "main";

public TestDb() {

// TODO Auto-generated constructor stub}

public void createDB() {

DbOpenHelper helper = new DbOpenHelper(getContext());helper.getWritableDatabase();

}

public void insertDb() {PersonService service = new PersonDao(getContext());

Object[] params1 = { "张龙", "beijing", "male" };boolean flag = service.addPerson(params1);

Object[] params2 = { "赵虎", "shanghai", "male" };flag = flag&&service.addPerson(params2);

Object[] params3 = { "王朝", "HK", "male" };flag = flag&&service.addPerson(params3);

Object[] params4 = { "马汉", "beijing", "female" };flag = flag&&service.addPerson(params4);

Log.i(TAG, "-----插入数据----->>" + flag);}

public void deleteDb() {

PersonService service = new PersonDao(getContext());Object[] params = { 1 };

boolean flag = service.deletePerson(params);Log.i(TAG, "-----删除数据----->>" + flag);

}

public void updateDb() {PersonService service=new PersonDao(getContext());

Object[] params = { "张三", "上海", "男","2" };boolean flag=service.updatePerson(params);

Log.i(TAG, "---------->>" + flag);}

public void getDb(){

PersonService service=new PersonDao(getContext());Map map = service.viewPerson(new String[]{"2"});

Log.i(TAG, "---------->>" + map.toString());}

public void listDb() {

PersonService service = new PersonDao(getContext());List> list = service.listPersonMaps(null);

Log.i(TAG, "---------->>" + list.toString());}

}

insertDB()后,假如是在模拟器上调试,可以应用FIle Explorer对象导出mydb.db文件,应用SQLite Expert Professional(这是一个SQLite的治理软件,博客着末供给下载地址),打开数据库:

履行deleteDb()删除第一条数据:

履行updateDb()更新第二条数据:

履行getDb(),查询第二条数据,履行listDb(),查询整个数据,查看日志输出:

而假如是从事Android开拓,还有需要懂得别的一种操作SQLite的要领,应用SQLiteDatabase所供给的措施实现CRUD操作。主要有以下几个措施:

long insert(String table ,String nullColumnHack,ContentValues values):插入一条数据。

int delete(String table ,String whereCaluse,String[] whereArgs):根据前提,删除数据。

int updata(String table,ContentValues values,String whereCaluse,String[] whereArgs):根据前提,更新数据

Cursor query(...):根据前提,查询数据。供给多种重载措施,主要查询不合的前提。

下面以一个示例法度榜样解说一下应用SQLiteDatabase所供给的措施实现CRUD操作:

接口代码:

package com.examle.sqlitedbdemo.service;

import java.util.List;

import java.util.Map;

import android.content.ContentValues;

public interface PersonService2 {

public boolean addPerson(ContentValues values);

public boolean deletePerson(String whereClause, String[] whereArgs);

public boolean updatePerson(ContentValues values, String whereClause,String[] whereArgs);

public Map viewPerson(String selection,

String[] selectionArgs);

public List> listPersonMaps(String selection,String[] selectionArgs);

}

实今世码:

package com.examle.sqlitedbdemo.dao;

import java.util.ArrayList;

import java.util.HashMap;import java.util.List;

import java.util.Map;

import android.content.ContentValues;import android.content.Context;

import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;

import com.examle.sqlitedbdemo.service.PersonService2;

import com.example.sqlitedbdemo.db.DbOpenHelper;

public class PersonDao2 implements PersonService2 {private DbOpenHelper helper = null;

public PersonDao2(Context context) {

helper = new DbOpenHelper(context);}

@Override

public boolean addPerson(ContentValues values) {boolean flag = false;

SQLiteDatabase database = null;long id = -1;

try {database = helper.getWritableDatabase();

// 履行insert,返回当前行IDid = database.insert("person", null, values);

flag = (id != -1 ? true : false);} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {database.close();

}}

return flag;}

@Override

public boolean deletePerson(String whereClause, String[] whereArgs) {boolean flag = false;

SQLiteDatabase database = null;int count = 0;

try {database = helper.getWritableDatabase();

// 履行删除操作,返回影响行数count = database.delete("person", whereClause, whereArgs);

flag = (count > 0 ? true : false);} catch (Exception e) {

e.printStackTrace();} finally {

if (database != null) {database.close();

}}

return flag;}

@Override

public boolean updatePerson(ContentValues values, String whereClause,String[] whereArgs) {

boolean flag = false;SQLiteDatabase database = null;

int count = 0;try {

database = helper.getWritableDatabase();// 履行更新操作,返回影响行数

count = database.update("person", values, whereClause, whereArgs);flag = (count > 0 ? true : false);

} catch (Exception e) {e.printStackTrace();

} finally {if (database != null) {

database.close();}

}return flag;

}

@Overridepublic Map viewPerson(String selection,

String[] selectionArgs) {SQLiteDatabase database = null;

Cursor cursor = null;Map map = new HashMap();

try {database = helper.getReadableDatabase();

// 设置查询前提cursor = database.query(true, "person", null, selection,

selectionArgs, null, null, null, null);int cols_len = cursor.getColumnCount();

while (cursor.moveToNext()) {for (int i = 0; i

String cols_key = cursor.getColumnName(i);String cols_value = cursor.getString(cursor

.getColumnIndex(cols_key));if (cols_value == null) {

cols_value = "";}

map.put(cols_key, cols_value);}

}} catch (Exception e) {

e.printStackTrace();}

return map;}

@Override

public List> listPersonMaps(String selection,String[] selectionArgs) {

List> list = new ArrayList>();SQLiteDatabase database = null;

Cursor cursor = null;try {

database = helper.getReadableDatabase();cursor = database.query(false, "person", null, selection,

selectionArgs, null, null, null, null);int cols_len = cursor.getColumnCount();

while (cursor.moveToNext()) {Map map = new HashMap();

for (int i = 0; iString cols_key = cursor.getColumnName(i);

String cols_value = cursor.getString(cursor.getColumnIndex(cols_key));

if (cols_value == null) {cols_value = "";

}map.put(cols_key, cols_value);

}list.add(map);

}} catch (Exception e) {

e.printStackTrace();}

return list;}

}

着末和上面一下,创建一个测试类来测试这个数据库操作:

package com.example.sqlitedbdemo.db;

import java.util.List;

import java.util.Map;

import com.examle.sqlitedbdemo.dao.PersonDao2;import com.examle.sqlitedbdemo.service.PersonService2;

import android.content.ContentValues;

import android.test.AndroidTestCase;import android.util.Log;

public class TestDb2 extends AndroidTestCase {

private final String TAG = "main";

public TestDb2() {// TODO Auto-generated constructor stub

}

public void addPerson() {PersonService2 service2 = new PersonDao2(getContext());

ContentValues values1 = new ContentValues();values1.put("name", "张龙");

values1.put("address", "beijing");values1.put("sex", "male");

boolean flag = service2.addPerson(values1);ContentValues values2 = new ContentValues();

values2.put("name", "赵虎");values2.put("address", "shanghai");

values2.put("sex", "male");flag = flag&&service2.addPerson(values2);

ContentValues values3 = new ContentValues();values3.put("name", "王朝");

values3.put("address", "HK");values3.put("sex", "male");

flag = flag&&service2.addPerson(values3);ContentValues values4 = new ContentValues();

values4.put("name", "王朝");values4.put("address", "HK");

values4.put("sex", "male");flag = flag&&service2.addPerson(values4);

Log.i(TAG, "----------->>" + flag);}

public void deletePerson() {

PersonService2 service2 = new PersonDao2(getContext());boolean flag = service2.deletePerson(" id =?", new String[]{"1"});

Log.i(TAG, "----------->>" + flag);}

public void updatePerson(){

PersonService2 service2 = new PersonDao2(getContext());ContentValues values = new ContentValues();

values.put("name", "张三");values.put("address", "上海");

values.put("sex", "男");boolean flag=service2.updatePerson(values, " id=? ", new String[]{"2"});

Log.i(TAG, "----------->>" + flag);}

public void viewPerson(){

PersonService2 service2 = new PersonDao2(getContext());Map map=service2.viewPerson(" id=? ", new String[]{"2"});

Log.i(TAG, "----------->>" + map.toString());}

public void listPerson(){PersonService2 service2 = new PersonDao2(getContext());

List> list=service2.listPersonMaps(null,null);Log.i(TAG, "----------->>" + list.toString());

}}

实现的功能和上面一样,这里就不展示效果图了,然则由于是上面两种操作数据库的要领是在一个利用中完成的,并且数据一样,履行第二个测试类的时刻,必要把之前创建的数据库删除,详情拜见源码。

SQLite事务

SQLite的事务经由过程SQLiteDatabase中包孕的两个措施对其进行节制:beginTransaction(),开始事务;endTransaction(),停止事务。除此之外,SQLiteDatabase还供给了一个inTransaction()措施用来判断当前高低文是否处于事务情况中。当法度榜样履行endTransaction()措施时将会停止事务,到底是回滚事务照样提交事务取决于SQLiteDatabase是否调用了setTransactionSuccessful()措施来设置事务标志,假如法度榜样事务履行中调用该措施设置了事务成功则提交事务,否则法度榜样将回滚事务。

示例源码下载

总结

上面就基础解说了SQLite在Android中的时刻,虽然有两种操作要领,并且直接应用SQL语句操作数据库对付认识SQL语句的开拓者开说,是异常知心的,然则在Android中,照样有需要懂得一下应用SQLiteDatabase供给的措施操作数据库的要领,由于Android有一个内容供给者(Content Provider),可以应用外部利用造访内部利用的数据,它通报数据的形式,大年夜部分是与SQLiteDatabase内置措施的参数同等的,以是假犹如一应用SQLiteDatabase供给的措施操作数据库,是很方便的,无需额外转换SQL语句。

SQLiteExpertSetup下载地址:part1、part2。

您可能还会对下面的文章感兴趣: