数据库的主题是
例如,如果您正在编写“笔记”应用,您应该理想上将用户的各条笔记存储在数据库中。当然,您也可以将每条笔记作为单独的文本文件进行存储,但是这样一来,您可能需要分别使用大量文件,而不是使用一个合并的数据库文件。一个更大的障碍是数据库世界中常见的分类和搜索等任务几乎不可能实现。
在本教程中,我们将逐步讲解创建数据库、将数据库保存到文件中、存储信息以及检索数据以在 Corona 应用中使用。
熟悉 JSON 的开发者知道它非常适合轻松存储类似类型的信息,因为 Corona 中解码后的 JSON 字符串将返回为 Lua 表。那么您为什么使用 JSON 而不使用数据库或
在决定使用哪个工具时的基本经验原则是,如果数据量很大,尤其是需要搜索或分类数据时,数据库每次都是最优选择。然而,对于较小的数据集(例如存储配置数据的表),JSON 因其简单性而胜出。
有关以 JSON 格式保存和加载数据的更多详细信息,请参阅 使用 JSON 保存/加载表 教程。
您可以通过两种方式创建 SQLite 数据库
由于您几乎肯定想要存储数据以便将来访问,因此本教程将仅讨论第二种方法。
此示例展示了如何打开已保存的数据库文件和/或创建尚未存在的数据库文件
-- Require the SQLite library local sqlite3 = require( "sqlite3" ) -- Create a file path for the database file "data.db" local path = system.pathForFile( "data.db", system.DocumentsDirectory ) -- Open the database for access local db = sqlite3.open( path )
请注意,创建数据库的建议位置是 system.DocumentsDirectory
,如下例所示。无法写入您的项目资源目录,而临时/缓存目录会定期被操作系统清除,因此使用文档目录将确保您能够读写数据库,并且该数据库驻留在安全、持久的位置。
使用 SQLite 数据库时你将听到的一些常用术语包括表(不是 Lua 表,而是 SQL 表)、列和行。从根本上讲,SQL 表可以看作是数据的“类别”。进而,每个表都可以有许多列,这些列可以看作是这个表的“属性”,例如,UserID
、FirstName
、LastName
等。最后,插入表中的各个“记录”称为行。
行——更具体地说它们的属性——是你最常要处理的实际数据,但在我们可以添加行之前,我们必须设置一个具有特定列的表
local tableSetup = [[CREATE TABLE IF NOT EXISTS test ( UserID INTEGER PRIMARY KEY autoincrement, FirstName, LastName );]] db:exec( tableSetup )
在上面的代码中,tableSetup
是一个字符串,代表一个SQL 查询——从根本上讲,一个告诉数据库该做什么的命令。在本例中,我们将创建一个名为 test
的表并添加三个列
UserID
FirstName
LastName
然后,我们只需对上述中创建的数据库对象 (db
) “执行”此查询。
表中的第一列通常是设置为
请注意,查询字符串是用双中括号包裹的[[
和 ]]
)
通过 INSERT
语句完成创建新行。首先,我们展示基本用法,然后我们将介绍一个更动态的示例。
local insertQuery = [[INSERT INTO test VALUES ( NULL, "John", "Smith" );]] db:exec( insertQuery )
此示例相当简单
在前面的代码中,我们创建了一个名为 test
的表,现在我们“插入到”该 test
表中。
对于行的值,我们在创建表时按列声明的相同顺序,将它们列在 VALUES
术语后的括号 (()
) 中。保持这种一致的顺序非常重要!
记住,由于 autoincrement
标志,UserID
将NULL
作为该列值(而不是一个实际数字)传递的原因。
现在,让我们发挥创造力,举一个更动态的示例。下面的代码将根据从 Lua 表中提取的值向 SQL 表 (test
) 中插入三行(这假设你已经创建了数据库和 test
表)。
local people = { { FirstName = "John", LastName = "Smith", }, { FirstName = "James", LastName = "Nelson", }, { FirstName = "Tricia", LastName = "Cole", }, } for i = 1,#people do local q = [[INSERT INTO test VALUES ( NULL, "]] .. people[i].FirstName .. [[","]] .. people[i].LastName .. [[" );]] db:exec( q ) end
你并不总需要创建新行——事实上,你经常需要更新已经存在的一行。在下面的示例中,我们假设前面的示例中的三行已插入到 test
表中。
local q = [[UPDATE test SET FirstName="Trisha" WHERE UserID=3;]] db:exec( q )
从本质上讲,此查询查找其中 UserID
3
的行,并将 FirstName
值更改为 Trisha
。虽然你不一定要使用主键列来查找行,但这通常是查找特定行的最简单方法,因为它将始终是唯一的。
用于删除行的 SQL 查询看起来与我们用于更新行的查询非常相似,主要区别在于使用了DELETE FROM
UPDATE
。下面的示例从 test
表中删除John Smith
local q = [[DELETE FROM test WHERE UserID=1;]] db:exec( q )
有多种方法可以从 SQL 数据库中检索数据。有时,您只需要一行特定行,而另一些时候您可能需要特定表中的所有行。在其他情况下,为了稍微缩小范围,您可能只想根据特定条件获取某个表中一部分行。所有这些(以及更多)都可以使用 SQLite 实现!
以下示例说明如何从文件中加载现有数据库,并从特定查询的行中填充 Lua 数组。这假定data.db
包含我们的test
)
-- Require the SQLite library local sqlite3 = require( "sqlite3" ) -- Create a file path for the database file "data.db" local path = system.pathForFile( "data.db", system.DocumentsDirectory ) -- Open the database for access local db = sqlite3.open( path ) -- Create empty "people" table local people = {} -- Loop through database table rows via a SELECT query for row in db:nrows( "SELECT * FROM test" ) do print( "Row:", row.UserID ) -- Create sub-table at next available index of "people" table people[#people+1] = { FirstName = row.FirstName, LastName = row.LastName } end
关注的最重点是第 14 行,我们在其中执行 SQL SELECT
语句,并通过 nrows()
方法返回一个迭代器,以便与 for
循环结合使用,以便轻松遍历所有找到的行。在此示例中,我们只需将数据复制到 people
数组中,以便稍后在应用程序中使用它。
有关使用 SELECT
命令筛选数据的详细信息,请阅读这篇文章。
完成对数据库的访问时,非常务必通过在数据库对象上调用 close()
方法(例如 db:close()
)关闭与数据库的“连接”。
if ( db and db:isopen() ) then db:close() end
当然,此代码必须存在于您要关闭的数据库对象的正确作用域中,即上述示例中的 db
对象,以便 Lua 了解它应关闭哪个数据库。
这总结了 Corona 中数据库访问的基本知识。不过,我们仅介绍了 SQLite 所能实现的皮毛,因此我们鼓励您进一步探索以发现更多可能性,从我们的 SQLite 文档 开始。