在项目开发中,我们或多或少都会用到数据库。在Android中,我们一般使用SQLite,因为Android在android.database.sqlite
包封装了很多SQLite操作的API。我自己写了一个Demo来总结SQLite的使用,托管在Github上,大家可以点击下载APK,也可以点击下载源码。Demo截图如下:
在使用SQLite时,我建议先下载一个本地SQLite客户端来验证操作,在本地写的SQL语句运行正确后,再转移到Android中。我用的是SQLite Expert Personal。
首先创建一个继承在SQLiteOpenHelper的类,并重写onCreate()
和onUpgrade()
方法。
-
public class OrderDBHelper extends SQLiteOpenHelper{
-
private static final int DB_VERSION = 1;
-
private static final String DB_NAME = "myTest.db";
-
public static final String TABLE_NAME = "Orders";
-
public OrderDBHelper(Context context) {
-
super(context, DB_NAME, null, DB_VERSION);
-
}
-
@Override
-
public void onCreate(SQLiteDatabase sqLiteDatabase) {
-
// create table Orders(Id integer primary key, CustomName text, OrderPrice integer, Country text);
-
String sql = "create table if not exists " + TABLE_NAME + " (Id integer primary key, CustomName text, OrderPrice integer, Country text)";
-
sqLiteDatabase.execSQL(sql);
-
}
-
@Override
-
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
-
String sql = "DROP TABLE IF EXISTS " + TABLE_NAME;
-
sqLiteDatabase.execSQL(sql);
-
onCreate(sqLiteDatabase);
-
}
-
}
这个类主要用于建数据库和建表用,我们再创建一个OrderDao用于处理所有的数据操作方法。在OrderDao钟实例化OrderDBHelper:
-
public OrderDao(Context context) {
-
this.context = context;
-
ordersDBHelper = new OrderDBHelper(context);
-
}
数据库操作无外乎:“增删查改”。对于“增删改”这类对表内容变换的操作,我们需先调用getWritableDatabase()
,在执行的时候可以调用通用的execSQL(String sql)
方法或对应的操作API:insert()
、delete()
、update()
。而对“查”,需要调用getReadableDatabase()
,这时就不能使用execSQL方法了,得使用query()
或rawQuery()
方法。下面开始一一介绍。
增加数据
在我的Demo中,有两种增加数据操作:
初始化数据
在进入Demo程序时,先判断表中是否有数据,如果表中没有数据,我将先添加一些数据。在初始化数据时,因为一次性要添加的数据比较多,所以我直接采用的是execSQL
方法:
-
db = ordersDBHelper.getWritableDatabase();
-
db.beginTransaction();
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (1, 'Arc', 100, 'China')");
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (2, 'Bor', 200, 'USA')");
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (3, 'Cut', 500, 'Japan')");
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (4, 'Bor', 300, 'USA')");
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (5, 'Arc', 600, 'China')");
-
db.execSQL("insert into " + OrderDBHelper.TABLE_NAME + " (Id, CustomName, OrderPrice, Country) values (6, 'Doom', 200, 'China')");
-
db.setTransactionSuccessful();
插入一条新数据
我们还可以使用insert(String table,String nullColumnHack,ContentValues values)
方法来插入,ContentValues
内部实现就是HashMap
,但是两者还是有差别的,ContenValues
Key只能是String类型,Value只能存储基本类型的数据,像string,int之类的,不能存储对象这种东西:
-
public ContentValues() {
-
// Choosing a default size of 8 based on analysis of typical
-
// consumption by applications.
-
mValues = new HashMap<String, Object>(8);
-
}
使用insert()方法我们插入一条新数据(7, "Jne", 700, "China"),对于修改数据的操作我们一般当作事务(Transaction)处理:
-
db = ordersDBHelper.getWritableDatabase();
-
db.beginTransaction();
-
// insert into Orders(Id, CustomName, OrderPrice, Country) values (7, "Jne", 700, "China");
-
ContentValues contentValues = new ContentValues();
-
contentValues.put("Id", 7);
-
contentValues.put("CustomName", "Jne");
-
contentValues.put("OrderPrice", 700);
-
contentValues.put("Country", "China");
-
db.insertOrThrow(OrderDBHelper.TABLE_NAME, null, contentValues);
-
db.setTransactionSuccessful();
删除数据
删除数据的方法除了execSQL
还有delete(String table,String whereClause,String[] whereArgs)
,whereClause是删除条件,whereArgs是删除条件值数组。
-
db = ordersDBHelper.getWritableDatabase();
-
db.beginTransaction();
-
// delete from Orders where Id = 7
-
db.delete(OrderDBHelper.TABLE_NAME, "Id = ?", new String[]{String.valueOf(7)});
-
db.setTransactionSuccessful();
再看删除的源码,里面会拼装删除条件和删除条件值数组:
-
public int delete(String table, String whereClause, String[] whereArgs) {
-
acquireReference();
-
try {
-
SQLiteStatement statement = new SQLiteStatement(this, "DELETE FROM " + table +
-
(!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
-
try {
-
return statement.executeUpdateDelete();
-
} finally {
-
statement.close();
-
}
-
} finally {
-
releaseReference();
-
}
-
}
修改数据
修改数据和插入数据很相似,调用的方法除了execSQL
还可以是update(String table,ContentValues values,String whereClause, String[] whereArgs)
:
-
db = ordersDBHelper.getWritableDatabase();
-
db.beginTransaction();
-
// update Orders set OrderPrice = 800 where Id = 6
-
ContentValues cv = new ContentValues();
-
cv.put("OrderPrice", 800);
-
db.update(OrderDBHelper.TABLE_NAME,
-
cv,
-
"Id = ?",
-
new String[]{String.valueOf(6)});
-
db.setTransactionSuccessful();
查找数据
查找数据有两个方法,一是public Cursor query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit);
,另外一个是public Cursor rawQuery(String sql, String[] selectionArgs)
。rawQuery
的写法类似上面的execSQL
,在此不做介绍,query
方法中的参数如下:
- table:表名称
- columns:列名称数组
- selection:条件字句,相当于where
- selectionArgs:条件字句,参数数组
- groupBy:分组列
- having:分组条件
- orderBy:排序列
- limit:分页查询限制
- Cursor:返回值,相当于结果集ResultSet
我们可以看到返回的类型都是Cursor
,Cursor
是一个游标接口,提供了遍历查询结果的方法,如移动指针方法move(),获得列值方法。Cursor游标常用方法如下:
我们先来查一查用户名为"Bor"的信息:
-
db = ordersDBHelper.getReadableDatabase();
-
// select * from Orders where CustomName = 'Bor'
-
cursor = db.query(OrderDBHelper.TABLE_NAME,
-
ORDER_COLUMNS,
-
"CustomName = ?",
-
new String[] {"Bor"},
-
null, null, null);
-
if (cursor.getCount() > 0) {
-
List<Order> orderList = new ArrayList<Order>(cursor.getCount());
-
while (cursor.moveToNext()) {
-
Order order = parseOrder(cursor);
-
orderList.add(order);
-
}
-
return orderList;
-
}
当然我们也可以查询总数、最大值最小值之类的,以查询Country为China的用户总数为例:
-
db = ordersDBHelper.getReadableDatabase();
-
// select count(Id) from Orders where Country = 'China'
-
cursor = db.query(OrderDBHelper.TABLE_NAME,
-
new String[]{"COUNT(Id)"},
-
"Country = ?",
-
new String[] {"China"},
-
null, null, null);
-
if (cursor.moveToFirst()) {
-
count = cursor.getInt(0);
-
}
至此SQLite就介绍完了,大家可以下载Demo详细查看。Demo中还有一些其他比较干货的东西,大家可以挖掘挖掘。当然Demo中也有些不足,我还会更新,尽量做到让用户通过Demo就能学会如何使用SQLite。