SQLite在安卓中的应用

在 Android 应用程序中,SQLite 是默认的嵌入式数据库解决方案,Android 系统为开发者提供了相应的 API 来管理 SQLite 数据库。通过使用 SQLiteOpenHelper 类和 SQLiteDatabase 类,开发者可以方便地创建、查询、更新和删除数据库中的数据。

以下是关于如何在 Android 中使用 SQLite 的详细介绍和示例。


一、在 Android 中使用 SQLite 的步骤

1. 创建 SQLiteOpenHelper 类

SQLiteOpenHelper 是一个辅助类,用于管理数据库的创建和版本管理。它提供了两个重要的方法:

  • onCreate(SQLiteDatabase db):当数据库第一次创建时调用。
  • onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):当数据库需要升级时调用。

示例:创建 SQLiteOpenHelper 子类

public class MyDatabaseHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "MyDatabase.db";  // 数据库名称private static final int DATABASE_VERSION = 1;                // 数据库版本public MyDatabaseHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);}// 第一次创建数据库时调用@Overridepublic void onCreate(SQLiteDatabase db) {// 创建数据库中的表String CREATE_TABLE = "CREATE TABLE users ("+ "id INTEGER PRIMARY KEY AUTOINCREMENT,"+ "name TEXT NOT NULL,"+ "age INTEGER,"+ "email TEXT);";db.execSQL(CREATE_TABLE);}// 当数据库版本升级时调用@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 如果表已存在则删除,重新创建db.execSQL("DROP TABLE IF EXISTS users");onCreate(db);}
}
  • DATABASE_NAME 定义了数据库的名称。
  • DATABASE_VERSION 是数据库的版本号,每当数据库结构发生变化时,需要升级版本号。
  • onCreate() 方法在数据库首次创建时调用,执行 SQL 语句来创建数据库中的表。
  • onUpgrade() 方法在数据库需要升级时调用,可以用于处理表结构的变更。
2. 打开数据库

使用 SQLiteOpenHelper 类时,可以通过调用 getWritableDatabase()getReadableDatabase() 方法来打开数据库。前者允许执行写操作,而后者只允许执行读操作。

MyDatabaseHelper dbHelper = new MyDatabaseHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
3. 插入数据

使用 insert() 方法将数据插入到表中。

// 创建一个 ContentValues 对象,用于存储键值对
ContentValues values = new ContentValues();
values.put("name", "Alice");
values.put("age", 25);
values.put("email", "alice@example.com");// 插入数据
long newRowId = db.insert("users", null, values);
  • ContentValues 类用于保存列名与列值的映射。
  • insert() 方法将数据插入到指定的表中,返回插入数据的行 ID。
4. 查询数据

使用 query() 方法从数据库中查询数据。该方法返回一个 Cursor 对象,用于遍历查询结果。

// 定义要查询的列
String[] projection = {"id","name","age","email"
};// 查询数据
Cursor cursor = db.query("users",   // 表名projection,   // 要返回的列null,         // WHERE 子句null,         // WHERE 子句的参数null,         // GROUP BY 子句null,         // HAVING 子句null          // 排序方式
);// 遍历查询结果
while (cursor.moveToNext()) {long userId = cursor.getLong(cursor.getColumnIndexOrThrow("id"));String userName = cursor.getString(cursor.getColumnIndexOrThrow("name"));int userAge = cursor.getInt(cursor.getColumnIndexOrThrow("age"));String userEmail = cursor.getString(cursor.getColumnIndexOrThrow("email"));
}// 关闭游标
cursor.close();
  • projection 定义了需要查询的列。
  • Cursor 对象用于从查询结果中提取数据,moveToNext() 方法用于遍历结果集。
5. 更新数据

使用 update() 方法更新表中的数据。

// 创建 ContentValues 对象
ContentValues values = new ContentValues();
values.put("age", 26);// 更新记录
String selection = "name = ?";
String[] selectionArgs = { "Alice" };int count = db.update("users",    // 表名values,     // 要更新的值selection,  // WHERE 子句selectionArgs  // WHERE 子句的参数
);
  • update() 方法根据指定的条件更新表中的记录,返回受影响的行数。
6. 删除数据

使用 delete() 方法删除表中的数据。

// 定义删除条件
String selection = "name = ?";
String[] selectionArgs = { "Alice" };// 删除记录
int deletedRows = db.delete("users", selection, selectionArgs);
  • delete() 方法根据指定的条件删除表中的记录,返回删除的行数。

二、数据库操作的异步处理

在 Android 中,数据库操作通常需要在子线程中进行,以避免在主线程上执行耗时操作,防止阻塞 UI。

可以使用 AsyncTaskHandlerThreadJetpack 提供的 Room 库来简化和管理异步的数据库操作。

使用 Room 作为 SQLite 的抽象层

Room 是 Android Jetpack 提供的一个持久性库,它简化了与 SQLite 的交互,并且支持异步查询。使用 Room 可以避免手动编写大量的 SQL 代码,并提供类型安全的 API。

Room 的基础组件:
  1. 实体 (Entity):对应数据库中的表。
  2. DAO (Data Access Object):定义数据操作方法。
  3. 数据库 (Database):数据库持有者,管理实体和 DAO。

示例:使用 Room 管理数据库

  1. 定义实体类:
@Entity
public class User {@PrimaryKey(autoGenerate = true)public int id;public String name;public int age;public String email;
}
  1. 定义 DAO 接口:
@Dao
public interface UserDao {@Insertvoid insertUser(User user);@Query("SELECT * FROM User WHERE id = :id")User getUserById(int id);@Updatevoid updateUser(User user);@Deletevoid deleteUser(User user);
}
  1. 创建数据库类:
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {public abstract UserDao userDao();
}
  1. 初始化 Room 数据库:
AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "MyDatabase").build();// 在子线程中执行数据库操作
new Thread(() -> {User user = new User();user.name = "Alice";user.age = 25;user.email = "alice@example.com";db.userDao().insertUser(user);
}).start();

三、SQLite 数据库备份和恢复

由于 SQLite 数据存储在一个单一的文件中,因此备份和恢复操作非常简单。可以直接复制数据库文件来备份或恢复数据。

备份数据库文件:

File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(dbFile).getChannel();FileChannel dst = new FileOutputStream(backupFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}

恢复数据库文件:

File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(backupFile).getChannel();FileChannel dst = new FileOutputStream(dbFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}

四、SQLite 数据库的性能优化

  1. 使用索引:为经常查询的列创建索引可以显著提升查询速度。

    CREATE INDEX idx_user_name ON users(name);
    
  2. 事务处理:将多个操作放在一个事务中执行,可以减少磁盘 I/O,从而提高性能。

    BEGIN TRANSACTION;
    -- 执行多条 SQL 语句
    COMMIT;
    
  3. 按需加载数据:在查询大量数据时,使用分页查询减少内存消耗。

    SELECT * FROM users LIMIT 10 OFFSET 20;
    

通过上述步骤,开发者可以轻松在 Android 中集成并使用 SQLite 数据库。为了进一步深入理解,接下来将继续介绍 SQLite 在 Android 中的性能优化、常见的最佳实践,以及在不同场景下的高级用法。


五、SQLite 在 Android 中的性能优化

SQLite 数据库在 Android 应用中处理小规模数据时表现非常优异,但当数据量增大时,可能会面临性能问题。以下是几种常见的性能优化方法:

1. 使用事务

将多条 SQL 操作放在一个事务中可以显著提升数据库操作的效率。SQLite 的每一条独立的插入或更新操作都会触发一次磁盘写操作,增加了 I/O 的开销。如果将多条插入或更新操作包裹在同一个事务中,则只会有一次磁盘写入,减少了 I/O 操作,极大提高了性能。

示例:使用事务插入多条记录

db.beginTransaction();
try {for (User user : userList) {ContentValues values = new ContentValues();values.put("name", user.getName());values.put("age", user.getAge());values.put("email", user.getEmail());db.insert("users", null, values);}db.setTransactionSuccessful();  // 标记事务成功
} finally {db.endTransaction();  // 结束事务
}
  • db.beginTransaction() 开启事务。
  • db.setTransactionSuccessful() 在事务成功时调用。
  • db.endTransaction() 结束事务。
2. 使用索引 (Indexing)

为常用查询的列创建索引,可以加速查询速度。索引本质上是表中特定列的排序结构,它减少了查询时的扫描行数。

创建索引的示例:

CREATE INDEX idx_user_name ON users(name);

注意,虽然索引可以加快查询速度,但也会增加插入和更新操作的开销,因此应根据需要平衡索引的使用。

3. 减少数据查询

在查询数据时,避免使用 SELECT * 来检索所有列,尽量只查询需要的列,减少不必要的数据传输。

示例:只查询需要的列

String[] projection = {"id","name"
};
Cursor cursor = db.query("users",projection,null,null,null,null,null
);
4. 使用批量操作

在处理大批量数据操作时,使用批量插入、更新或删除可以提高操作效率。批量操作可以通过事务和 SQLiteStatement 提高性能。

批量插入示例:

SQLiteStatement stmt = db.compileStatement("INSERT INTO users (name, age, email) VALUES (?, ?, ?)");db.beginTransaction();
try {for (User user : userList) {stmt.bindString(1, user.getName());stmt.bindLong(2, user.getAge());stmt.bindString(3, user.getEmail());stmt.execute();stmt.clearBindings();}db.setTransactionSuccessful();
} finally {db.endTransaction();
}
5. 使用 PRAGMA 进行性能调优

SQLite 提供了许多 PRAGMA 命令,允许开发者动态配置数据库的行为,从而提升性能。例如:

  • PRAGMA synchronous = OFF;:关闭同步写入,提升写入速度(在数据一致性不是首要关注时使用)。
  • PRAGMA journal_mode = WAL;:将数据库设置为“写入时日志”模式,这样可以在高并发读写的场景下提升性能。

示例:设置 WAL 模式

PRAGMA journal_mode = WAL;

在 WAL 模式下,写操作不会直接覆盖原数据,而是记录在日志中,并在空闲时间将日志内容合并回主数据库文件,从而提高并发读写的性能。


六、SQLite 的最佳实践

1. 善用 ContentValues 和 Cursor
  • 使用 ContentValues 来存储插入或更新的数据,不仅简化了代码,还提高了可读性。
  • 使用 Cursor 遍历查询结果时,始终在使用后关闭 Cursor,防止内存泄漏。

关闭 Cursor 示例:

Cursor cursor = db.query("users", null, null, null, null, null, null);
try {while (cursor.moveToNext()) {// 获取数据}
} finally {cursor.close();  // 确保 cursor 关闭
}
2. 使用 Room 框架

在复杂的 Android 应用程序中,直接使用 SQLite 可能会导致 SQL 语句冗长、难以维护。为了简化与 SQLite 的交互,推荐使用 Room 框架,它提供了类型安全的 API,并能与 LiveData 和 RxJava 轻松集成,实现异步查询操作。

3. 避免在主线程进行数据库操作

数据库操作可能会耗时较长,尤其是在处理大数据集或网络存储时。为了避免 UI 卡顿,务必在工作线程中执行数据库操作。可以使用 AsyncTaskExecutorService 或 Room 提供的异步操作方法。

示例:使用 ExecutorService 进行异步操作

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {// 在后台线程中执行数据库操作db.userDao().insertUser(user);
});
4. 确保数据库版本管理

当数据库的结构发生变化时,需要通过增加数据库的版本号并在 onUpgrade() 中进行适当的迁移操作,以确保数据的完整性。

版本升级示例:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {if (oldVersion < 2) {db.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");}
}

通过这种方式,可以安全地向数据库表中添加新字段,而不会破坏现有数据。


七、SQLite 高级用法

1. 数据库加密

Android 系统默认的 SQLite 数据库是不加密的。如果需要对敏感数据进行加密,可以使用 SQLCipher 这样的第三方库。SQLCipher 是对 SQLite 的增强版,提供了对数据库文件的透明加密支持。

使用 SQLCipher 加密数据库:

  1. 添加依赖:
implementation 'net.zetetic:android-database-sqlcipher:4.5.0'
  1. 创建或打开加密数据库:
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(databaseFile, "your-password", null);

通过加密,数据在数据库文件中存储时将是加密的,即使文件被拷贝,未经授权的用户也无法直接查看数据。

2. 数据库迁移

当应用程序的数据库架构需要更新时,必须处理好数据迁移。Room 框架提供了方便的迁移机制,可以帮助开发者在数据库版本升级时保持数据的完整性。

Room 迁移示例:

Migration MIGRATION_1_2 = new Migration(1, 2) {@Overridepublic void migrate(@NonNull SupportSQLiteDatabase database) {database.execSQL("ALTER TABLE users ADD COLUMN phone TEXT");}
};Room.databaseBuilder(context, AppDatabase.class, "MyDatabase").addMigrations(MIGRATION_1_2).build();

通过 Room 的迁移功能,数据库的版本升级变得更加安全和可控。

3. 数据库备份与恢复

SQLite 的备份和恢复操作可以通过文件操作来实现。开发者可以直接复制 SQLite 数据库文件以创建备份,或者通过将文件移动到安全的存储位置来进行恢复。

示例:备份数据库文件到外部存储

File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(dbFile).getChannel();FileChannel dst = new FileOutputStream(backupFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}

示例:从备份文件恢复数据库

File dbFile = context.getDatabasePath("MyDatabase.db");
File backupFile = new File(Environment.getExternalStorageDirectory(), "MyDatabase_backup.db");try (FileChannel src = new FileInputStream(backupFile).getChannel();FileChannel dst = new FileOutputStream(dbFile).getChannel()) {dst.transferFrom(src, 0, src.size());
} catch (IOException e) {e.printStackTrace();
}

总结

SQLite 是一个轻量、可靠、简单易用的数据库解决方案,特别适合嵌入式系统和移动应用中的数据存储需求。通过 Android 提供的 API,开发者可以轻松地实现数据持久化功能。在实际开发中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1559915.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【SQL】收入更高的员工

目录 语法 需求 示例 分析 代码 语法 FROM Employee a, Employee b 两个表之间笛卡尔积&#xff08;Cartesian product&#xff09;的形式&#xff0c;用了逗号分隔的连接&#xff08;comma-separated join&#xff09;&#xff0c;这是早期SQL语法中用于连接表的一种方式…

TikTok 伪装度分析:揭开社交媒体的真实面纱

在现代社交媒体中&#xff0c;TikTok凭借其短视频的形式和算法推荐的机制&#xff0c;迅速吸引了大量用户。然而&#xff0c;随着用户基数的扩大&#xff0c;平台上的内容呈现出多样化的趋势&#xff0c;而“伪装度”这一概念也逐渐成为我们分析TikTok内容质量和用户行为的重要…

SpringBoot使用esayExcel根据模板导出excel

1、依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.3</version></dependency> 2、模板 3、实体类 package com.skybird.iot.addons.productionManagement.qualityTesting…

泰始明昌文旅:如何打造真正的文旅爆品体系

泰始明昌文旅&#xff1a;如何打造真正的文旅爆品体系 泰始明昌文旅&#xff1a;如何打造真正的爆品体系 关键词&#xff1a;泰始明昌文旅,文旅爆品,核心卖点,用户痛点,项目特点,对手弱点,爆品体系,爆品品类,结构化,品质,价值链接,生态体系,营销推广,持续创新 摘要&#xff…

接口和多态

接口 概念 接口是功能的集合&#xff0c;它同样是一种引用数据类型&#xff0c;可以把接口看作抽象类更为抽象的 "类"。 接口只描述所应该具备的功能方法&#xff0c;但是没有具体的方法实现&#xff0c;即接口中具有的都是抽象方法&#xff0c;这些抽象方法的实现是…

美发店业务流程优化:SpringBoot管理系统

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

Java | Leetcode Java题解之第468题验证IP地址

题目&#xff1a; 题解&#xff1a; class Solution {public String validIPAddress(String queryIP) {if (queryIP.indexOf(.) > 0) {// IPv4int last -1;for (int i 0; i < 4; i) {int cur (i 3 ? queryIP.length() : queryIP.indexOf(., last 1));if (cur <…

汽车3d动效的作用!云渲染实现3d动效

在汽车营销领域&#xff0c;3D动效技术以其独特的视觉冲击力和交互体验&#xff0c;正成为吸引消费者注意力的新利器。而云渲染技术的应用&#xff0c;更是让这些动效如虎添翼&#xff0c;实现了高效、低成本的3D视觉内容制作与分享。本文将探讨汽车3D动效的作用&#xff0c;并…

java中的I/O(8个案例+代码+效果图)

目录 1.File类 1&#xff09;常用构造方法 1&#xff09;File(String pathname) 2&#xff09;File(String parent, String child) 3&#xff09;File(File parent, String child) 2&#xff09;常用方法 1&#xff09;boolean canRead() 2&#xff09;boolean canWrite() 3&am…

SiLM266x系列SiLM2661高压电池组前端充/放电高边NFET驱动器 为电池系统保护提供可靠性和设计灵活性

SiLM2661产品概述&#xff1a; SiLM2661能够灵活的应对不同应用场景对锂电池进行监控和保护的需求&#xff0c;为电池系统保护提供可靠性和设计灵活性。是用于电池充电/放电系统控制的低功耗、高边 N 沟道 FET 驱动器&#xff0c;高边保护功能可避免系统的接地引脚断开连接&am…

Linux云计算 |【第四阶段】RDBMS2-DAY2

主要内容&#xff1a; 数据读写分离概述、Maxscale实现数据读写分离、多实例配置、中间件概述 一、数据读写分离概述 数据读写分离&#xff08;Read/Write Splitting&#xff09;是一种数据库架构设计模式&#xff0c;旨在提高数据库系统的性能、可扩展性和可用性。通过将读操…

how to increase the height of the ps or cdm window

when the line reaches the bottom; directly pull up the top bar of the window after pulling down the bar

Llama-3.2-3B-Instruct PyTorch模型微调最佳实践

1 引言 Meta Llama 3.2多语言大型语言模型集合&#xff08;LM&#xff09;是一个1B和3B大小&#xff08;文本输入/文本输出&#xff09;的预训练和指令微调模型集合。Llama 3.2指令调整的纯文本模型针对多语言对话用例进行了优化&#xff0c;包括智能检索和总结任务。它们在常…

Vue组件继承与扩展

Vue组件继承与扩展 前言 与Class继承类似&#xff0c;在Vue中可以通过组件继承来达到复用和扩展基础组件的目的&#xff0c;虽然它可能会带来一些额外的性能损耗和维护成本&#xff0c;但其在解决一些非常规问题时有奇效。本文将通过一些非常规的功能需求来讨论其实现过程。 …

锐明Crocus系统 RepairRecord.do SQL注入漏洞

0x01 产品描述&#xff1a; 明锐技术是一家专注于AI和视频技术的商用车智能物联&#xff08;AIoT&#xff09;解决方案提供商&#xff0c;Crocus系统是其核心产品之一。该系统旨在利用人工智能、高清视频、大数据和自动驾驶技术&#xff0c;提高企业或车队的运营效率&#xff0…

python31_format方法的使用

format方法的使用 def str_format(c, d):"""格式化字符串函数本函数的目的是通过给定的参数c和d&#xff0c;去填充一个预设的字符串模板。模板中包含了{name1}和{name2}两个占位符&#xff0c;分别用参数c和d的值来替换。这个过程演示了Python中字符串格式化的…

AR虚拟试用,让网购不再只靠想象!

在数字化浪潮席卷全球的今天&#xff0c;电子商务已成为我们日常生活中不可或缺的一部分。然而&#xff0c;传统的网购体验往往受限于二维图片和文字描述&#xff0c;消费者在购买前只能依靠想象来构建商品的模样与适用性&#xff0c;这无疑增加了购物的不确定性和风险。幸运的…

基于卷积神经网络的脊柱骨折识别系统,resnet50,mobilenet模型【pytorch框架+python】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于卷积神经网络的脊柱骨折识别系统&#xff0c;resnet50&#xff0c;mobilenet【pytorch框架&#xff0c;python&#xff0c;tkinter】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于卷…

Java面试宝典-Java集合02

目录 Java面试宝典-Java集合02 21、TreeMap 和 TreeSet 在排序时如何比较元素&#xff1f; 22、ArrayList 和 LinkedList 的区别是什么&#xff1f; 23、ArrayList 和 Vector 的区别&#xff1f; 24、队列和栈是什么&#xff1f;有什么区别&#xff1f; 25、Queue和Deque的区别…

版本控制系统Helix Core的常见使用误区及解决办法、实用工具及新功能介绍

日前&#xff0c;Perforce携手合作伙伴龙智一同亮相Unreal Fest 2024上海站&#xff0c;分享Helix Core版本控制系统及其协作套件的强大功能与最新动态&#xff0c;助力游戏创意产业加速前行。 Perforce解决方案工程师Kory Luo在活动主会场&#xff0c;带来《Perforce Helix C…