访问量: 10 次浏览
SQLite C# 简介,本章我们将提供必要的定义,我们将展示如何安装 Mono。本教程中的所有示例都将在 Mono 上运行。稍后,我们创建第一个工作示例。
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 是基于 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 是 .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 数据库的版本。
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
我们有一辆新车插入桌子。