Android数据存储(二)

数据库存储

引言

对于大数量结构化数据的存取,采用文件的方式操作复杂,效率低下,因此Android系统引人了轻量级嵌人式关系数据库SQLite,支持SQL语言,可以方便地实现数据的增、删、改、查等操作。

SOLite 介绍

Android 系统集成了SOLite数据库,任何应用都可以使用它。默认情况下,SQLite数据库存储在内部存储空间的/data/data//databases日录下。

1. 重要的类和接口

1.1 SQLiteDatabase 常用方法

方法 描述
public static SQLiteDatabase openDatabase ( String path ,SQLiteDatabase, CursorFactory, int flags ) 以指定模式打开指定路径下的数据库文件
public void execSQL( String sql) 执行 sql 语句
public void execSQL( Sting sql, Object [ ] args) 执行 sql语句,args 为参数值数组
public Cursor rawQuery ( String sql, String [ ]selection_Args) 执行指定的 sql 查询语句
public long insert ( String table, String nullColumn, Cont-entValues values ) 向 table 表插入数据,nullCloumn为默认NULL值的列名,values为字段键值对
public int update( String table, ContentValues values,String whereClause String [ ] whereArgs) 修改table表数据,values为修改字段键值对,whereClause为where子,whereArgs为where子句参数值数组
public int delete ( String table, String whereClause, String [] whereArgs) 删除table 表数据,whereClause为where 子句whereArgs为 where 子句参数值数组
public Cursor query( String table, String[]columnsString selection, String [ ]selectionArgs, String groupBy,String having, String orderBy) 从table表查询数据,返回结果集Cursor,col-umns为列名数组,selection为where子语,selectionArgs为where子句参数值数组,groupBy为分组,having为分组过滤,orderBy为排序
public void close( ) 关闭数据库

1.2 Cursor 接口

SQLiteDatabase 类中 query()方法的返回值为查询结果集的Cursor游标。Cursor是一个接口,在 android.database包中,开发者可以通过遍历Cursor 的方法得到查询结果的所有记录。

Cursor 接口的常用方法

方法 功能描述
public abstract getCount( ) 获取查询结果的数量
public abstract boolean isF’irst( ) 判断结果游标是否指向第一行
public abstract boolean isLast( ) 判断结果游标是否指向最后一行
public abstract boolean moveToFirst( ) 移动游标到结果集第一行
public abstract boolean moveToLast( ) 移动游标到结果集最后一行
public abstract boolean moveToNext( ) 移动游标到结果集下一行
public abstract boolean moveToPrevious( ) 移动游标到结果集上一行
public abstract int getInt( int columnIndex) 根据列索引,获取列的整数值
public abstract String getString( int columnlndex ) 根据列索引,获取列的字符串值

1.3 .SQLiteOpenHelper类

SOLiteDatabase 类是一个数据库操作类,在对象实例化、数据库升级、访问对象的管理等方面使用起来具有一定的复杂性。Android 系统提供了一个数据库操作辅助类 SOLiteOpenHelper,它封装了创建和更新数据库使用的细节。它是一个抽象类,开发者可以定义其子类实现其抽象方法,辅助完成数据库的操作。

方法 描述
public SQLiteOpenHepler( Context context, String name ,SQLiteDatabase. CursorFactory factory, int version ) 构造方法,必须指明数据库名和版本号
public abstract void onCreate( $QLiteDatabase db) 抽象方法,可重写该方法,利用 ab创建表初始化数据
public synchronized void close( ) 关闭数据库
public synchronized SQLiteDatabase getReadableDatabase ( ) 以只读方式创建或者打开数据库
public synchronized $QLiteDatabase getWritableDatabase( ) 以写方式创建或者打开数据库
public abstract void onUpgrade( SOLiteDatabase db, int oldVersion, int newVersion ) 当版本号增加后,该方法被自动执行,实现数据库的升级、数据更新等

2. 代码实例

2.1 创建表

前面提到,使用到SQLite就需要创建到表,但是没有像mysql类似的数据库链接,只有本身提供的自带的小型数据库,所以我们按照SQLiteDataBase的基础方式创建出一个数据表,并且重写其中的OnCreat方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* StudentDBHelper类用于管理学生数据库的创建和版本管理。
* 继承自SQLiteOpenHelper,提供数据库的创建和版本升级功能。
*/
public class StudentDBHelper extends SQLiteOpenHelper {

// 数据库名称
private static final String DATABASE_NAME = "student_db";

// 数据表名称
private static final String TABLE_NAME = "student";

// 数据库版本号
private static final int DATABASE_VERSION = 1;

/**
* 构造方法,初始化数据库助手。
*
* @param context 应用的上下文,通常是Activity或Application的实例。
*/
public StudentDBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

/**
* 当数据库首次创建时调用该方法。
* 在此方法中创建学生信息表。
*
* @param db SQLiteDatabase对象,用于执行SQL语句。
*/
@Override
public void onCreate(SQLiteDatabase db) {
// 创建学生表的SQL语句
String strSQL = "CREATE TABLE " + TABLE_NAME +
" (sid INTEGER PRIMARY KEY AUTOINCREMENT, " + // 自增主键
"stu_no VARCHAR(100), " + // 学号字段,最大长度100
"name VARCHAR(100), " + // 姓名字段,最大长度100
"clazz VARCHAR(100), " + // 班级字段,最大长度100
"publish TEXT)"; // 发布日期字段,存储为文本类型

// 执行SQL语句以创建表
db.execSQL(strSQL);
}

/**
* 当数据库版本更新时调用该方法。
* 在此方法中实现数据库的升级逻辑,例如迁移数据。
*
* @param db SQLiteDatabase对象,用于执行SQL语句。
* @param oldVersion 旧版本号。
* @param newVersion 新版本号。
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 通常在此处实现数据库表的升级逻辑
// 可以添加 ALTER TABLE 语句或 DROP TABLE 语句来更新表结构
}
}

如果需要在创建时往其中添加一些数据就可以在创建时的OnCreat方法下面执行插入操作:

1
2
3
String sql1 = "INSERT INTO " + TABLE_NAME +
" VALUES(null, '202001', '韩1', '计算机1班', '2020-06-13')";
db.execSQL(sql1);

3.2 Dao持久化

要将数据等的操作加载入数据库中,就需要一个媒介,也就是上面提到的Cursor对象,其中的cursor起到一个类似推车的作用,将所有的数据都带过来,最后对这个对象中的元素进行清洗得到需要的数据

其中的查询操作需要使用到Cursor对象,更删改主要依靠execSQL对SQL语句进行提交和执行,而execSQL又是SQLiteDatabase对象中的操作,这样我们可以将其提取成一个方法来减少对对象的调用,将需要执行的sql语句提交到这个方法就可以实现对语句的执行

主要的操作都是交给execSQL这个自己的对象操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
public boolean execSQL(final String strSQL) {
try {
db.beginTransaction();
db.execSQL(strSQL);
db.setTransactionSuccessful();
} catch (RuntimeException e) {
e.printStackTrace();
return false;
} finally {
db.endTransaction();
}
return true;
}

这样我们就可以将增删改查写成更加简介的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* StudentDao类用于执行与学生相关的数据库操作。
* 包括增、删、查等功能,通过SQLiteOpenHelper管理数据库。
*/
public class StudentDao {
private SQLiteDatabase db; // SQLiteDatabase对象,用于执行SQL命令

/**
* 构造方法,初始化StudentDao对象并获取可写的数据库实例。
*
* @param dbHelper SQLiteOpenHelper对象,用于管理数据库创建和版本管理
*/
public StudentDao(SQLiteOpenHelper dbHelper) {
db = dbHelper.getWritableDatabase(); // 获取可写数据库
}

/**
* 执行查询操作,并将结果存储到给定的列表中。
*
* @param list 存储查询结果的列表,使用Map来表示每一行数据
* @param strSQL 要执行的SQL查询语句
*/
public void execQuery(List<Map<String, Object>> list, final String strSQL) {
Cursor cursor = null; // 定义Cursor对象用于遍历查询结果
try {
cursor = db.rawQuery(strSQL, null); // 执行查询
list.clear(); // 清空列表以准备存储新结果
if (cursor.moveToFirst()) { // 检查游标是否有数据
do {
// 创建一个Map用于存储一行数据
Map<String, Object> map = new HashMap<>();
map.put("sid", cursor.getInt(0)); // 获取学生ID
map.put("stu_no", cursor.getString(1)); // 获取学号
map.put("name", cursor.getString(2)); // 获取姓名
map.put("clazz", cursor.getString(3)); // 获取班级
map.put("publish", cursor.getString(4)); // 获取发布日期
list.add(map); // 将当前行的数据添加到列表中
} while (cursor.moveToNext()); // 移动到下一行
}
} catch (RuntimeException e) {
e.printStackTrace(); // 打印异常信息
} finally {
if (cursor != null) {
cursor.close(); // 确保游标在使用后被关闭,避免内存泄漏
}
}
}

/**
* 执行不返回结果的SQL语句(如INSERT、DELETE等)。
*
* @param strSQL 要执行的SQL语句
* @return 如果执行成功返回true,否则返回false
*/
public boolean execSQL(final String strSQL) {
try {
db.beginTransaction(); // 开始事务
db.execSQL(strSQL); // 执行SQL语句
db.setTransactionSuccessful(); // 设置事务成功
} catch (RuntimeException e) {
e.printStackTrace(); // 打印异常信息
return false; // 返回执行失败
} finally {
db.endTransaction(); // 结束事务
}
return true; // 返回执行成功
}

/**
* 添加学生信息到数据库。
*
* @param stuNo 学号
* @param name 姓名
* @param clazz 班级
* @param publish 发布日期
*/
public void addStudent(String stuNo, String name, String clazz, String publish) {
// 构建INSERT SQL语句
String strSQL = "INSERT INTO student(stu_no, name, clazz, publish) VALUES('"
+ stuNo + "', '" + name + "', '" + clazz + "', '" + publish + "')";
execSQL(strSQL); // 执行SQL语句
}

/**
* 根据学号删除学生信息。
*
* @param stuNo 学号
*/
public void deleteStudent(String stuNo) {
// 构建DELETE SQL语句
String strSQL = "DELETE FROM student WHERE stu_no = '" + stuNo + "'";
execSQL(strSQL); // 执行SQL语句
}

/**
* 查询学生信息,根据提供的条件过滤结果。
*
* @param list 存储查询结果的列表
* @param stuNo 学号(可选)
* @param name 姓名(可选)
* @param clazz 班级(可选)
*/
public void queryStudents(List<Map<String, Object>> list, String stuNo, String name, String clazz) {
StringBuilder strSQL = new StringBuilder("SELECT * FROM student WHERE 1=1 "); // 基础查询语句
if (!stuNo.isEmpty()) {
strSQL.append(" AND stu_no LIKE '%").append(stuNo).append("%'"); // 添加学号过滤条件
}
if (!name.isEmpty()) {
strSQL.append(" AND name LIKE '%").append(name).append("%'"); // 添加姓名过滤条件
}
if (!clazz.isEmpty()) {
strSQL.append(" AND clazz LIKE '%").append(clazz).append("%'"); // 添加班级过滤条件
}
strSQL.append(" ORDER BY publish DESC"); // 按发布日期降序排列
execQuery(list, strSQL.toString()); // 执行查询
}
}

3.3 对象调用

完成以上创建后,基本完成了后端数据库的主要开发,剩下的就主要为前端调用的方式,我们需要创建一个初始化 StudentDao,使其能够使用 StudentDBHelper 提供的数据库访问功能。通过 StudentDao,可以执行对学生表的各种操作,例如添加、删除和查询学生记录。这样做的好处是将数据库操作的逻辑封装在 StudentDao 中,符合单一职责原则,使代码更清晰和可维护。

1
dao = new StudentDao(new StudentDBHelper(this));

那么我们可以通过一下对StudnetDao中的方法进行调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
//直接调用型
private void deleteStu(String stuNo) {
dao.deleteStudent(stuNo);
refreshStudentList();
}
//传参型
private void refreshStudentList() {
String stuNo = txtStuNo.getText().toString().trim();
String name = txtName.getText().toString().trim();
String clazz = txtClazz.getText().toString().trim();
dao.queryStudents(list, stuNo, name, clazz);
adapter.notifyDataSetChanged(); // 确保适配器已初始化
}

4. 总结

1.首先需要对SQLiteOpenHelper进行继承实现其中的onCreate用来创建一个数据表对象

2.创建持久化dao层,私有SQLiteDatabase对象,调用SQLiteDatabase对象的增删改查方法

3.主类中新建一个SQLiteOpenHelper的实现子类并交给SQLiteDatabase的dao层管理

4.在主类中调用dao对象应用dao层实现的方法

1
dao = new StudentDao(new StudentDBHelper(this));