Android开发:查询SQLite数据库表数据
数据库基础知识在 Android SQLite 查询中的应用
关系型数据库概念回顾
在深入探讨 Android 中 SQLite 数据库表数据查询之前,有必要回顾一下关系型数据库的基本概念。关系型数据库以二维表的形式组织数据,每个表由行(记录)和列(字段)组成。例如,一个“用户”表可能包含“用户ID”“用户名”“密码”等列,每一行代表一个具体的用户记录。这种结构使得数据的组织和管理具有高度的逻辑性和规范性。
在关系型数据库中,表与表之间可以通过外键建立关联关系。比如,有一个“订单”表,其中的“用户ID”字段可以作为外键关联到“用户”表的“用户ID”,这样就能明确每个订单是由哪个用户创建的。这种关联关系在数据查询中起着至关重要的作用,它使得我们可以从多个相关表中获取有意义的信息。
SQL 基本语法概述
SQL(Structured Query Language)即结构化查询语言,是用于数据库查询、操作和管理的标准语言。在 Android 开发中查询 SQLite 数据库主要使用 SQL 语句。
SELECT 语句基础
SELECT 语句是 SQL 中用于查询数据的核心语句。其基本语法结构为:SELECT 列名 FROM 表名;
。例如,要从名为“users”的表中查询所有用户的“用户名”,可以使用语句:SELECT username FROM users;
。如果要查询多个列,列名之间用逗号分隔,如SELECT username, email FROM users;
。若要查询表中的所有列,可以使用通配符*
,即SELECT * FROM users;
。
WHERE 子句用于条件过滤
WHERE 子句用于在查询中添加条件,只返回满足特定条件的数据。语法为SELECT 列名 FROM 表名 WHERE 条件;
。条件可以是各种比较表达式,例如,要查询年龄大于 30 岁的用户,可以写为SELECT * FROM users WHERE age > 30;
。条件中还可以使用逻辑运算符AND
、OR
和NOT
进行组合。比如,查询年龄大于 30 岁且性别为“男”的用户:SELECT * FROM users WHERE age > 30 AND gender = '男';
。
ORDER BY 子句用于排序
ORDER BY 子句用于对查询结果进行排序。可以按升序(ASC,默认)或降序(DESC)排列。例如,要按用户年龄从大到小查询用户:SELECT * FROM users ORDER BY age DESC;
。如果要按多个列排序,列名之间用逗号分隔,如SELECT * FROM users ORDER BY age DESC, username ASC;
Android 开发中 SQLiteOpenHelper 类
SQLiteOpenHelper 类简介
在 Android 开发中,SQLiteOpenHelper 类是一个非常重要的辅助类,用于管理 SQLite 数据库的创建、版本升级和降级等操作。它提供了一种方便的方式来处理数据库的生命周期。
继承 SQLiteOpenHelper 类
要使用 SQLiteOpenHelper,首先需要创建一个继承自该类的自定义类。例如:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "MyDatabaseHelper";
private static final String DATABASE_NAME = "my_database.db";
private static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTableQuery = "CREATE TABLE users (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"username TEXT," +
"password TEXT," +
"age INTEGER," +
"gender TEXT)";
db.execSQL(createTableQuery);
Log.d(TAG, "Table 'users' created successfully");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < newVersion) {
// 进行数据库版本升级操作,例如添加新列
String addColumnQuery = "ALTER TABLE users ADD COLUMN email TEXT";
db.execSQL(addColumnQuery);
Log.d(TAG, "Column 'email' added to 'users' table during upgrade");
}
}
}
在上述代码中,MyDatabaseHelper
类继承自SQLiteOpenHelper
。构造函数中调用了父类的构造函数,传入了数据库名称、游标工厂(通常为null
)和数据库版本。onCreate
方法在数据库首次创建时被调用,这里创建了一个名为“users”的表。onUpgrade
方法在数据库版本发生变化时被调用,这里演示了添加新列的操作。
获取 SQLiteDatabase 对象
通过MyDatabaseHelper
类的实例,可以获取SQLiteDatabase
对象,用于执行 SQL 语句。例如:
MyDatabaseHelper helper = new MyDatabaseHelper(context);
SQLiteDatabase db = helper.getWritableDatabase();
// 或者获取只读数据库
// SQLiteDatabase db = helper.getReadableDatabase();
getWritableDatabase
方法用于获取可读写的数据库对象,如果数据库不存在,会先调用onCreate
方法创建数据库。getReadableDatabase
方法用于获取只读的数据库对象,当数据库磁盘空间不足等情况下,可能会返回只读数据库。
简单的单表查询
查询所有列
在 Android 中查询 SQLite 数据库表的所有列数据是最基本的操作之一。假设我们已经有了一个SQLiteDatabase
对象db
,并且数据库中有一个名为“users”的表,要查询该表的所有数据,可以使用以下代码:
Cursor cursor = db.query("users", null, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
String password = cursor.getString(cursor.getColumnIndex("password"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
String gender = cursor.getString(cursor.getColumnIndex("gender"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username + ", Password: " + password + ", Age: " + age + ", Gender: " + gender);
} while (cursor.moveToNext());
}
cursor.close();
在上述代码中,db.query
方法用于执行查询操作。第一个参数是表名“users”,第二个参数null
表示查询所有列。后面几个null
参数分别用于指定筛选条件、分组、分组条件、排序等,这里都未使用。query
方法返回一个Cursor
对象,它指向查询结果集。通过cursor.moveToFirst
方法将游标移动到结果集的第一行,如果存在数据,则通过do - while
循环遍历结果集。在循环中,使用cursor.getColumnIndex
方法获取列的索引,然后通过cursor.getInt
、cursor.getString
等方法获取对应列的数据。最后,关闭游标以释放资源。
查询指定列
如果只需要查询表中的某些特定列,可以在db.query
方法的第二个参数中指定列名数组。例如,只查询“用户名”和“年龄”列:
String[] columns = {"username", "age"};
Cursor cursor = db.query("users", columns, null, null, null, null, null);
if (cursor.moveToFirst()) {
do {
String username = cursor.getString(cursor.getColumnIndex("username"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
Log.d("QueryResult", "Username: " + username + ", Age: " + age);
} while (cursor.moveToNext());
}
cursor.close();
这里将需要查询的列名“username”和“age”组成数组作为db.query
方法的第二个参数,其他操作与查询所有列类似。
使用 WHERE 子句进行条件查询
简单条件查询
使用WHERE
子句可以根据特定条件查询数据。例如,要查询年龄大于 30 岁的用户:
String selection = "age >?";
String[] selectionArgs = {"30"};
Cursor cursor = db.query("users", null, selection, selectionArgs, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
String password = cursor.getString(cursor.getColumnIndex("password"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
String gender = cursor.getString(cursor.getColumnIndex("gender"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username + ", Password: " + password + ", Age: " + age + ", Gender: " + gender);
} while (cursor.moveToNext());
}
cursor.close();
在上述代码中,selection
变量定义了WHERE
子句的条件“age >?”,其中?
是占位符。selectionArgs
数组用于替换占位符的值,这里是“30”。这样就实现了查询年龄大于 30 岁的用户数据。
复杂条件查询
可以使用逻辑运算符组合多个条件。例如,查询年龄大于 30 岁且性别为“男”的用户:
String selection = "age >? AND gender =?";
String[] selectionArgs = {"30", "男"};
Cursor cursor = db.query("users", null, selection, selectionArgs, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
String password = cursor.getString(cursor.getColumnIndex("password"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
String gender = cursor.getString(cursor.getColumnIndex("gender"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username + ", Password: " + password + ", Age: " + age + ", Gender: " + gender);
} while (cursor.moveToNext());
}
cursor.close();
这里的selection
条件使用了AND
逻辑运算符组合了两个条件,selectionArgs
数组依次为两个占位符提供值。
使用 ORDER BY 子句进行排序查询
按单个列排序
要对查询结果按某个列进行排序,可以使用ORDER BY
子句。例如,按年龄从大到小查询用户:
String orderBy = "age DESC";
Cursor cursor = db.query("users", null, null, null, null, null, orderBy);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
String password = cursor.getString(cursor.getColumnIndex("password"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
String gender = cursor.getString(cursor.getColumnIndex("gender"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username + ", Password: " + password + ", Age: " + age + ", Gender: " + gender);
} while (cursor.moveToNext());
}
cursor.close();
在db.query
方法中,通过orderBy
参数指定按“age”列降序排列(DESC
表示降序,若要升序则使用ASC
,默认是ASC
)。
按多个列排序
也可以按多个列进行排序。例如,先按年龄从大到小,年龄相同的再按用户名升序排序:
String orderBy = "age DESC, username ASC";
Cursor cursor = db.query("users", null, null, null, null, null, orderBy);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
String password = cursor.getString(cursor.getColumnIndex("password"));
int age = cursor.getInt(cursor.getColumnIndex("age"));
String gender = cursor.getString(cursor.getColumnIndex("gender"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username + ", Password: " + password + ", Age: " + age + ", Gender: " + gender);
} while (cursor.moveToNext());
}
cursor.close();
这里的orderBy
参数中,多个列名之间用逗号分隔,分别指定了排序方式。
聚合函数与分组查询
聚合函数的使用
COUNT 函数
COUNT
函数用于统计行数。例如,要统计“users”表中的用户数量:
String[] columns = {"COUNT(*)"};
Cursor cursor = db.query("users", columns, null, null, null, null, null);
if (cursor.moveToFirst()) {
int count = cursor.getInt(0);
Log.d("QueryResult", "User count: " + count);
}
cursor.close();
在db.query
方法中,将"COUNT(*)"
作为查询列,执行查询后,从结果集中获取第一列的值,即为用户数量。
SUM 函数
假设“users”表中有一个“score”列表示用户的成绩,要计算所有用户成绩的总和,可以使用SUM
函数:
String[] columns = {"SUM(score)"};
Cursor cursor = db.query("users", columns, null, null, null, null, null);
if (cursor.moveToFirst()) {
int sumScore = cursor.getInt(0);
Log.d("QueryResult", "Total score: " + sumScore);
}
cursor.close();
这里以"SUM(score)"
作为查询列,获取的结果就是成绩总和。
AVG 函数
计算“users”表中用户成绩的平均值,使用AVG
函数:
String[] columns = {"AVG(score)"};
Cursor cursor = db.query("users", columns, null, null, null, null, null);
if (cursor.moveToFirst()) {
double avgScore = cursor.getDouble(0);
Log.d("QueryResult", "Average score: " + avgScore);
}
cursor.close();
同样,将"AVG(score)"
作为查询列获取平均成绩。
MAX 和 MIN 函数
要获取“users”表中成绩的最大值和最小值,分别使用MAX
和MIN
函数:
// 获取最大成绩
String[] maxColumns = {"MAX(score)"};
Cursor maxCursor = db.query("users", maxColumns, null, null, null, null, null);
if (maxCursor.moveToFirst()) {
int maxScore = maxCursor.getInt(0);
Log.d("QueryResult", "Max score: " + maxScore);
}
maxCursor.close();
// 获取最小成绩
String[] minColumns = {"MIN(score)"};
Cursor minCursor = db.query("users", minColumns, null, null, null, null, null);
if (minCursor.moveToFirst()) {
int minScore = minCursor.getInt(0);
Log.d("QueryResult", "Min score: " + minScore);
}
minCursor.close();
分别以"MAX(score)"
和"MIN(score)"
作为查询列获取最大和最小成绩。
分组查询
GROUP BY 基本使用
分组查询可以将数据按某个或某些列进行分组,并对每个组应用聚合函数。例如,要按性别统计用户数量:
String[] columns = {"gender", "COUNT(*)"};
String groupBy = "gender";
Cursor cursor = db.query("users", columns, null, null, groupBy, null, null);
if (cursor.moveToFirst()) {
do {
String gender = cursor.getString(cursor.getColumnIndex("gender"));
int count = cursor.getInt(cursor.getColumnIndex("COUNT(*)"));
Log.d("QueryResult", "Gender: " + gender + ", Count: " + count);
} while (cursor.moveToNext());
}
cursor.close();
在db.query
方法中,通过groupBy
参数指定按“gender”列进行分组,查询列包括“gender”和每组的用户数量(使用COUNT(*)
)。
HAVING 子句用于分组后筛选
HAVING
子句用于对分组后的结果进行筛选。例如,只显示用户数量大于 10 的性别分组:
String[] columns = {"gender", "COUNT(*)"};
String groupBy = "gender";
String having = "COUNT(*) > 10";
Cursor cursor = db.query("users", columns, null, null, groupBy, having, null);
if (cursor.moveToFirst()) {
do {
String gender = cursor.getString(cursor.getColumnIndex("gender"));
int count = cursor.getInt(cursor.getColumnIndex("COUNT(*)"));
Log.d("QueryResult", "Gender: " + gender + ", Count: " + count);
} while (cursor.moveToNext());
}
cursor.close();
这里通过having
参数指定了分组后筛选的条件“COUNT(*) > 10”,只有满足该条件的分组才会出现在查询结果中。
多表关联查询
内连接(INNER JOIN)
假设我们有两个表,“users”表和“orders”表,“orders”表中有一个“user_id”外键关联到“users”表的“id”。要查询每个用户及其对应的订单信息,可以使用内连接:
String query = "SELECT users.username, orders.order_id, orders.order_amount " +
"FROM users " +
"INNER JOIN orders ON users.id = orders.user_id";
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
do {
String username = cursor.getString(cursor.getColumnIndex("username"));
int orderId = cursor.getInt(cursor.getColumnIndex("order_id"));
double orderAmount = cursor.getDouble(cursor.getColumnIndex("order_amount"));
Log.d("QueryResult", "Username: " + username + ", Order ID: " + orderId + ", Order Amount: " + orderAmount);
} while (cursor.moveToNext());
}
cursor.close();
在上述代码中,使用db.rawQuery
方法执行原生 SQL 查询。查询语句通过INNER JOIN
关键字将“users”表和“orders”表连接起来,连接条件是“users.id = orders.user_id”。查询结果中选择了“users”表的“username”列和“orders”表的“order_id”、“order_amount”列。
左连接(LEFT JOIN)
左连接会返回左表(LEFT JOIN
关键字左边的表)中的所有行,以及右表中满足连接条件的行。例如,要查询所有用户及其订单信息,即使某个用户没有订单也显示该用户信息:
String query = "SELECT users.username, orders.order_id, orders.order_amount " +
"FROM users " +
"LEFT JOIN orders ON users.id = orders.user_id";
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
do {
String username = cursor.getString(cursor.getColumnIndex("username"));
Integer orderId = cursor.isNull(cursor.getColumnIndex("order_id"))? null : cursor.getInt(cursor.getColumnIndex("order_id"));
Double orderAmount = cursor.isNull(cursor.getColumnIndex("order_amount"))? null : cursor.getDouble(cursor.getColumnIndex("order_amount"));
Log.d("QueryResult", "Username: " + username + ", Order ID: " + orderId + ", Order Amount: " + orderAmount);
} while (cursor.moveToNext());
}
cursor.close();
这里使用LEFT JOIN
进行连接,对于没有订单的用户,其对应的“order_id”和“order_amount”列值为null
,在代码中通过cursor.isNull
方法进行判断并处理。
右连接(RIGHT JOIN)
右连接与左连接相反,它会返回右表中的所有行,以及左表中满足连接条件的行。例如:
String query = "SELECT users.username, orders.order_id, orders.order_amount " +
"FROM users " +
"RIGHT JOIN orders ON users.id = orders.user_id";
Cursor cursor = db.rawQuery(query, null);
if (cursor.moveToFirst()) {
do {
String username = cursor.isNull(cursor.getColumnIndex("username"))? null : cursor.getString(cursor.getColumnIndex("username"));
int orderId = cursor.getInt(cursor.getColumnIndex("order_id"));
double orderAmount = cursor.getDouble(cursor.getColumnIndex("order_amount"));
Log.d("QueryResult", "Username: " + username + ", Order ID: " + orderId + ", Order Amount: " + orderAmount);
} while (cursor.moveToNext());
}
cursor.close();
此代码使用RIGHT JOIN
,对于没有匹配用户的订单,“username”列值为null
,同样通过cursor.isNull
方法处理。
全外连接(FULL OUTER JOIN)
在 SQLite 中没有直接支持全外连接,但可以通过左连接和右连接的并集来模拟。假设要查询所有用户和所有订单,无论是否有匹配关系:
// 左连接部分
String leftJoinQuery = "SELECT users.username, orders.order_id, orders.order_amount " +
"FROM users " +
"LEFT JOIN orders ON users.id = orders.user_id";
Cursor leftCursor = db.rawQuery(leftJoinQuery, null);
// 右连接部分
String rightJoinQuery = "SELECT users.username, orders.order_id, orders.order_amount " +
"FROM users " +
"RIGHT JOIN orders ON users.id = orders.user_id";
Cursor rightCursor = db.rawQuery(rightJoinQuery, null);
// 合并结果(这里简单打印,实际应用中可能需要更复杂处理)
if (leftCursor.moveToFirst()) {
do {
String username = leftCursor.getString(leftCursor.getColumnIndex("username"));
Integer orderId = leftCursor.isNull(leftCursor.getColumnIndex("order_id"))? null : leftCursor.getInt(leftCursor.getColumnIndex("order_id"));
Double orderAmount = leftCursor.isNull(leftCursor.getColumnIndex("order_amount"))? null : leftCursor.getDouble(leftCursor.getColumnIndex("order_amount"));
Log.d("LeftJoinResult", "Username: " + username + ", Order ID: " + orderId + ", Order Amount: " + orderAmount);
} while (leftCursor.moveToNext());
}
leftCursor.close();
if (rightCursor.moveToFirst()) {
do {
String username = rightCursor.isNull(rightCursor.getColumnIndex("username"))? null : rightCursor.getString(rightCursor.getColumnIndex("username"));
int orderId = rightCursor.getInt(rightCursor.getColumnIndex("order_id"));
double orderAmount = rightCursor.getDouble(rightCursor.getColumnIndex("order_amount"));
Log.d("RightJoinResult", "Username: " + username + ", Order ID: " + orderId + ", Order Amount: " + orderAmount);
} while (rightCursor.moveToNext());
}
rightCursor.close();
这里分别执行左连接和右连接查询,并分别处理结果,模拟了全外连接的效果。
使用 ContentProvider 查询 SQLite 数据库
ContentProvider 简介
ContentProvider 是 Android 四大组件之一,它主要用于在不同的应用程序之间共享数据。通过 ContentProvider,可以将 SQLite 数据库的数据暴露给其他应用,实现数据的共享和交换。
创建自定义 ContentProvider
首先需要创建一个继承自ContentProvider
的类。例如:
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;
public class MyContentProvider extends ContentProvider {
private static final String TAG = "MyContentProvider";
private static final String AUTHORITY = "com.example.mycontentprovider";
private static final String PATH_USERS = "users";
public static final Uri CONTENT_URI_USERS = Uri.parse("content://" + AUTHORITY + "/" + PATH_USERS);
private static final int USERS = 1;
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, PATH_USERS, USERS);
}
private MyDatabaseHelper dbHelper;
@Override
public boolean onCreate() {
dbHelper = new MyDatabaseHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor;
switch (uriMatcher.match(uri)) {
case USERS:
cursor = db.query("users", projection, selection, selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// 其他未实现的方法(insert、update、delete等)
@Override
public Uri insert(Uri uri, ContentValues values) {
// 实现插入逻辑
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// 实现更新逻辑
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// 实现删除逻辑
return 0;
}
@Override
public String getType(Uri uri) {
// 返回 MIME 类型
return null;
}
}
在上述代码中,MyContentProvider
类继承自ContentProvider
。AUTHORITY
定义了内容提供者的权限,PATH_USERS
定义了与“users”表相关的路径。uriMatcher
用于匹配不同的 URI。onCreate
方法初始化MyDatabaseHelper
。query
方法根据匹配的 URI 执行相应的查询操作,并设置通知 URI。
在 AndroidManifest.xml 中注册 ContentProvider
要使ContentProvider
生效,需要在AndroidManifest.xml
中注册:
<provider
android:name=".MyContentProvider"
android:authorities="com.example.mycontentprovider"
android:exported="true" />
这里android:name
指定了ContentProvider
类的路径,android:authorities
与代码中的AUTHORITY
一致,android:exported
设置为true
表示可以被其他应用访问。
通过 ContentResolver 查询数据
在其他应用中,可以通过ContentResolver
来查询MyContentProvider
暴露的数据。例如:
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(MyContentProvider.CONTENT_URI_USERS, null, null, null, null);
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndex("id"));
String username = cursor.getString(cursor.getColumnIndex("username"));
Log.d("QueryResult", "ID: " + id + ", Username: " + username);
} while (cursor.moveToNext());
}
cursor.close();
这里通过getContentResolver
获取ContentResolver
对象,然后使用resolver.query
方法根据MyContentProvider.CONTENT_URI_USERS
进行查询,操作方式与直接使用SQLiteDatabase
查询类似,但数据来自ContentProvider
提供的共享数据。
事务在查询中的应用
事务的概念
事务是数据库操作的一个逻辑单元,它由一组相关的数据库操作组成,这些操作要么全部成功执行,要么全部不执行,以保证数据的一致性和完整性。在 Android SQLite 数据库中,事务对于涉及多个查询操作且需要保证数据一致性的场景非常重要。
使用事务进行查询操作
例如,假设我们有两个表“accounts”(包含账户余额信息)和“transactions”(记录交易信息)。现在要进行一次转账操作,从一个账户扣除金额并在另一个账户增加金额,同时记录交易信息。这就需要使用事务来确保这一系列操作的原子性。
SQLiteDatabase db = dbHelper.getWritableDatabase();
try {
db.beginTransaction();
// 从转出账户扣除金额
String updateFromAccountQuery = "UPDATE accounts SET balance = balance -? WHERE account_id =?";
String[] fromArgs = {"100", "1"};
db.execSQL(updateFromAccountQuery, fromArgs);
// 向转入账户增加金额
String updateToAccountQuery = "UPDATE accounts SET balance = balance +? WHERE account_id =?";
String[] toArgs = {"100", "2"};
db.execSQL(updateToAccountQuery, toArgs);
// 记录交易信息
ContentValues values = new ContentValues();
values.put("from_account_id", 1);
values.put("to_account_id", 2);
values.put("amount", 100);
db.insert("transactions", null, values);
db.setTransactionSuccessful();
} catch (Exception e) {
Log.e("TransactionError", "Transaction failed", e);
} finally {
db.endTransaction();
}
在上述代码中,首先调用db.beginTransaction
开始事务。然后依次执行从转出账户扣除金额、向转入账户增加金额以及记录交易信息的操作。如果所有操作都成功,调用db.setTransactionSuccessful
标记事务成功。如果在事务执行过程中出现异常,catch
块捕获异常并记录错误信息。最后,无论事务是否成功,都通过db.endTransaction
结束事务。如果事务未标记成功,endTransaction
会回滚所有操作,保证数据的一致性。
查询性能优化
索引的使用
创建索引
索引可以显著提高查询性能。在 SQLite 中,可以使用CREATE INDEX
语句创建索引。例如,在“users”表的“username”列上创建索引:
String createIndexQuery = "CREATE INDEX idx_username ON users (username)";
db.execSQL(createIndexQuery);
这样在查询“username”列相关条件时,数据库可以更快地定位数据。
复合索引
也可以创建复合索引,用于多个列的联合查询。例如,在“users”表的“age”和“gender”列上创建复合索引:
String createCompositeIndexQuery = "CREATE INDEX idx_age_gender ON users (age, gender)";
db.execSQL(createCompositeIndexQuery);
当查询条件涉及“age”和“gender”两个列时,复合索引能提高查询效率。
避免不必要的查询
在代码中,要避免进行不必要的数据库查询。例如,如果某些数据已经在内存中,就不需要再次从数据库查询。可以使用缓存机制来存储经常查询的数据,减少数据库的负载。
优化查询语句
尽量简化查询语句,避免复杂的子查询和嵌套查询。例如,能用连接查询解决的问题,尽量不使用子查询,因为连接查询通常在性能上更优。同时,合理使用WHERE
子句、ORDER BY
子句等,确保查询条件准确,避免全表扫描。
通过以上对 Android 开发中 SQLite 数据库表数据查询的详细介绍,包括从基础的单表查询到复杂的多表关联查询,以及性能优化等方面,开发者可以全面掌握 SQLite 查询的相关知识和技巧,开发出高效、稳定的数据查询功能。