2023年6月21日发(作者:)
Android学习之SQLite数据库存储•引⾔概念 SQLite数据库,和其他的SQL数据库不同, 我们并不需要在⼿机上另外安装⼀个数据库软件,Android系统已经集成了这个数据库;特点SQLite是⼀个轻量级的关系型数据库,运算速度快,占⽤资源少,很适合在移动设备上使⽤不仅⽀持标准SQL语法,还遵循ACID(数据库事务)原则,⽆需账号,使⽤起来⾮常⽅便SQLite⽀持五种数据类型NULLinteger(整型)real(浮点型)text(⽂本类型)blob(⼆进制类型)SQLite 通过⽂件来保存数据库
⼀个⽂件就是⼀个数据库数据库中⼜包含多个表格表格⾥⼜有多条记录每条记录由多个字段构成每个字段都有对应的值•创建数据库 Android为了让我们能够更加⽅便地管理数据库,专门提供了⼀个 SQLiteOpenHelper 帮助类; 借助这个类就可以⾮常简单地对数据库进⾏创建和升级。
SQLiteOpenHelper 是⼀个抽象类,这意味着如果我们想要使⽤它的话,就需要创建⼀个⾃⼰的帮助类去继承它; SQLiteOpenHelper 中有两个抽象⽅法,分别是
oncreate() 和
onUpgrade() ;
onCreate(database) : 数据库第⼀次被创建时被调⽤
onUpgrade(database,oldVersion,newVersion) : 在数据库的版本发⽣变化时会被调⽤⼀般在软件升级时才需改变版本号,⽽数据库的版本是由程序员控制的假设数据库现在的版本是 1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新⽤户⼿机⾥的数据库表结构为了实现这⼀⽬的,可以把原来的数据库版本设置为 2,或者其他与旧版本号不同的数字即可 我们必须在⾃⼰的帮助类⾥⾯重写这两个⽅法,然后分别在这两个⽅法中去实现 创建、升级数据库 的逻辑。
SQLiteOpenHelper 中还有两个⾮常重要的实例⽅法:
getReadableDatabase() 和
getWritableDatabase() 。 这两个⽅法都可以 创建或打开 ⼀个现有的数据库(如果数据库已存在则直接打开,否则创建⼀个新的数据库), 并返回⼀个可对数据库进⾏读写操作的对象。 不同的是,当数据库不可写⼊的时候(如磁盘空间已满):
getReadableDatabase() ⽅法返回的对象将以只读的⽅式去打开数据库
getWritableDatabase() ⽅法则将出现异常 SQLiteOpenHelper 中有三个构造⽅法可供重写,⼀般使⽤参数少⼀点的那个:
SQLiteOpenHelper(Context context, String name, Factory factory, int version)
该构造⽅法中接收四个参数:
Context context :这个没什么好说的,必须有这个才能对数据库进⾏操作
String name :第⼆个参数是数据库名,创建数据库时使⽤的就是这⾥指定的名称
Factory factory :第三个参数允许我们在查询数据的时候返回⼀个⾃定义的 Cursor,⼀般都是传⼊null
int version :第四个参数表⽰当前数据库的版本号,可⽤于对数据库进⾏升级操作 构建出 SQLiteOpenHelper 的实例之后,再调⽤它的
getReadableDatabase() 或
getWritableDatabase() ⽅法就能够创建数据库了; 数据库⽂件会存放在
/data/data/
onCreate() ⽅法也会得到执⾏,所以通常会在这⾥去处理⼀些创建表的逻辑。•通过代码深⼊理解准备⼯作 ⾸先新建⼀个 TestDatabase 项⽬。 在该项⽬中新建 MyDatabaseHelper 类,继承⾃ SQLiteOpenHelper;blic class MyDatabaseHelper extends SQLiteOpenHelper { public static final String CREATE_BOOK = "create table Book (" + "id integer primary key autoincrement," + "name text," + "price real)"; private Context mContext; public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable Factory factory, int version) { super(context, name, factory, version); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { L(CREATE_BOOK); xt(mContext,"Create Succeeded!",_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }} 可以看到,我们把建表语句定义成了⼀个字符串常量,然后在
onCreate() 中调⽤了
L(CREATE_BOOK); 去执⾏这条建表语句; 之后,弹出⼀个 Toast 提⽰建表成功,这样就可以保证在数据库创建的同时创建 Book 表; 在 SQL 中,Book 表的建表语句如下:CREATE TABLE Book( id INTEGER PRIMARY KEY autoincrement, NAME TEXT, price REAL); 其中,设置 id 为 primary key,并⽤ autoincrement 关键字表⽰ id 列是⾃增长的。 接下来,修改 activity_ 中的代码;activity_
onCreate() ⽅法中构建了⼀个 MyDatabaseHelper 对象,并且通过构造函数的参数将数据库名指定为 ,版本号指定为1; 然后在 Create按钮 的点击事件⾥调⽤了
getWritableDatabase() ⽅法; 这样当第⼀次点击 Create按钮 时,就会检测到当前程序中并没有 这个数据库, 于是会创建该数据库并调⽤ MyDatabaseHelper 中的
onCreate() ⽅法,这样 Book 表也就得到了创建,然后会弹出⼀个 Toast 提⽰创建成功。 再次点击 Create按钮 时,会发现此时已经存在 数据库了,因此不会再创建⼀次。运⾏效果 此时 数据库 和 Book表 应该都已经创建成功了,因为当你再次点击 Create按钮 时,不会再有 Toast 弹出; 可是怎样才能证实它们的确创建成功了? 打开 Android Device Monitor(不知道什么是 ADM 的⼩伙伴可以参考我的这篇博客), 找到
/data/data/tabase/databases/ ⽬录: 你会发现该⽬录下多了⼀个 ⽂件,但是看不到 Book 表,这可如何是好? 下⾯介绍⼀下通过使⽤ adb shell ⽅式来对数据库和表的创建情况进⾏检查。通过 adb 调试 adb 是 Android SDK 中⾃带的⼀个调试⼯具,使⽤这个⼯具可以直接对连接在电脑上的⼿机或模拟器进⾏调试操作; 它存放在 Android SDK 的 platform-tools ⽬录下,如果想要在命令⾏中使⽤这个⼯具,就需要先把它的路径配置到环境变量中; 如果不知道你的 Android SDK 安装在哪的⼩伙伴,可以通过以下⽅式找到: 点击【Tools】->【SDK Manager】; 找到 Android SDK 的安装路径; 在【电脑】中打开该路径,并找到【platform-tools】⽂件夹; 复制该路径,打开【环境变量】,在【系统变量】⾥找到【Path】并点击编辑,将 platform-tools ⽬录配置进去即可; 配置好了环境变量后,就可以使⽤ adb ⼯具了; 通过【Win+R】打开命令⾏界⾯,输⼊ adb shell,就会进⼊到设备的控制台; 其中,# 符号是超级管理员的意思,也就是说,现在你可以访问模拟器中的⼀切数据; 如果你的命令⾏上显⽰的是 $,那么就表⽰你现在是普遍管理员,需输⼊ su 命令切换成超级管理员,这样才能执⾏以下操作; 接下来使⽤ cd 命令进⼊到
/data/data/tabase/databases/ ⽬录下; (偷偷告诉你,⿏标右击可以实现粘贴功能) 使⽤ ls 命令查看该⽬录⾥的⽂件; 这个⽬录下出现了两个数据库⽂件,⼀个正是我们创建的 ; ⽽另⼀个 -journal 则是为了让数据库能够⽀持事务⽽产⽣的临时⽇志⽂件,通常情况下这个⽂件的⼤⼩都是 0 字节; 接下来我们就要借助 sqlite 命令来打开数据库了,只需要键⼊【sqlite3 数据库名】即可; 这时就已经打开了 数据库,现在就可以对这个数据库中的表进⾏管理了; ⾸先来看⼀下⽬前数据库中有哪些表,键⼊ .table 命令; 可以看到,此时数据库中有两张表:android_metadata表 是每个数据库中都会⾃动⽣成的,不⽤管它⽽另外⼀张 Book表 就是我们在 MyDatabaseHelper 中创建的了 这⾥还可以通过 .schema 命令来查看它们的建表语句; 由此证明,数据库 和 Book表 确实已经创建成功了; 之后键⼈ .exit 或 .quit 命令可以退出数据库的编辑,再键⼊ exit 命令就可以退出设备控制台了。通过 SQLite Expert 调试 当然,除了使⽤ adb ⼯具外,还可以通过使⽤ SQLite 可视化管理⼯具来查看; SQLite Expert 是⼀款功能强⼤的 SQLite 可视化管理⼯具,SQLite Expert 允许⽤户在 SQLite 服务器上执⾏创建、编辑、复制、提取等操作。 可以帮我们查看 SQLite 数据库以及⽣成 SQLite 数据库; 【】,我下载的是这个版本【】; 通过 Android Device Monitor 找到 ⽂件,导出到本地(选中 后选择右上⾓的导出按钮保存到本地); 并通过 SQLite Expert 打开该⽂件; 相⽐于使⽤ adb 调试,真的是简单粗暴,接下来就通过 SQLite Expert 调试了;升级数据库 如果你⾜够细⼼,⼀定会发现 MyDatabaseHelper中还有⼀个空⽅法呢; 没错,
onUpgrade() ⽅法是⽤于对数据库进⾏升级的,它在整个数据库的管理⼯作当中起着⾮常重要的作⽤,可千万不能忽视。
⽬前 DatabaseTest项⽬ 中已经有⼀张 Book表 ⽤于存放书的各种详细数据; 如果我们想再添加⼀张Category表⽤于记录图书的分类,该怎么做呢? ⽐如 Category表中有 id(主键)、分类名和分类代码 这⼏个列,那么建表语句就可以写成:CREATE TABLE Category( id INTEGER PRIMARY KEY , category_name TEXT, category_code INTEGER); 接下来将这条建表语句添加到 MyDatabaseHelper 中,修改 中的代码;blic class MyDatabaseHelper extends SQLiteOpenHelper { private Context mContext; public MyDatabaseHelper(...) {...} @Override public void onCreate(SQLiteDatabase db) { L(CREATE_BOOK);
L("CREATE TABLE Category(" + "id INTEGER PRIMARY KEY ," + "category_name TEXT," + "category_code INTEGER)"); xt(mContext,"Create Succeeded!",_SHORT).show(); } @Override public void onUpgrade(...) {...}} 看上去好像都挺对的吧? 现在我们重新运⾏⼀下程序,并点击 Create按钮,你会发现,没有弹出创建成功的提⽰。 当然,你也可以通过 SQLite Expert⼯具 到数据库中再去检查⼀下,这样你会更加地确认 Category表 没有创建成功。
其实没有创建成功的原因不难思考,因为此时 数据库 已经存在了, 之后不管我们怎样点击 Create按钮,MyDatabaseHelper 中的
onCreate() ⽅法都不会再次执⾏,因此新添加的表也就⽆法得到创建了。
解决这个问题的办法也相当简单,只需要先将程序卸载掉,然后重新运⾏,这时 数据库 已经不存在了; 如果再点击 Create按钮,MyDatabaseHelper 中的
onCreate() ⽅法就会执⾏,这时 Category表 就可以创建成功了。 不过,通过卸载程序的⽅式来新增⼀张表毫⽆疑问是很极端的做法; 其实我们只需要巧妙地运⽤ SQLiteOpenHelper 的升级功能就可以很轻松地解决这个问题; 修改 中的代码;blic class MyDatabaseHelper extends SQLiteOpenHelper { ... public MyDatabaseHelper(...) {...} @Override public void onCreate(SQLiteDatabase db) {...} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { L("drop table if exists Book"); L("drop table if exists Category"); onCreate(db); }} 可以看到,我们在
onUpgrade() ⽅法中执⾏了两条DROP语句; 如果发现数据库中已经存在 Book表 或 Category表 了,就将这两张表删除掉,然后再调⽤
onCreate() ⽅法重新创建; 这⾥先将已经存在的表删除掉,因为如果在创建表时发现这张表已经存在了,就会直接报错。
接下来的问题就是如何让
onUpgrade() ⽅法能够执⾏了,还记得SQLiteOpenHelper的构造⽅法⾥接收的第四个参数吗? 它表⽰当前数据库的版本号,之前我们传⼊的是 1,现在只要传⼊⼀个与 1 不同的整数,就可以让
onUpgrade() ⽅法得到执⾏了。 修改 中的代码;blic class MainActivity extends AppCompatActivity implements kListener{ ... @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main); helper = new MyDatabaseHelper(this,"",null,2); ... } @Override public void onClick(View v) {...}} 这⾥将数据库版本号指定为2,表⽰我们对数据库进⾏升级了。 现在重新运⾏程序,并点击Create按钮,这时就会再次弹出创建成功的提⽰; 为了验证⼀下 Category表 是不是已经创建成功了,我们在 SQLite Expert 中打开 数据库; (注意,每次在更新 后,都需要重新导出⼀遍) 由此可以看出,Category表 已经创建成功了,同时也说明我们的升级功能的确起到了作⽤。•CRUD 我们可以对数据进⾏的操作有 4 种,即 CRUD:C 代表添加(Create)R 代表查询(Retrieve)U 代表更新(Update)D 代表删除(Delete) 每⼀种操作⼜各⾃对应了⼀种 SQL 命令,如果你⽐较熟悉SQL语⾔的话,⼀定会知道:添加数据时使⽤ insert查询数据时使⽤ select更新数据时使⽤ update删除数据时使⽤ delete 但是开发者的⽔平总会是参差不齐的,未必每⼀个⼈都能⾮常熟悉地使⽤SQL语⾔; 因此Android也提供了⼀系列的辅助性⽅法,使得在 Android 中即使不去编写 SQL 语句,也能轻松完成所有的 CRUD 操作。 前⾯我们已经知道,调⽤ SQLiteOpenHelper 的
getReadableDatabase() 或
getWritableDatabase() ⽅法是可以⽤于创建和升级数据库的; 不仅如此,这两个⽅法还都会返回⼀个 SQLiteDatabase 对象,借助这个对象就可以对数据进⾏ CRUD 操作了。添加数据 SQLiteDatabase 中提供了⼀个
insert() ⽅法,这个⽅法就是专门⽤于添加数据的,它接收3个参数:第⼀个参数是表名,我们希望向哪张表⾥添加数据,这⾥就传⼊该表的名字第⼆个参数⽤于在未指定添加数据的情况下给某些可为空的列⾃动赋值NULL,⼀般我们⽤不到这个功能,直接传⼊null即可第三个参数是⼀个 ContentValues 对象,它提供了⼀系列的
put() ⽅法重载,⽤于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加数据传⼊即可 介绍完了基本⽤法,接下来还是让我们通过例⼦的⽅式来亲⾝体验⼀下如何添加数据吧; 修改 activity_ 中的代码,如下所⽰;activity_
insert() ⽅法将数据添加到表当中; 注意这⾥我们实际上添加了两条数据,上述代码中使⽤ Contentvalues 分别组装了两次不同的内容,并调⽤了两次
insert() ⽅法。运⾏结果 通过 SQLite Expert 打开 数据库 来查看⼀下(先导出); 由此可以看出,我们刚刚组装的两条数据都已经准确⽆误地添加到Book表中了。更新数据 学习完了如何向表中添加数据,接下来我们看看怎样才能修改表中已有的数据。 SQLiteDatabase 中也提供了⼀个⾮常好⽤的
update() ⽅法,⽤于对数据进⾏更新,这个⽅法接收四个参数:第⼀个参数和
insert() ⽅法⼀样,也是表名,在这⾥指定去更新哪张表⾥的数据第⼆个参数是 ContentValues 对象,把要更新的数据在这⾥组装进去第三、第四个参数⽤于约束更新某⼀⾏或某⼏⾏中的数据,不指定的话默认就是更新所有⾏ 那么接下来我们仍然是在 TestDatabase 项⽬的基础上修改,看⼀下更新数据的具体⽤法。 ⽐如说刚才添加到数据库⾥的第⼀本书,由于过了畅销季,卖得不是很⽕了,现在需要通过降低价格的⽅式来吸引更多的顾客,我们应该怎么操作呢? ⾸先修改 activity_ 中的代码;activity_
update() ⽅法去执⾏具体的更新操作,可以看到,这⾥使⽤了 第三、第四个参数 来指定具体更新哪⼏⾏; 第三个参数对应的是 SQL 语句的 where 部分,表⽰更新所有 name 等于 ? 的⾏; ⽽ ? 是⼀个占位符,可以通过第四个参数提供的⼀个字符串数组为第三个参数中的每个占位符指定相应的内容。 因此上述代码想表达的意图是将名字是《第⼀⾏代码》的这本书的价格改成 42.5; 需要注意的是,相较于上⼀次的代码,这次我将
private SQLiteDatabase db; 和
private ContentValues values; 提取了出来; 因为在 case 中第⼆次设置 db 和 values 的时候报错,报错原因是存在 case 中包含这两个变量的设置;运⾏结果 导出后查询表中的数据情况; 可以看到,《第⼀⾏代码》这本书的价格已经被成功改为 42.5 了。删除数据 SQLiteDatabase 中提供了⼀个
delete() ⽅法,专门⽤于删除数据,这个⽅法接收三个参数:第⼀个参数仍然是表名第⼆、第三个参数是⽤于约束删除某⼀⾏或某⼏⾏的数据,不指定的话默认就是删除所有⾏activity_
query() ⽅法⽤于对数据进⾏查询。 这个⽅法的参数⾮常复杂,最短的⼀个⽅法重载也需要传⼊七个参数。 那我们就先来看⼀下这七个参数各⾃的含义:第⼀个参数不⽤说,当然还是表名,表⽰我们希望从哪张表中查询数据第⼆个参数⽤于指定去查询哪⼏列,如果不指定则默认查询所有列第三、第四个参数⽤于约束查询某⼀⾏或某⼏⾏的数据,不指定则默认查询所有⾏的数据第五个参数⽤于指定需要去 group by 的列,不指定则表⽰不对查询结果进⾏ group by 操作第六个参数⽤于对 group by 之后的数据进⾏进⼀步的过滤,不指定则表⽰不进⾏过滤第七个参数⽤于指定查询结果的排序⽅式,不指定则表⽰使⽤默认的排序⽅式 更多详细的内容可以参考下表; 调⽤
query() ⽅法后会返回⼀个 Cursor 对象,查询到的所有数据都将从这个对象中取出。activity_
blic class MainActivity extends AppCompatActivity implements kListener{ private static final String TAG = "MainActivity"; ...
private Button mBtnQuery; @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main); ... mBtnQuery = findViewById(); lickListener(this); } @Override public void onClick(View v) { switch(()){ case : ... break; case : ... break; case : ... break; case : ... break;
case : db = tableDatabase(); //查询 Book 表中所有的数据 Cursor cursor = ("Book",null,null,null,null,null,null); if(First()){ do{ //遍历 cursor 对象,取出数据并打印 String name = ing(umnIndex("name")); double price = ble(umnIndex("price")); Log.d(TAG, "************"); Log.d(TAG, "book name is "+name); Log.d(TAG, "book price is "+price); }while(Next()); (); } break; } }} 可以看到,我们⾸先在查询按钮的点击事件⾥⾯调⽤了 SQLiteDatabase 的
query() ⽅法去查询数据; 这⾥的
query() ⽅法⾮常简单,只是使⽤了第⼀个参数指明去查询 Book表,后⾯的参数全部为 null,这就表⽰希望查询这张表中的所有数据,虽然这张表中⽬前只剩下⼀条数据了; 查询完之后就得到了⼀个 Cursor对象; 接着我们调⽤它的
moveToFirst() ⽅法将数据的指针移动到第⼀⾏的位置,然后进⼊了⼀个循环当中,去遍历查询到的每⼀⾏数据; 在这个循环中可以通过 Cursor 的
getColumnIndex() ⽅法获取到某⼀列在表中对应的位置索引,然后将这个索引传⼊到相应的取值⽅法中,就可以得到从数据库中读取到的数据了; 接着我们使⽤Log的⽅式将驭出的数据打印出来,借此来检查⼀下读取⼯作有没有成功完成。 最后别忘了调⽤
close() ⽅法来关闭 cursor。运⾏结果 可以看到,这⾥已经将 Book表 中唯⼀的⼀条数据成功地读取出来了。•GitHub 【】
2023年6月21日发(作者:)
Android学习之SQLite数据库存储•引⾔概念 SQLite数据库,和其他的SQL数据库不同, 我们并不需要在⼿机上另外安装⼀个数据库软件,Android系统已经集成了这个数据库;特点SQLite是⼀个轻量级的关系型数据库,运算速度快,占⽤资源少,很适合在移动设备上使⽤不仅⽀持标准SQL语法,还遵循ACID(数据库事务)原则,⽆需账号,使⽤起来⾮常⽅便SQLite⽀持五种数据类型NULLinteger(整型)real(浮点型)text(⽂本类型)blob(⼆进制类型)SQLite 通过⽂件来保存数据库
⼀个⽂件就是⼀个数据库数据库中⼜包含多个表格表格⾥⼜有多条记录每条记录由多个字段构成每个字段都有对应的值•创建数据库 Android为了让我们能够更加⽅便地管理数据库,专门提供了⼀个 SQLiteOpenHelper 帮助类; 借助这个类就可以⾮常简单地对数据库进⾏创建和升级。
SQLiteOpenHelper 是⼀个抽象类,这意味着如果我们想要使⽤它的话,就需要创建⼀个⾃⼰的帮助类去继承它; SQLiteOpenHelper 中有两个抽象⽅法,分别是
oncreate() 和
onUpgrade() ;
onCreate(database) : 数据库第⼀次被创建时被调⽤
onUpgrade(database,oldVersion,newVersion) : 在数据库的版本发⽣变化时会被调⽤⼀般在软件升级时才需改变版本号,⽽数据库的版本是由程序员控制的假设数据库现在的版本是 1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新⽤户⼿机⾥的数据库表结构为了实现这⼀⽬的,可以把原来的数据库版本设置为 2,或者其他与旧版本号不同的数字即可 我们必须在⾃⼰的帮助类⾥⾯重写这两个⽅法,然后分别在这两个⽅法中去实现 创建、升级数据库 的逻辑。
SQLiteOpenHelper 中还有两个⾮常重要的实例⽅法:
getReadableDatabase() 和
getWritableDatabase() 。 这两个⽅法都可以 创建或打开 ⼀个现有的数据库(如果数据库已存在则直接打开,否则创建⼀个新的数据库), 并返回⼀个可对数据库进⾏读写操作的对象。 不同的是,当数据库不可写⼊的时候(如磁盘空间已满):
getReadableDatabase() ⽅法返回的对象将以只读的⽅式去打开数据库
getWritableDatabase() ⽅法则将出现异常 SQLiteOpenHelper 中有三个构造⽅法可供重写,⼀般使⽤参数少⼀点的那个:
SQLiteOpenHelper(Context context, String name, Factory factory, int version)
该构造⽅法中接收四个参数:
Context context :这个没什么好说的,必须有这个才能对数据库进⾏操作
String name :第⼆个参数是数据库名,创建数据库时使⽤的就是这⾥指定的名称
Factory factory :第三个参数允许我们在查询数据的时候返回⼀个⾃定义的 Cursor,⼀般都是传⼊null
int version :第四个参数表⽰当前数据库的版本号,可⽤于对数据库进⾏升级操作 构建出 SQLiteOpenHelper 的实例之后,再调⽤它的
getReadableDatabase() 或
getWritableDatabase() ⽅法就能够创建数据库了; 数据库⽂件会存放在
/data/data/
onCreate() ⽅法也会得到执⾏,所以通常会在这⾥去处理⼀些创建表的逻辑。•通过代码深⼊理解准备⼯作 ⾸先新建⼀个 TestDatabase 项⽬。 在该项⽬中新建 MyDatabaseHelper 类,继承⾃ SQLiteOpenHelper;blic class MyDatabaseHelper extends SQLiteOpenHelper { public static final String CREATE_BOOK = "create table Book (" + "id integer primary key autoincrement," + "name text," + "price real)"; private Context mContext; public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable Factory factory, int version) { super(context, name, factory, version); mContext = context; } @Override public void onCreate(SQLiteDatabase db) { L(CREATE_BOOK); xt(mContext,"Create Succeeded!",_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }} 可以看到,我们把建表语句定义成了⼀个字符串常量,然后在
onCreate() 中调⽤了
L(CREATE_BOOK); 去执⾏这条建表语句; 之后,弹出⼀个 Toast 提⽰建表成功,这样就可以保证在数据库创建的同时创建 Book 表; 在 SQL 中,Book 表的建表语句如下:CREATE TABLE Book( id INTEGER PRIMARY KEY autoincrement, NAME TEXT, price REAL); 其中,设置 id 为 primary key,并⽤ autoincrement 关键字表⽰ id 列是⾃增长的。 接下来,修改 activity_ 中的代码;activity_
onCreate() ⽅法中构建了⼀个 MyDatabaseHelper 对象,并且通过构造函数的参数将数据库名指定为 ,版本号指定为1; 然后在 Create按钮 的点击事件⾥调⽤了
getWritableDatabase() ⽅法; 这样当第⼀次点击 Create按钮 时,就会检测到当前程序中并没有 这个数据库, 于是会创建该数据库并调⽤ MyDatabaseHelper 中的
onCreate() ⽅法,这样 Book 表也就得到了创建,然后会弹出⼀个 Toast 提⽰创建成功。 再次点击 Create按钮 时,会发现此时已经存在 数据库了,因此不会再创建⼀次。运⾏效果 此时 数据库 和 Book表 应该都已经创建成功了,因为当你再次点击 Create按钮 时,不会再有 Toast 弹出; 可是怎样才能证实它们的确创建成功了? 打开 Android Device Monitor(不知道什么是 ADM 的⼩伙伴可以参考我的这篇博客), 找到
/data/data/tabase/databases/ ⽬录: 你会发现该⽬录下多了⼀个 ⽂件,但是看不到 Book 表,这可如何是好? 下⾯介绍⼀下通过使⽤ adb shell ⽅式来对数据库和表的创建情况进⾏检查。通过 adb 调试 adb 是 Android SDK 中⾃带的⼀个调试⼯具,使⽤这个⼯具可以直接对连接在电脑上的⼿机或模拟器进⾏调试操作; 它存放在 Android SDK 的 platform-tools ⽬录下,如果想要在命令⾏中使⽤这个⼯具,就需要先把它的路径配置到环境变量中; 如果不知道你的 Android SDK 安装在哪的⼩伙伴,可以通过以下⽅式找到: 点击【Tools】->【SDK Manager】; 找到 Android SDK 的安装路径; 在【电脑】中打开该路径,并找到【platform-tools】⽂件夹; 复制该路径,打开【环境变量】,在【系统变量】⾥找到【Path】并点击编辑,将 platform-tools ⽬录配置进去即可; 配置好了环境变量后,就可以使⽤ adb ⼯具了; 通过【Win+R】打开命令⾏界⾯,输⼊ adb shell,就会进⼊到设备的控制台; 其中,# 符号是超级管理员的意思,也就是说,现在你可以访问模拟器中的⼀切数据; 如果你的命令⾏上显⽰的是 $,那么就表⽰你现在是普遍管理员,需输⼊ su 命令切换成超级管理员,这样才能执⾏以下操作; 接下来使⽤ cd 命令进⼊到
/data/data/tabase/databases/ ⽬录下; (偷偷告诉你,⿏标右击可以实现粘贴功能) 使⽤ ls 命令查看该⽬录⾥的⽂件; 这个⽬录下出现了两个数据库⽂件,⼀个正是我们创建的 ; ⽽另⼀个 -journal 则是为了让数据库能够⽀持事务⽽产⽣的临时⽇志⽂件,通常情况下这个⽂件的⼤⼩都是 0 字节; 接下来我们就要借助 sqlite 命令来打开数据库了,只需要键⼊【sqlite3 数据库名】即可; 这时就已经打开了 数据库,现在就可以对这个数据库中的表进⾏管理了; ⾸先来看⼀下⽬前数据库中有哪些表,键⼊ .table 命令; 可以看到,此时数据库中有两张表:android_metadata表 是每个数据库中都会⾃动⽣成的,不⽤管它⽽另外⼀张 Book表 就是我们在 MyDatabaseHelper 中创建的了 这⾥还可以通过 .schema 命令来查看它们的建表语句; 由此证明,数据库 和 Book表 确实已经创建成功了; 之后键⼈ .exit 或 .quit 命令可以退出数据库的编辑,再键⼊ exit 命令就可以退出设备控制台了。通过 SQLite Expert 调试 当然,除了使⽤ adb ⼯具外,还可以通过使⽤ SQLite 可视化管理⼯具来查看; SQLite Expert 是⼀款功能强⼤的 SQLite 可视化管理⼯具,SQLite Expert 允许⽤户在 SQLite 服务器上执⾏创建、编辑、复制、提取等操作。 可以帮我们查看 SQLite 数据库以及⽣成 SQLite 数据库; 【】,我下载的是这个版本【】; 通过 Android Device Monitor 找到 ⽂件,导出到本地(选中 后选择右上⾓的导出按钮保存到本地); 并通过 SQLite Expert 打开该⽂件; 相⽐于使⽤ adb 调试,真的是简单粗暴,接下来就通过 SQLite Expert 调试了;升级数据库 如果你⾜够细⼼,⼀定会发现 MyDatabaseHelper中还有⼀个空⽅法呢; 没错,
onUpgrade() ⽅法是⽤于对数据库进⾏升级的,它在整个数据库的管理⼯作当中起着⾮常重要的作⽤,可千万不能忽视。
⽬前 DatabaseTest项⽬ 中已经有⼀张 Book表 ⽤于存放书的各种详细数据; 如果我们想再添加⼀张Category表⽤于记录图书的分类,该怎么做呢? ⽐如 Category表中有 id(主键)、分类名和分类代码 这⼏个列,那么建表语句就可以写成:CREATE TABLE Category( id INTEGER PRIMARY KEY , category_name TEXT, category_code INTEGER); 接下来将这条建表语句添加到 MyDatabaseHelper 中,修改 中的代码;blic class MyDatabaseHelper extends SQLiteOpenHelper { private Context mContext; public MyDatabaseHelper(...) {...} @Override public void onCreate(SQLiteDatabase db) { L(CREATE_BOOK);
L("CREATE TABLE Category(" + "id INTEGER PRIMARY KEY ," + "category_name TEXT," + "category_code INTEGER)"); xt(mContext,"Create Succeeded!",_SHORT).show(); } @Override public void onUpgrade(...) {...}} 看上去好像都挺对的吧? 现在我们重新运⾏⼀下程序,并点击 Create按钮,你会发现,没有弹出创建成功的提⽰。 当然,你也可以通过 SQLite Expert⼯具 到数据库中再去检查⼀下,这样你会更加地确认 Category表 没有创建成功。
其实没有创建成功的原因不难思考,因为此时 数据库 已经存在了, 之后不管我们怎样点击 Create按钮,MyDatabaseHelper 中的
onCreate() ⽅法都不会再次执⾏,因此新添加的表也就⽆法得到创建了。
解决这个问题的办法也相当简单,只需要先将程序卸载掉,然后重新运⾏,这时 数据库 已经不存在了; 如果再点击 Create按钮,MyDatabaseHelper 中的
onCreate() ⽅法就会执⾏,这时 Category表 就可以创建成功了。 不过,通过卸载程序的⽅式来新增⼀张表毫⽆疑问是很极端的做法; 其实我们只需要巧妙地运⽤ SQLiteOpenHelper 的升级功能就可以很轻松地解决这个问题; 修改 中的代码;blic class MyDatabaseHelper extends SQLiteOpenHelper { ... public MyDatabaseHelper(...) {...} @Override public void onCreate(SQLiteDatabase db) {...} @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { L("drop table if exists Book"); L("drop table if exists Category"); onCreate(db); }} 可以看到,我们在
onUpgrade() ⽅法中执⾏了两条DROP语句; 如果发现数据库中已经存在 Book表 或 Category表 了,就将这两张表删除掉,然后再调⽤
onCreate() ⽅法重新创建; 这⾥先将已经存在的表删除掉,因为如果在创建表时发现这张表已经存在了,就会直接报错。
接下来的问题就是如何让
onUpgrade() ⽅法能够执⾏了,还记得SQLiteOpenHelper的构造⽅法⾥接收的第四个参数吗? 它表⽰当前数据库的版本号,之前我们传⼊的是 1,现在只要传⼊⼀个与 1 不同的整数,就可以让
onUpgrade() ⽅法得到执⾏了。 修改 中的代码;blic class MainActivity extends AppCompatActivity implements kListener{ ... @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main); helper = new MyDatabaseHelper(this,"",null,2); ... } @Override public void onClick(View v) {...}} 这⾥将数据库版本号指定为2,表⽰我们对数据库进⾏升级了。 现在重新运⾏程序,并点击Create按钮,这时就会再次弹出创建成功的提⽰; 为了验证⼀下 Category表 是不是已经创建成功了,我们在 SQLite Expert 中打开 数据库; (注意,每次在更新 后,都需要重新导出⼀遍) 由此可以看出,Category表 已经创建成功了,同时也说明我们的升级功能的确起到了作⽤。•CRUD 我们可以对数据进⾏的操作有 4 种,即 CRUD:C 代表添加(Create)R 代表查询(Retrieve)U 代表更新(Update)D 代表删除(Delete) 每⼀种操作⼜各⾃对应了⼀种 SQL 命令,如果你⽐较熟悉SQL语⾔的话,⼀定会知道:添加数据时使⽤ insert查询数据时使⽤ select更新数据时使⽤ update删除数据时使⽤ delete 但是开发者的⽔平总会是参差不齐的,未必每⼀个⼈都能⾮常熟悉地使⽤SQL语⾔; 因此Android也提供了⼀系列的辅助性⽅法,使得在 Android 中即使不去编写 SQL 语句,也能轻松完成所有的 CRUD 操作。 前⾯我们已经知道,调⽤ SQLiteOpenHelper 的
getReadableDatabase() 或
getWritableDatabase() ⽅法是可以⽤于创建和升级数据库的; 不仅如此,这两个⽅法还都会返回⼀个 SQLiteDatabase 对象,借助这个对象就可以对数据进⾏ CRUD 操作了。添加数据 SQLiteDatabase 中提供了⼀个
insert() ⽅法,这个⽅法就是专门⽤于添加数据的,它接收3个参数:第⼀个参数是表名,我们希望向哪张表⾥添加数据,这⾥就传⼊该表的名字第⼆个参数⽤于在未指定添加数据的情况下给某些可为空的列⾃动赋值NULL,⼀般我们⽤不到这个功能,直接传⼊null即可第三个参数是⼀个 ContentValues 对象,它提供了⼀系列的
put() ⽅法重载,⽤于向 ContentValues 中添加数据,只需要将表中的每个列名以及相应的待添加数据传⼊即可 介绍完了基本⽤法,接下来还是让我们通过例⼦的⽅式来亲⾝体验⼀下如何添加数据吧; 修改 activity_ 中的代码,如下所⽰;activity_
insert() ⽅法将数据添加到表当中; 注意这⾥我们实际上添加了两条数据,上述代码中使⽤ Contentvalues 分别组装了两次不同的内容,并调⽤了两次
insert() ⽅法。运⾏结果 通过 SQLite Expert 打开 数据库 来查看⼀下(先导出); 由此可以看出,我们刚刚组装的两条数据都已经准确⽆误地添加到Book表中了。更新数据 学习完了如何向表中添加数据,接下来我们看看怎样才能修改表中已有的数据。 SQLiteDatabase 中也提供了⼀个⾮常好⽤的
update() ⽅法,⽤于对数据进⾏更新,这个⽅法接收四个参数:第⼀个参数和
insert() ⽅法⼀样,也是表名,在这⾥指定去更新哪张表⾥的数据第⼆个参数是 ContentValues 对象,把要更新的数据在这⾥组装进去第三、第四个参数⽤于约束更新某⼀⾏或某⼏⾏中的数据,不指定的话默认就是更新所有⾏ 那么接下来我们仍然是在 TestDatabase 项⽬的基础上修改,看⼀下更新数据的具体⽤法。 ⽐如说刚才添加到数据库⾥的第⼀本书,由于过了畅销季,卖得不是很⽕了,现在需要通过降低价格的⽅式来吸引更多的顾客,我们应该怎么操作呢? ⾸先修改 activity_ 中的代码;activity_
update() ⽅法去执⾏具体的更新操作,可以看到,这⾥使⽤了 第三、第四个参数 来指定具体更新哪⼏⾏; 第三个参数对应的是 SQL 语句的 where 部分,表⽰更新所有 name 等于 ? 的⾏; ⽽ ? 是⼀个占位符,可以通过第四个参数提供的⼀个字符串数组为第三个参数中的每个占位符指定相应的内容。 因此上述代码想表达的意图是将名字是《第⼀⾏代码》的这本书的价格改成 42.5; 需要注意的是,相较于上⼀次的代码,这次我将
private SQLiteDatabase db; 和
private ContentValues values; 提取了出来; 因为在 case 中第⼆次设置 db 和 values 的时候报错,报错原因是存在 case 中包含这两个变量的设置;运⾏结果 导出后查询表中的数据情况; 可以看到,《第⼀⾏代码》这本书的价格已经被成功改为 42.5 了。删除数据 SQLiteDatabase 中提供了⼀个
delete() ⽅法,专门⽤于删除数据,这个⽅法接收三个参数:第⼀个参数仍然是表名第⼆、第三个参数是⽤于约束删除某⼀⾏或某⼏⾏的数据,不指定的话默认就是删除所有⾏activity_
query() ⽅法⽤于对数据进⾏查询。 这个⽅法的参数⾮常复杂,最短的⼀个⽅法重载也需要传⼊七个参数。 那我们就先来看⼀下这七个参数各⾃的含义:第⼀个参数不⽤说,当然还是表名,表⽰我们希望从哪张表中查询数据第⼆个参数⽤于指定去查询哪⼏列,如果不指定则默认查询所有列第三、第四个参数⽤于约束查询某⼀⾏或某⼏⾏的数据,不指定则默认查询所有⾏的数据第五个参数⽤于指定需要去 group by 的列,不指定则表⽰不对查询结果进⾏ group by 操作第六个参数⽤于对 group by 之后的数据进⾏进⼀步的过滤,不指定则表⽰不进⾏过滤第七个参数⽤于指定查询结果的排序⽅式,不指定则表⽰使⽤默认的排序⽅式 更多详细的内容可以参考下表; 调⽤
query() ⽅法后会返回⼀个 Cursor 对象,查询到的所有数据都将从这个对象中取出。activity_
blic class MainActivity extends AppCompatActivity implements kListener{ private static final String TAG = "MainActivity"; ...
private Button mBtnQuery; @Override protected void onCreate(Bundle savedInstanceState) { te(savedInstanceState); setContentView(ty_main); ... mBtnQuery = findViewById(); lickListener(this); } @Override public void onClick(View v) { switch(()){ case : ... break; case : ... break; case : ... break; case : ... break;
case : db = tableDatabase(); //查询 Book 表中所有的数据 Cursor cursor = ("Book",null,null,null,null,null,null); if(First()){ do{ //遍历 cursor 对象,取出数据并打印 String name = ing(umnIndex("name")); double price = ble(umnIndex("price")); Log.d(TAG, "************"); Log.d(TAG, "book name is "+name); Log.d(TAG, "book price is "+price); }while(Next()); (); } break; } }} 可以看到,我们⾸先在查询按钮的点击事件⾥⾯调⽤了 SQLiteDatabase 的
query() ⽅法去查询数据; 这⾥的
query() ⽅法⾮常简单,只是使⽤了第⼀个参数指明去查询 Book表,后⾯的参数全部为 null,这就表⽰希望查询这张表中的所有数据,虽然这张表中⽬前只剩下⼀条数据了; 查询完之后就得到了⼀个 Cursor对象; 接着我们调⽤它的
moveToFirst() ⽅法将数据的指针移动到第⼀⾏的位置,然后进⼊了⼀个循环当中,去遍历查询到的每⼀⾏数据; 在这个循环中可以通过 Cursor 的
getColumnIndex() ⽅法获取到某⼀列在表中对应的位置索引,然后将这个索引传⼊到相应的取值⽅法中,就可以得到从数据库中读取到的数据了; 接着我们使⽤Log的⽅式将驭出的数据打印出来,借此来检查⼀下读取⼯作有没有成功完成。 最后别忘了调⽤
close() ⽅法来关闭 cursor。运⾏结果 可以看到,这⾥已经将 Book表 中唯⼀的⼀条数据成功地读取出来了。•GitHub 【】
发布评论