SQLite C# 简介,本章我们将提供必要的定义,我们将展示如何安装 Mono。 本教程中的所有示例都将在 Mono 上运行。 稍后,我们创建第一个工作示例。
关于 SQLite 数据库
SQLite 是嵌入式关系数据库引擎。 它的开发人员称其为自包含,无服务器,零配置和事务型 SQL 数据库引擎。 它非常受欢迎,当今全球有数亿本使用。 SQLite 用于 Solaris 10 和 Mac OS 操作系统,iPhone 或 Skype。 Qt4 库对 SQLite 以及 Python 或 PHP 语言提供了内置支持。 许多流行的应用内部都使用 SQLite,例如 Firefox 或 Amarok。
$ sudo apt-get install sqlite3
如果尚未安装sqlite3
库,则需要安装它。
SQLite 附带sqlite3
命令行实用程序。 它可用于对数据库发出 SQL 命令。 现在,我们将使用sqlite3
命令行工具创建一个新数据库。
$ sqlite3 test.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
我们为sqlite3
工具提供了一个参数。 test.db
是数据库名称。 它是我们磁盘上的单个文件。 如果存在,则将其打开。 如果不是,则创建它。
sqlite> .tables
sqlite> .exit
$ ls
test.db
.tables
命令提供了 test.db 数据库中的表列表。 当前没有表。 .exit
命令终止sqlite3
命令行工具的交互式会话。 ls
Unix 命令显示当前工作目录的内容。 我们可以看到test.db
文件。 所有数据将存储在该单个文件中。
Mono
Mono 是基于 C# 和公共语言运行时的 ECMA 标准的 Microsoft .NET Framework 的开源实现。 在本教程中,我们需要安装 Mono 才能编译和运行示例。
可以从 Linux 发行版的软件包中安装 Mono,也可以从源代码中安装 Mono,以获得更多最新版本。
$ bunzip2 mono-2.10.8.tar.bz2
$ tar -xf mono-2.10.8.tar
$ cd mono-2.10.8/
$ ./configure
$ make
$ sudo make install
我们从 Mono 网站下载mono-2.10.8.tar.bz2
tarball。 解压缩,构建并安装库。 我们安装了 Mono 运行时,C# 语言和 SQLite C# 数据适配器。
$ bunzip2 libgdiplus-2.10.9.tar.bz2
$ tar -xf libgdiplus-2.10.9.tar
$ cd libgdiplus-2.10.9/
$ ./configure
$ make
$ sudo make install
对于带有 Winforms 控件的示例,我们还需要libgdiplus
库。 它位于单独的文件中。 我们构建并安装它。
$ sudo ldconfig
$ ldconfig -p | grep libgdiplus
libgdiplus.so.0 (libc6) => /usr/local/lib/libgdiplus.so.0
libgdiplus.so (libc6) => /usr/local/lib/libgdiplus.so
我们还运行ldconfig
工具来更新动态库的数据库。 ldconfig
扫描正在运行的系统,并设置用于加载共享库的符号链接。
Mono.Data.Sqlite
程序集包含 SQLite 数据库的 ADO.NET 数据提供程序。 它用 C# 编写,并且可用于所有 CLI 语言:C# ,Visual Basic,Boo 等。
$ ls /usr/local/lib/mono/4.0/Mono.Data.Sqlite.dll
/usr/local/lib/mono/4.0/Mono.Data.Sqlite.dll
从技术角度来看,我们需要一个 DLL。 在我们的系统上,它位于上述路径下。 (实际上,以上是指向 DLL 的软链接,该 DLL 位于gac
子目录中。)
ADO.NET
ADO.NET
是.NET 框架的重要组成部分。 该规范统一了对关系数据库,XML 文件和其他应用数据的访问。 从程序员的角度来看,它是一组与数据库和其他数据源一起使用的库和类。 Mono.Data.SQLite
是 SQLite 数据库的 ADO.NET 规范的实现。 它是用 C# 语言编写的驱动程序,可用于所有.NET 语言。
SqliteConnection
,SqliteCommand
,SqliteDataReader
和SqliteDataAdapter
是.NET 数据提供程序模型的核心元素。 SqliteConnection
创建到特定数据源的连接。 SqliteCommand
对象针对数据源执行一条 SQL 语句。 SqliteDataReader
从数据源读取数据流。 SqliteDataAdapter
是DataSet
和数据源之间的中介。 它填充DataSet
并解析数据源的更新。
DataSet
对象用于大量数据的离线工作。 它是一种断开连接的数据表示形式,可以保存来自各种不同来源的数据。 SqliteDataReader
和DataSet
都用于处理数据。 它们在不同的情况下使用。 如果只需要读取查询结果,则SqliteDataReader
是更好的选择。 如果我们需要更广泛的数据处理,或者要将 Winforms 控件绑定到数据库表,则首选DataSet
。
SQLite 版本
如果是第一个程序,我们将检查 SQLite 数据库的版本。
using System;
using Mono.Data.Sqlite;
public class Example
{
static void Main()
{
string cs = "Data Source=:memory:";
SqliteConnection con = null;
SqliteCommand cmd = null;
try
{
con = new SqliteConnection(cs);
con.Open();
string stm = "SELECT SQLITE_VERSION()";
cmd = new SqliteCommand(stm, con);
string version = Convert.ToString(cmd.ExecuteScalar());
Console.WriteLine("SQLite version : {0}", version);
} catch (SqliteException ex)
{
Console.WriteLine("Error: {0}", ex.ToString());
} finally
{
if (cmd != null)
{
cmd.Dispose();
}
if (con != null)
{
try
{
con.Close();
} catch (SqliteException ex)
{
Console.WriteLine("Closing connection failed.");
Console.WriteLine("Error: {0}", ex.ToString());
} finally
{
con.Dispose();
}
}
}
}
}
我们连接到内存数据库并选择一个 SQLite 版本。
using Mono.Data.Sqlite;
Mono.Data.SqliteClient
程序集包含 SQLite 数据库引擎的 ADO.NET 数据提供程序。 我们导入 SQLite 数据提供程序的元素。
string cs = "Data Source=:memory:";
这是连接字符串。 数据提供者使用它来建立与数据库的连接。 我们创建一个内存数据库。
con = new SqliteConnection(cs);
创建一个SqliteConnection
对象。 该对象用于打开与数据库的连接。
con.Open();
这行打开数据库连接。
string stm = "SELECT SQLITE_VERSION()";
这是SQL SELECT
语句。 它返回数据库的版本。 SQLITE_VERSION()
是内置的 SQLite 函数。
SqliteCommand cmd = new SqliteCommand(stm, con);
SqliteCommand
是一个对象,用于在数据库上执行查询。 参数是 SQL 语句和连接对象。
string version = Convert.ToString(cmd.ExecuteScalar());
有些查询仅返回标量值。 在我们的例子中,我们需要一个简单的字符串来指定数据库的版本。 在这种情况下使用ExecuteScalar()
。 我们避免了使用更复杂的对象的开销。
Console.WriteLine("SQLite version : {0}", version);
数据库的版本将打印到控制台。
} catch (SqliteException ex)
{
Console.WriteLine("Error: {0}", ex.ToString());
如果发生异常,我们将错误消息打印到控制台。
} finally
{
if (cmd != null)
{
cmd.Dispose();
}
SqliteCommand
类实现IDisposable
接口。 因此,必须对其进行明确处理。
if (con != null)
{
try
{
con.Close();
} catch (SqliteException ex)
{
Console.WriteLine("Closing connection failed.");
Console.WriteLine("Error: {0}", ex.ToString());
} finally
{
con.Dispose();
}
}
关闭连接可能会引发另一个异常。 我们处理这种情况。
$ dmcs version.cs -r:Mono.Data.Sqlite.dll
我们汇编示例。 提供了 SQLite 数据提供程序 DLL 的路径。
$ mono ./version.exe
SQLite version : 3.7.7
这是我们系统上程序的输出。
使用语句
C# 语言实现垃圾回收。 这是一个自动释放不再需要的对象的过程。 该过程是不确定的。 我们不能确定 CLR(公共语言运行时)何时决定释放资源。 对于有限的资源,例如文件句柄或网络连接,最好尽快释放它们。 使用using
语句,程序员可以控制何时释放资源。 当程序超出了 using 块时,到达其末尾或引发异常,则资源被释放。
在内部,using 语句被转换为 try,finally 块,在 finally 块中调用了Dispose()
。 请注意,您可能更喜欢使用try
,catch
和finally
块,而不是using
语句。 特别是,如果您想显式地利用catch
块。 在本教程中,我们选择了 using 语句。 主要是因为代码较短。
通常,当我们使用IDisposable
对象时,应在 using 语句中声明并实例化它。 (或在 finally 块中调用 Dispose()方法。)对于 SQLite ADO.NET 驱动程序,我们对SqliteConnection
,SqliteCommand
,SqliteDataReader
,SqliteCommandBuilder
和SqliteDataAdapter
使用 using 语句 ]类。 我们不必将其用于DataSet
或DataTable
类。 他们可以留给垃圾收集器。
using System;
using Mono.Data.Sqlite;
public class Example
{
static void Main()
{
string cs = "URI=file:test.db";
using (SqliteConnection con = new SqliteConnection(cs))
{
con.Open();
using (SqliteCommand cmd = new SqliteCommand(con))
{
cmd.CommandText = "SELECT SQLITE_VERSION()";
string version = Convert.ToString(cmd.ExecuteScalar());
Console.WriteLine("SQLite version : {0}", version);
}
con.Close();
}
}
}
我们有同样的例子。 这次我们实现了 using 关键字。
using (SqliteConnection con = new SqliteConnection(cs))
{
con.Open();
using (SqliteCommand cmd = new SqliteCommand(con))
SqliteConnection
和SqliteCommand
都实现IDisposable
接口。 因此,它们用using
关键字包装。
创建并填充表
接下来,我们将创建一个数据库表并用数据填充它。
using System;
using Mono.Data.Sqlite;
public class Example
{
static void Main()
{
string cs = "URI=file:test.db";
using ( SqliteConnection con = new SqliteConnection(cs))
{
con.Open();
using (SqliteCommand cmd = new SqliteCommand(con))
{
cmd.CommandText = "DROP TABLE IF EXISTS Cars";
cmd.ExecuteNonQuery();
cmd.CommandText = @"CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
Name TEXT, Price INT)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(1,'Audi',52642)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(2,'Mercedes',57127)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(3,'Skoda',9000)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(4,'Volvo',29000)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(5,'Bentley',350000)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(6,'Citroen',21000)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(7,'Hummer',41400)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(8,'Volkswagen',21600)";
cmd.ExecuteNonQuery();
}
con.Close();
}
}
}
在上面的代码示例中,我们创建具有 8 行的Cars
表。
cmd.CommandText = "DROP TABLE IF EXISTS Cars";
cmd.ExecuteNonQuery();
首先,如果该表已经存在,则将其删除。 如果我们不想要结果集,例如对于DROP
,INSERT
或DELETE
语句,可以使用ExecuteNonQuery()
方法。
cmd.CommandText = @"CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
Name TEXT, Price INT)";
cmd.ExecuteNonQuery();
Cars
表已创建。 INTEGER PRIMARY KEY
列在 SQLite 中自动增加。
cmd.CommandText = "INSERT INTO Cars VALUES(1,'Audi',52642)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO Cars VALUES(2,'Mercedes',57127)";
cmd.ExecuteNonQuery();
我们在表中插入两行。
sqlite> .mode column
sqlite> .headers on
在sqlite3
命令行工具中,我们修改了数据在控制台中的显示方式。 我们使用列模式并打开标题。
sqlite> SELECT * FROM Cars;
Id Name Price
---------- ---------- ----------
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
我们验证数据。 Cars
表已成功创建。
预备语句
现在,我们将以预备语句来关注自己。 在编写预备语句时,我们使用占位符,而不是直接将值写入语句中。 预准备的语句可提高安全性和性能。
using System;
using Mono.Data.Sqlite;
public class Example
{
static void Main()
{
string cs = "URI=file:test.db";
using(SqliteConnection con = new SqliteConnection(cs))
{
con.Open();
using (SqliteCommand cmd = new SqliteCommand(con))
{
cmd.CommandText = "INSERT INTO Cars(Name, Price) VALUES(@Name, @Price)";
cmd.Prepare();
cmd.Parameters.AddWithValue("@Name", "BMW");
cmd.Parameters.AddWithValue("@Price", 36600);
cmd.ExecuteNonQuery();
}
con.Close();
}
}
}
我们向Cars
表添加一行。 我们使用参数化命令。
cmd.CommandText = "INSERT INTO Cars(Name, Price) VALUES(@Name, @Price)";
cmd.Prepare();
在这里,我们创建一个预备语句。 在编写预备语句时,我们使用占位符,而不是直接将值写入语句中。 预备语句更快,并且可以防止 SQL 注入攻击。 @Name
和@Price
是占位符,稍后将填充。
cmd.Parameters.AddWithValue("@Name", "BMW");
cmd.Parameters.AddWithValue("@Price", 36600);
值绑定到占位符。
cmd.ExecuteNonQuery();
执行预备语句。 当我们不希望返回任何数据时,我们使用SqliteCommand
对象的ExecuteNonQuery()
方法。
$ mono prepared.exe
sqlite> SELECT * FROM Cars;
Id Name Price
---------- ---------- ----------
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
9 BMW 36600
我们有一辆新车插入桌子。