Android SQLite 数据库常用命令

转载请注明出处:https://blog.csdn.net/turtlejj/article/details/105015349,谢谢~

       最近在工作中,看到有一部分同事,在查看Android应用程序的数据库文件时,都要先通过adb pull命令,把db文件从手机拷贝到电脑端,再通过一些软件打开查看。这种方式虽然没有什么问题,但在执行某些操作后,数据库发生变化,如果想再次查看,又要再执行一次adb pull操作,很麻烦。

       其实,我们完全可以通过adb shell,使用sqlite3这个命令行工具,来查看我们db文件中的表、表结构以及表中存储的数据。

       本篇文章,既是我给自己写的一份备忘,也希望能为不熟悉sqlite3工具的同学提供一份命令速查手册,方便大家在使用的时候,不用再去各个地方查找资料。

       当然,由于篇幅原因,我们这里并不会列出sqlite3的所有命令,但对于Android应用的开发和调试来说,完全可以满足。

 

一、Android应用程序的database目录

       Android应用程序,如果需要使用数据库来对数据进行持久化,一定会在应用的目录下生成一个database文件夹,用以存放db文件,如下所示。

       其中,.db文件,为应用程序进行数据持久化的数据库文件;而.db-journal文件,则是系统自动生成的日志文件,用于数据库在进行事务时的回滚操作,一般情况下,该文件的大小为0。

pixel:/data/data/com.example.demo/databases # ls -al
total 60
drwxrwx--x 2 u0_a215 u0_a215  4096 2020-03-14 10:25 .
drwx------ 6 u0_a215 u0_a215  4096 2020-03-14 10:25 ..
-rw-rw---- 1 u0_a215 u0_a215 49152 2020-03-14 10:40 demo.db
-rw-rw---- 1 u0_a215 u0_a215     0 2020-03-14 10:40 demo.db-journal

 

二、使用sqlite3打开db文件

       使用sqlite3打开db文件时,可以指定打开的方式为“可写模式”或“只读模式”。(某些旧版本的sqlite3可能没有readonly选项)

# 可写模式打开db文件
pixel:/data/data/com.example.demo/databases # sqlite3 demo.db 
SQLite version 3.28.0 2019-04-16 19:49:53
Enter ".help" for usage hints.
sqlite> 

# 只读模式打开db文件
pixel:/data/data/com.example.demo/databases # sqlite3 -readonly demo.db 
SQLite version 3.28.0 2019-04-16 19:49:53
Enter ".help" for usage hints.
sqlite> 

 

三、退出sqlite3模式

       退出sqlite3有三种方式,我们这里比较推荐前两种

# 使用".exit"
sqlite>.exit
pixel:/data/data/com.example.demo/databases # 


# 使用".quit"命令
sqlite>.quit
pixel:/data/data/com.example.demo/databases # 


// 连续按三次"Ctrl + C"
sqlite> ^C^C^C
pixel:/data/data/com.example.demo/databases # 

 

四、sqlite3的几种显示模式

       sqlite3在显示数据时,有10种模式,如下所示。

sqlite> .mode mode_name
mode_name list:
  ascii    Columns/rows delimited by 0x1F and 0x1E   # 以ASCII码显示,可能会是乱码
  csv      Comma-separated values                    # 以"逗号"分隔
  column   Left-aligned columns.  (See .width)       # 以左对齐方式显示
  html     HTML <table> code                         # 以html格式显示
  insert   SQL insert statements for TABLE           # 以SQL语句形式展示数据是如何插入的
  line     One value per line                        # 单行显示,并显示每个值的变量名
  list     Values delimited by "|"                   # 以"|"分隔,这是sqlite3的默认模式
  quote    Escape answers as for SQL                 # 类似"insert"模式,但该模式只包含数据插入的内容,但不包含SQL语法
  tabs     Tab-separated values                      # 以"tab"分隔
  tcl      TCL list elements                         # 将每个值以"双引号"引用,并用空格分隔

       我相信,大部分同学在看了上面的解释以后,都不可能完全体会到这10种模式到底会显示成什么样子。我们下面通过实际的例子来给大家展示一下。

# ascii模式
sqlite> .mode ascii
sqlite> select * from news;
10这是第二条新闻的内容1584793640734第二条新闻

# csv模式
sqlite> .mode csv
sqlite> select * from news;
1,0,"这是第二条新闻的内容",1584793640734,"第二条新闻"

# column模式
sqlite> .mode column
sqlite> select * from news;
1           0             这是第二条新闻的内容                      1584793640734  第二条新闻          

# html模式
sqlite> .mode html
sqlite> select * from news;
<TR><TD>1</TD>
<TD>0</TD>
<TD>这是第二条新闻的内容</TD>
<TD>1584793640734</TD>
<TD>第二条新闻</TD>
</TR>

# insert模式
sqlite> .mode insert
sqlite> select * from news;
INSERT INTO "table" VALUES(1,0,'这是第二条新闻的内容',1584793640734,'第二条新闻');

# line模式
sqlite> .mode line 
sqlite> select * from news;
          id = 1
commentcount = 0
     content = 这是第二条新闻的内容
 publishdate = 1584793640734
       title = 第二条新闻

# list模式
sqlite> .mode list
sqlite> select * from news;
1|0|这是第二条新闻的内容|1584793640734|第二条新闻

# quote模式
sqlite> .mode quote
sqlite> select * from news;
1,0,'这是第二条新闻的内容',1584793640734,'第二条新闻'

# tabs模式
sqlite> .mode tabs
sqlite> select * from news;
1	0	这是第二条新闻的内容	1584793640734	第二条新闻

# tcl模式
sqlite> .mode tcl
sqlite> select * from news;
"1" "0" "\350\277\231\346\230\257\347\254\254\344\272\214\346\235\241\346\226\260\351\227\273\347\232\204\345\206\205\345\256\271" "1584793640734" "\347\254\254\344\272\214\346\235\241\346\226\260\351\227\273"

       通过上面的演示,我们可以很清楚的看到,同样的数据,分别以这10种模式展示出来的样子。其中我们比较常用的模式是list和line。其中list模式,是sqlite3所使用的默认模式,使用"|"对数据进行分隔,每行即为表中的一组数据,十分简洁;但其弊端是,无法得知,被"|"分隔的每个数据,代表表中的哪一列,不够清晰。而line模式,每行只展示一个数据,且会指出该数据在表中的列名,十分清晰;但同样带来的弊端是,如果表的列很多,则打印表中的一行数据,需要占用大量的篇幅,不够简洁。

 

五、使用“.table”命令查看db文件中的所有表

sqlite> .table
android_metadata  news
comment

       可以看到,db中共有三张表,其中“news”和“comment”两个表是我们在代码中创建出来的表。而剩下的“android_metadata”,是系统自动创建的。有关这张表的内容,我们会在后面讲到。

 

六、对表做CURD操作

       对表做CURD操作与我们在数据库软件中使用SQL语句完全一样,这里我们只举几个简单的例子,不熟悉SQL语句的同学,可以自行百度,该部分内容不在我们本篇文章的讲解范围之内。

       注意,如果打开db文件时,使用了-readonly参数,则只能对表进行查询操作,不能执行insert、delete和update操作。

# 查询"news"表,得到一条数据
sqlite> select * from news;
          id = 1
commentcount = 2
     content = 这是第一条新闻的内容
 publishdate = 1584793640734
       title = 第一条新闻


# 查询"news"表中的数据个数
sqlite> select count(*) from news;
count(*) = 1


# 向"news"表中插入一条数据
sqlite> insert into "news" values(2,0,'这是第二条新闻的内容',1584793642000,'第二条新闻');


# 查询"news"表,得到两条数据
sqlite> select * from news;
          id = 1
commentcount = 2
     content = 这是第一条新闻的内容
 publishdate = 1584793640734
       title = 第一条新闻

          id = 2
commentcount = 0
     content = 这是第二条新闻的内容
 publishdate = 1584793642000
       title = 第二条新闻


# 从"news"中删除"id"为1的数据
sqlite> delete from 'news' where id=1;


# 查询"news"表,只剩下"id"为2的数据
sqlite> select * from news;
          id = 2
commentcount = 0
     content = 这是第三条新闻的内容
 publishdate = 1584793642000
       title = 第二条新闻


# 更新"news"中"id"为2的数据,将commentcount列的值改为99
sqlite> update 'news' set commentcount=99 where id=2;


# 查询"news"表,"id"为2的数据的commentcount列的值变为99
sqlite> select * from news;
          id = 2
commentcount = 99
     content = 这是第二条新闻的内容
 publishdate = 1584793642000
       title = 第二条新闻

       至此,使用sqlite3对db进行基本操作的讲解,就告一段落了。但本文还没有结束,如果你觉得以上的操作已经完全能够满足你的需求,那就可以到此为止了。当然,如果你希望了解更多,欢迎继续往下阅读。

 

七、查看表的结构及建表语句

       1. 使用“pragma table_info(table_name)”命令查看表结构

       通过“pragma table_info(table_name) ”命令,我们可以很清晰的看到表的接口,和其中每列的各种属性。

sqlite> pragma table_info(news);
       cid = 0           # 列ID
      name = id          # 列名
      type = integer     # 数据类型
   notnull = 0           # 是否可以为空
dflt_value =             # 默认值
        pk = 1           # 是否为主键

       cid = 1
      name = commentcount
      type = integer
   notnull = 0
dflt_value = 
        pk = 0

       cid = 2
      name = content
      type = text
   notnull = 0
dflt_value = 
        pk = 0

       cid = 3
      name = publishdate
      type = integer
   notnull = 0
dflt_value = 
        pk = 0

       cid = 4
      name = title
      type = text
   notnull = 0
dflt_value = 
        pk = 0

       但有时候,想将表的结构,分享给其他人时,如果拷贝这么一大堆内容,其他人在看起来的时候,也会很吃力,有没有什么办法,可以得到建表时所使用的语句呢?当然可以,我们继续往下看。

 

       2. 查看建表语句

       想要查询db的建表语句,有两种方式:

       方法一  使用“.schema”命令查看建表语句

sqlite> .schema
# "android_metadata"表的建表语句
CREATE TABLE android_metadata (locale TEXT);
# "news"表的建表语句
CREATE TABLE news (id integer primary key autoincrement,commentcount integer, content text, publishdate integer, title text);
# "comment"表的建表语句
CREATE TABLE comment (id integer primary key autoincrement,content text, publishdata integer, news_id integer);

       如果只想查看某一张表的建表语句,我们可以指定表名,以得到更简洁的结果

# 执行表名以得到某一张表的建表语句
sqlite> .schema news
CREATE TABLE news (id integer primary key autoincrement,commentcount integer, content text, publishdate integer, title text);


# 使用"--indent"参数,可以得到pretty-printing
sqlite> .schema --indent comment
CREATE TABLE comment(
  id integer primary key autoincrement,
  content text,
  publishdata integer,
  news_id integer
);


# 注意,不要加分号,否则不会打印出任何信息
sqlite> .schema news;
sqlite> 

 

       方法二  SQLite创建数据库时,会建立一张特殊的表“sqlite_master”,称为系统表(也有说法叫内置表),用以保存每张表的建表语句。我们可以通过查询该表的内容,来获得建表语句。

sqlite> select * from sqlite_master;
    type = table
    name = android_metadata
tbl_name = android_metadata
rootpage = 3
     sql = CREATE TABLE android_metadata (locale TEXT)

    type = table
    name = sqlite_sequence
tbl_name = sqlite_sequence
rootpage = 4
     sql = CREATE TABLE sqlite_sequence(name,seq)

    type = table
    name = news
tbl_name = news
rootpage = 5
     sql = CREATE TABLE news (id integer primary key autoincrement,commentcount integer, content text, publishdate integer, title text)

    type = index
    name = sqlite_autoindex_news_1
tbl_name = news
rootpage = 6

    type = table
    name = comment
tbl_name = comment
rootpage = 7
     sql = CREATE TABLE comment (id integer primary key autoincrement,content text, publishdata integer, news_id integer)

       其中,的字段含义如下所示:

type        # 记录了项目的类型,如table、index、view、trigger。
name        # 记录了项目的名称,如表名、索引名等。
tbl_name    # 记录所从属的表名,如索引所在的表名。对于表来说,该列就是表名本身。
rootpage    # 记录项目在数据库页中存储的编号。对于视图和触发器,该列值为0或者NULL。
sql         # 记录创建该项目的SQL语句。

       当然,我们也可以只查询某一张表的信息,可以得到更简洁的信息

sqlite> select * from sqlite_master where name='news';
    type = table
    name = news
tbl_name = news
rootpage = 6
     sql = CREATE TABLE news (id integer primary key autoincrement,commentcount integer, content text, publishdate integer, title text)

       相比于方法一,方法二中查询到的信息更全面。同时,也引出了几个系统默认创建的表,它们分别是“android_metadata”,“sqlite_sequence”和“sqlite_master”。

       其中“sqlite_master”表,我们在本节已经介绍过了,可以通过其查看每张表的建表语句,后面不再赘述。

       “android_metadata”在前面我们使用“.table”命令列出数据库中的表时,已经见到过了,但尚未对其进行分析讲解;而“sqlite_sequence”,我们至今还没有提到过,下面,我们就来对后两张表进行逐一分析。
       

. 系统创建的表

       1. “android_metadata”

       首先,我们来看一下这张表的建表语句和表中存储的内容。

# 建表语句
sqlite> .schema android_metadata
CREATE TABLE android_metadata (locale TEXT);


# 存储内容
sqlite> select * from android_metadata;
locale = zh_CN

       其实,这样一看,“android_metadata”表的作用就很清晰了,它是用来存储“默认语言环境”的,其中“zh_CN”就表示“简体中文,中华人民共和国”。当然,如果手机的默认语言环境如果是美式英语的话,那“locale”的值将会是“en-US”。

       关于“android_metadata”表和“Locale”的内容,如果大家有兴趣,可以自行阅读源码中的“SQLiteConnection.java”和“Locale.java”文件。

 

       2. “sqlite_sequence”

       老样子,还是先来看建表语句和表中存储的内容。

# 建表语句
sqlite> .schema sqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)


# 存储内容
sqlite> select * from sqlite_sequence;
 name = comment
  seq = 2

 name = news
  seq = 2

       “name”字段,没什么可以说的,就是表名。

       而“seq”是做什么用的呢?我们先来分别查询一下这两张表中的数据。

# 查询"news"表中的数据,只有一条记录
sqlite> select * from news;
          id = 2
commentcount = 99
     content = 这是第三条新闻的内容
 publishdate = 1584793642000
       title = 第三条新闻


# 查询"comment"表中的数据,有两条记录
sqlite> select * from comment;
         id = 1
    content = 好评!
publishdata = 1584793640700
    news_id = 2

         id = 2
    content = 赞一个!
publishdata = 1584793640719
    news_id = 2

       “comment”表中,有两条记录,与“sqlite_sequence”表中关于“comment”的“seq”的值吻合,但“news”表中只有一条,为什么“sqlite_sequence”表中关于“news”的“seq”值也是2呢?

       注意观察,我们发现,无论“news”表,还是“comment”表,其最大的id值,均为2。那是不是说,“sqlite_sequence”表中记录的“seq”值,有可能是每张表中id的最大值呢?我们不妨来做个实验。

# 像"new"表中插入一条id为8的数据
sqlite> INSERT INTO "news" VALUES(8,1002,'This is Only for Test',123123123,'Test');


# 查询"news"表中的数据
sqlite> select * from news;
          id = 2
commentcount = 99
     content = 这是第三条新闻的内容
 publishdate = 1584793642000
       title = 第三条新闻

          id = 8
commentcount = 1002
     content = This is Only for Test
 publishdate = 123123123
       title = Test


# 再次查询"sqlite_sequence"表中的数据
sqlite> select * from sqlite_sequence;
 name = comment
  seq = 2

 name = news
  seq = 8

       诶,“sqlite_sequence”中关于“news”表的“seq”值果然变为8了,说明我们之前的猜想是正确的。那么,为什么要记录这个值呢?我们不妨再来看看“news”表和“comment”表的建表语句。

# "news"表的建表语句
CREATE TABLE news (id integer primary key autoincrement,commentcount integer, content text, publishdate integer, title text);

# "comment"表的建表语句
CREATE TABLE comment (id integer primary key autoincrement,content text, publishdata integer, news_

       发现没有,两张表的id值,均为autoincrement类型。因此,数据库需要在每次插入数据时,记录每张表当前的id值,以便在下次向表中插入数据时,对该值进行+1操作。

 

       至此,所有要分析的内容都已经结束了,希望本文能对那些还不太熟悉sqlite3使用方法的同学带来一些帮助。时间仓促,文中难免会有疏漏,如有错误,欢迎大家予以指正。

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页