SQLite数据库的创建和升级

news2024/9/23 7:30:17

SQLite数据库的创建和升级

在刚开始接触Android的时候,我甚至都不敢相信,Android系统竟然是内置了数据库的!好吧,是我太孤陋寡闻了。SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务,所以只要你以前使用过其他的关系型数据库,就可以很快地上手SQLite。而SQLite又比一般的数据库要简单得多,它甚至不用设置用户名和密码就可以使用。Android正是把这个功能极为强大的数据库嵌入到了系统当中,使得本地持久化的功能有了一次质的飞跃。

前面我们所学的文件存储和SharedPreferences存储毕竟只适用于保存一些简单的数据和键值对,当需要存储大量复杂的关系型数据的时候,你就会发现以上两种存储方式很难应付得了。比如我们手机的短信程序中可能会有很多个会话,每个会话中又包含了很多条信息内容,并且大部分会话还可能各自对应了电话簿中的某个联系人。很难想象如何用文件或者SharedPreferences来存储这些数据量大、结构性复杂的数据吧?但是使用数据库就可以做得到。那么我们就赶快来看一看,Android中的SQLite数据库到底是如何使用的。

创建数据库

Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类就可以非常简单地对数据库进行创建和升级。既然有好东西可以直接使用,那我们自然要尝试一下了,下面我就对SQLiteOpenHelper的基本用法进行介绍。

首先你要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。

SQLiteOpenHelper中还有两个非常重要的实例方法:getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式去打开数据库,而getWritableDatabase()方法则将出现异常。

SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收4个参数,第一个参数是Context,这个没什么好说的,必须要有它才能对数据库进行操作。第二个参数是数据库名,创建数据库时使用的就是这里指定的名称。第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般都是传入null。第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()或getWritableDatabase()方法就能够创建数据库了,数据库文件会存放在/data/data/<package name>/databases/目录下。此时,重写的onCreate()方法也会得到执行,所以通常会在这里去处理一些创建表的逻辑。

接下来还是让我们通过例子的方式来更加直观地体会SQLiteOpenHelper的用法吧,首先新建一个DatabaseTest项目。这里我们希望创建一个名为BookStore.db的数据库,然后在这个数据库中新建一张Book表,表中有id(主键)、作者、价格、页数和书名等列。创建数据库表当然还是需要用建表语句的,这里也是要考验一下你的SQL基本功了,Book表的建表语句如下所示:

create table Book (
id integer primary key autoincrement,
author text,
price real,
pages integer,
name text)

只要你对SQL方面的知识稍微有一些了解,上面的建表语句对你来说应该都不难吧。SQLite不像其他的数据库拥有众多繁杂的数据类型,它的数据类型很简单,integer表示整型,real表示浮点型,text表示文本类型,blob表示二进制类型。另外,上述建表语句中我们还使用了primary key将id列设为主键,并用autoincrement关键字表示id列是自增长的。然后需要在代码中去执行这条SQL语句,才能完成创建表的操作。新建MyDatabaseHelper类继承自SQLiteOpenHelper,代码如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
private Context mContext;
public MyDatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

可以看到,我们把建表语句定义成了一个字符串常量,然后在onCreate()方法中又调用了SQLiteDatabase的execSQL()方法去执行这条建表语句,并弹出一个Toast提示创建成功,这样就可以保证在数据库创建完成的同时还能成功创建Book表。现在修改activity_main.xml中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/create_database"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create database"
/>
</LinearLayout>

布局文件很简单,就是加入了一个按钮,用于创建数据库。最后修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
}

这里我们在onCreate()方法中构建了一个MyDatabaseHelper对象,并且通过构造函数的参数将数据库名指定为BookStore.db,版本号指定为1,然后在Create database按钮的点击事件里调用了getWritableDatabase()方法。这样当第一次点击Create database按钮时,就会检测到当前程序中并没有BookStore.db这个数据库,于是会创建该数据库并调用MyDatabaseHelper中的onCreate()方法,这样Book表也就得到了创建,然后会弹出一个Toast提示创建成功。再次点击Create database按钮时,会发现此时已经存在BookStore.db数据库了,因此不会再创建一次。现在就可以运行一下代码了,在程序主界面点击Create database按钮,结果如图所示:

在这里插入图片描述

此时BookStore.db数据库和Book表应该都已经创建成功了,因为当你再次点击Create database按钮时,不会再有Toast弹出。打开Android Studio 底部工具栏App Inspection查看,如图所示:

在这里插入图片描述

由此证明,BookStore.db数据库和Book表确实已经创建成功了。

升级数据库

如果你足够细心,一定会发现MyDatabaseHelper中还有一个空方法呢!没错,onUpgrade()方法是用于对数据库进行升级的,它在整个数据库的管理工作当中起着非常重要的作用,可千万不能忽视它哟。

目前DatabaseTest项目中已经有一张Book表用于存放书的各种详细数据,如果我们想再添加一张Category表用于记录图书的分类,该怎么做呢?

比如Category表中有id(主键)、分类名和分类代码这几个列,那么建表语句就可以写成:

create table Category (
id integer primary key autoincrement,
category_name text,
category_code integer)

接下来我们将这条建表语句添加到MyDatabaseHelper中,代码如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
public static final String CREATE_CATEGORY = "create table Category ("
+ "id integer primary key autoincrement, "
+ "category_name text, "
+ "category_code integer)";
private Context mContext;
public MyDatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK);
db.execSQL(CREATE_CATEGORY);
Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

看上去好像都挺对的吧?现在我们重新运行一下程序,并点击Create database按钮,咦?竟然没有弹出创建成功的提示。当然,你也可以通过adb工具到数据库中再去检查一下,这样你会更加地确认Category表没有创建成功!

其实没有创建成功的原因不难思考,因为此时BookStore.db数据库已经存在了,之后不管我们怎样点击Create database按钮,MyDatabaseHelper中的onCreate()方法都不会再次执行,因此新添加的表也就无法得到创建了。

解决这个问题的办法也相当简单,只需要先将程序卸载掉,然后重新运行,这时BookStore.db数据库已经不存在了,如果再点击Create database按钮,MyDatabaseHelper中的onCreate()方法就会执行,这时Category表就可以创建成功了。

不过,通过卸载程序的方式来新增一张表毫无疑问是很极端的做法,其实我们只需要巧妙地运用SQLiteOpenHelper的升级功能就可以很轻松地解决这个问题。修改MyDatabaseHelper中的代码,如下所示:

public class MyDatabaseHelper extends SQLiteOpenHelper {
...
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists Book");
db.execSQL("drop table if exists Category");
onCreate(db);
}
}

可以看到,我们在onUpgrade()方法中执行了两条DROP语句,如果发现数据库中已经存在Book表或Category表了,就将这两张表删除掉,然后再调用onCreate()方法重新创建。这里先将已经存在的表删除掉,因为如果在创建表时发现这张表已经存在了,就会直接报错。

接下来的问题就是如何让onUpgrade()方法能够执行了,还记得SQLiteOpenHelper的构造方法里接收的第四个参数吗?它表示当前数据库的版本号,之前我们传入的是1,现在只要传入一个比1大的数,就可以让onUpgrade()方法得到执行了。修改MainActivity中的代码,如下所示:

public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dbHelper.getWritableDatabase();
}
});
}
}

这里将数据库版本号指定为2,表示我们对数据库进行升级了。现在重新运行程序,并点击Create database按钮,这时就会再次弹出创建成功的提示。为了验证一下Category表是不是已经创建成功了,打开Android Studio 底部工具栏App Inspection查看,如图所示:

在这里插入图片描述

由此可以看出,Category表已经创建成功了,同时也说明我们的升级功能的确起到了作用。

如果对你有帮助,就一键三连呗(点赞+收藏+关注),我会持续更新更多干货~~

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

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

相关文章

开源通用验证码识别OCR —— DdddOcr 源码赏析(一)

文章目录 [toc] 前言DdddOcr环境准备安装DdddOcr使用示例 源码分析实例化DdddOcr实例化过程 分类识别分类识别过程 未完待续 前言 DdddOcr 源码赏析 DdddOcr DdddOcr是开源的通用验证码识别OCR 官方传送门 环境准备 安装DdddOcr pip install ddddocr使用示例 示例图片如…

Datawhale X 魔搭 AI夏令营第四期 魔搭-AIGC方向全过程笔记

task1: 传送门 task2&#xff1a; 传送门 task3: 传送门 目录 Task1 赛题内容 可图Kolors-LoRA风格故事挑战赛 baseline要点讲解(请配合Datawhale速通教程食用) Step1 设置算例及比赛账号的报名和授权 Step2 进行赛事报名并创建PAI实例 Step3 执行baseline Step4…

软件架构:架构模式、特征及实践指南-读书笔记(1)

第二章 架构思维 2.1 架构与设计 为了使架构落地&#xff0c;必须打破阻碍在架构师和开发人员之间的所有障碍&#xff0c;从而使架构师和开发团队之间形成双向的强关联。如图2-3所示&#xff0c;架构师和开发人员必须在同一个虚拟团队中才能使架构落地。该模型不仅促进了架构师…

关于使用conda安装opencv-python失败的解决方法

当你想使用conda环境安装opencv-python时&#xff0c;会弹出&#xff1a; conda install opencv-python Collecting package metadata (current_repodata.json): done Solving environment: failed with initial frozen solve. Retrying with flexible solve. Collecting packa…

【网络】网络基础概念背景TCP/IP 五层模型跨网络传输详解

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.计算机网络发展 1.1 独立模式 1.2 网络互联 1.3 局域网 LAN 1.4 广域网 WAN 2.协议 2.1 初识协议 2.2 协议分层 2…

应急响应:挖矿木马-实战 案例一.【Linux 系统-排查和删除】

什么是挖矿木马 挖矿木马是一种恶意软件&#xff0c;它在未经用户许可的情况下&#xff0c;利用用户的计算资源来挖掘加密货币&#xff0c;从而为攻击者带来非法收益。这类软件通常通过多种手段传播&#xff0c;例如利用系统漏洞、弱密码爆破、伪装正常软件等方法感染目标设备…

TI官网下载芯片原理图文件和封装文件导入Altium Designer 21.0.9

1、TI文件下载以 UCC27614为例 打开TI官网直接找到元器件资料界面 在设计与开发栏中找到封装模型文件下载 确认封装 选择封装导出的目标软件–AD 2、文件导入AD软件中 解压压缩包找到项目文件使用AD打开 导入AD输出芯片封装 打开UL_Import.pas然后点击Run 出现UL Import 选择…

20240818 每日AI必读资讯

3人干翻谷歌&#xff01;免费学术搜索比谷歌学术相关性高5倍&#xff0c;已获YC投资 - 三人团队打造的学术搜索引擎&#xff1a;Lumina - 目前已处理了超30万次查询&#xff0c;支持24种语言 - 号称搜索结果相关性平均比谷歌学术高5倍&#xff0c;能搜索超1亿个研究对象&…

类和对象(下)(1)

类和对象&#xff08;下&#xff09; 再探构造函数 我们之前在实现构造函数的时候&#xff0c;初始化成员变量使用的方式都是在函数体内进行赋值&#xff0c;其实构造函数初始化成员变量还有一种方式&#xff1a;初始化列表。 初始化列表不只是为了写得方便&#xff0c;还能解…

信用贷款“并发”能做多少?“并发”前,得做好几件事

最近&#xff0c;咱们聊聊一个挺热门的话题——信用贷的“并发”现象&#xff0c;还有大家最关心的&#xff0c;信用贷款并发能做多少&#xff1f;“并发”操作过程中哪些是需要注意的。 信用贷款并发能做多少&#xff1f; 信用贷能贷多少&#xff0c;这事儿得从俩角度考虑&am…

问题: vue--elementUI 关于 Drawer 抽屉能打开而受蒙版影响不能正常关闭问题解决

对于一个后端为主的小白来说&#xff0c;刚接手Element 遇到的第一个大问题。 vue–elementUI 关于 Drawer 抽屉能打开而受蒙版影响不能正常关闭问题解决> 分享并且记录一下下 其实问题很简单。我们既然能打开。先定位问题。 当我们发现到问题的时候&#xff0c;我觉得应该 …

基于javaEE的校园二手书交易平台的设计与实现

TOC springboot287基于javaEE的校园二手书交易平台的设计与实现 第1章 绪论 1.1 研究背景 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这个…

NGINX 基础参数与功能

章节 1 NGINX 的源码安装 2 NGINX 核心配置详解 3 NGINX 之 location 匹配优先级 4 NGINX 基础参数与功能 目录 1 实现 Nginx 账户认证功能 1.1 创建htpasswd 认证文件 1.2 创建数据目录 1.3 指定认证文件路径 1.4 测试效果 2 定义重定向错误日志 2.1 指定错误日志访问路…

深度学习的量化和剪枝

一&#xff1a;背景 如果要将深度学习的AI模型部署到受限设备&#xff08;FPGA&#xff09;上&#xff0c;往往需要更小的存储需求和最低的计算复杂度。当然&#xff0c;还得保持一定的性能&#xff08;下降在能够接受的范围&#xff09;。受限设备资源的环境&#xff0c;一般是…

掌握ChatGPT写作艺术:从入门到精通的四个层次

这些周末我仔细研究了如何通过优化提示词提升ChatGPT输出内容的质量。 关于如何使用ChatGPT辅助我们的写作&#xff0c;我归纳了以下规律&#xff0c;希望能为你带来启发。 一、写作步骤 撰写一篇文章&#xff0c;思路上必须是从抽象到具体逐步深入。 首先我们需要明确写什么…

【数据结构与算法】冒泡排序

冒泡排序目录 一.冒泡排序原理二.图示三.冒泡排序具体实现四.冒泡排序升级版五.完整代码 一.冒泡排序原理 还是老样子,我们如何对这个进行排序呢? 冒泡排序的原理是,将两两进行比较,如果前面较大的我们就进行交换到后面. 然后再对交换后的这个和下一个进行比较,一轮过后,最大值…

spfa()算法(求最短路)

spfa算法是对bellman_ford算法的优化&#xff0c;大部分求最短路问题都可以用spaf算法来求。 注意&#xff1a; &#xff08;1&#xff09;如若图中有负权回路&#xff0c;不能用spfa算法&#xff0c;要用bellman_ford算法&#xff1b;若只有负权边&#xff0c;则可以用 spf…

Feign的基本使用

一、在项目中引入相关的依赖 创建两个微服务,分别为userservice、orderservice 现在需要在orderservie中查询用户相关的数据,所以需要使用feign进行远程调用userservice 1.1、在orderservice的pom.xml文件中添加下面的依赖 <dependency><groupId>org.springfram…

疫情居家办公系统--论文pf

TOC springboot394疫情居家办公系统--论文pf 第1章 绪论 1.1 课题背景 伴随着科技的进步&#xff0c;电子计算机已经成为人们日常生活不可或缺的办公工具。在这样的背景下&#xff0c;互联网技术被用于各个领域。为了能提高日常生活高效率&#xff0c;互联网信息技术性蓬勃…