# SQLite Visual Basic 简介

> 原文： [http://zetcode.com/db/sqlitevb/intro/](http://zetcode.com/db/sqlitevb/intro/)

在 SQLite Visual Basic 教程的第一章中，我们将提供必要的定义。 我们将展示如何安装 Mono & Visual Basic。 本教程中的所有示例都将在 Mono 上运行。 稍后，我们创建第一个工作示例。

## 关于 SQLite 数据库

`SQLite`是嵌入式关系数据库引擎。 它的开发者称其为自包含，无服务器，零配置和事务型 SQL 数据库引擎。 它非常受欢迎，当今全球有数亿本使用。 SQLite 用于 Solaris 10 和 Mac OS 操作系统，iPhone 或 Skype。 Qt4 库对 SQLite 以及 Python 或 PHP 语言提供了内置支持。 许多流行的应用内部都使用 SQLite，例如 Firefox 或 Amarok。

```vb
$ sudo apt-get install sqlite3

```

如果尚未安装`sqlite3`库，则需要安装它。

SQLite 附带`sqlite3`命令行工具。 它可用于对数据库发出 SQL 命令。 现在，我们将使用`sqlite3`命令行工具创建一个新数据库。

```vb
$ sqlite3 test.db
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"

```

我们为`sqlite3`工具提供了一个参数。 `test.db`是数据库名称。 它是我们磁盘上的单个文件。 如果存在，则将其打开。 如果不是，则创建它。

```vb
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，以获得更多最新版本。

```vb
$ 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 .NET 数据适配器。

```vb
$ 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`库。 它位于单独的文件中。 我们构建并安装它。

```vb
$ 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。

```vb
$ 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`子目录中。）

## Visual Basic

`Visual Basic`是一种现代的，高层通用的，基于对象的编程语言。 它是.NET 框架中第二重要的语言。 该语言的主要设计目标是创建一种易于使用和学习的编程语言。 它源自经典的 BASIC 语言。 Mono 将 Visual Basic 引入 Unix 平台。 它在单独的包中具有 Visual Basic 编译器。

```vb
$ bunzip2 mono-basic-2.10.tar.bz2
$ tar xvf mono-basic-2.10.tar
$ cd mono-basic-2.10/

```

我们从 Mono 项目网站下载资源。 我们对文件进行压缩，然后进入新创建的子目录。

```vb
$ ./configure
$ make
$ sudo make install

```

我们建立&安装编译器。

```vb
$ ls /usr/local/bin/vbnc*
/usr/local/bin/vbnc  /usr/local/bin/vbnc2

```

编译器称为 vbnc，默认情况下位于`/usr/local/lib/bin`目录中。

## 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 数据库的版本。

```vb
Option Strict On

Imports Mono.Data.Sqlite

Module Example

    Sub Main()

        Dim con As SqliteConnection
        Dim cmd As SqliteCommand

        Try            
            Dim cs As String = "Data Source=:memory:"
            con = New SqliteConnection(cs)
            con.Open()

            Dim stm As String = "SELECT SQLITE_VERSION()"
            cmd = New SqliteCommand(stm, con)

            Dim version As String = Convert.ToString(cmd.ExecuteScalar())

            Console.WriteLine("SQLite version : {0}", version)

        Catch ex As SqliteException

            Console.WriteLine("Error: " & ex.ToString())

        Finally

            If cmd IsNot Nothing
                cmd.Dispose()
            End If

            If con IsNot Nothing

                Try
                    con.Close()
                Catch ex As SqliteException
                    Console.WriteLine("Failed closing connection")
                    Console.WriteLine("Error: " & ex.ToString())
                Finally
                    con.Close()
                    con.Dispose()
                End Try

            End If

        End Try

    End Sub

End Module

```

我们连接到内存数据库，然后选择 SQLite 版本。

```vb
Imports Mono.Data.Sqlite

```

`Mono.Data.SqliteClient`程序集包含 SQLite 数据库引擎的 ADO.NET 数据供应器。 我们导入 SQLite 数据供应器的元素。

```vb
Dim con As SqliteConnection
Dim cmd As SqliteCommand

```

我们声明两个变量。 它们被放置在`Try`关键字之前，因为我们稍后将在它们上调用`Dispose()`和`Close()`方法。

```vb
Dim cs As String = "Data Source=:memory:"

```

这是连接字符串。 数据提供者使用它来建立与数据库的连接。 我们创建一个内存数据库。

```vb
con = New SqliteConnection(cs)

```

创建一个`SqliteConnection`对象。 该对象用于打开与数据库的连接。

```vb
con.Open()

```

这行打开数据库连接。

```vb
Dim stm As String = "SELECT SQLITE_VERSION()"

```

这是 SQL `SELECT`语句。 它返回数据库的版本。 `SQLITE_VERSION()`是内置的 SQLite 函数。

```vb
Dim cmd As New SqliteCommand(stm, con)

```

`SqliteCommand`是一个对象，用于在数据库上执行查询。 参数是 SQL 语句和连接对象。

```vb
Dim version As String = Convert.ToString(cmd.ExecuteScalar())

```

有些查询仅返回标量值。 在我们的例子中，我们需要一个简单的字符串来指定数据库的版本。 在这种情况下使用`ExecuteScalar()`。 我们避免了使用更复杂的对象的开销。

```vb
Console.WriteLine("SQLite version : {0}", version)

```

数据库的版本将打印到控制台。

```vb
Catch ex As SqliteException

    Console.WriteLine("Error: " & ex.ToString())

```

如果发生异常，我们将错误消息打印到控制台。

```vb
Finally

    If cmd IsNot Nothing
        cmd.Dispose()
    End If

```

`SqliteCommand`类实现`IDisposable`接口。 因此，必须将其显式放置在`Finally`块中。

```vb
If con IsNot Nothing

    Try
        con.Close()
    Catch ex As SqliteException
        Console.WriteLine("Failed closing connection")
        Console.WriteLine("Error: " & ex.ToString())
    Finally
        con.Close()
        con.Dispose()
    End Try

End If

```

关闭连接可能会引发另一个异常。 我们处理这种情况。 （尽管这种情况更有可能发生在基于服务器的数据库中，例如 MySQL 或 PostgreSQL。）

```vb
$ vbnc version.vb -r:Mono.Data.Sqlite.dll

```

我们汇编示例。 提供了 SQLite 数据供应器 DLL 的路径。

```vb
$ mono version.exe 
SQLite version : 3.7.7

```

这是我们系统上程序的输出。

## `using`语句

Visual Basic 语言实现垃圾回收。 这是一个自动释放不再需要的对象的过程。 该过程是不确定的。 我们不能确定 CLR（公共语言运行时）何时决定释放资源。 对于有限的资源，例如文件句柄或网络连接，最好尽快释放它们。 使用`Using`语句，程序员可以控制何时释放资源。 当程序不在`Using`块中时，到达其末尾或引发异常，资源将被释放。

在内部，通过`Finally`块中的`Dispose()`调用将`Using`语句转换为`Try`和`Finally`块。 请注意，您可能更喜欢使用`Try`，`Catch`和`Finally`块，而不是`Using`语句。 特别是，如果您想显式地利用`Catch`块。 在本教程中，我们选择了`Using`语句。

通常，当我们使用`IDisposable`对象时，应在`Using`语句中声明并实例化它。 （或在`Finally`块中调用`Dispose()`。）对于 SQLite ADO.NET 驱动程序，我们对`SqliteConnection`，`SqliteCommand`，`SqliteDataReader`，`SqliteCommandBuilder`使用`Using`语句。 和`SqliteDataAdapter`类。 我们不必将其用于`DataSet`。 或`DataTable`类。 他们可以留给垃圾收集器。

```vb
Option Strict On

Imports Mono.Data.Sqlite

Module Example

    Sub Main()

        Dim cs As String = "URI=file:test.db"

        Using con As New SqliteConnection(cs)

            con.Open()

            Using cmd As New SqliteCommand(con)

                cmd.CommandText = "SELECT SQLITE_VERSION()"

                Dim version As String = Convert.ToString(cmd.ExecuteScalar())
                Console.WriteLine("SQLite version : {0}", version)

            End Using

            con.Close()

        End Using

    End Sub

End Module

```

我们有同样的例子。 这次我们实现了`Using`关键字。

```vb
Using con As New SqliteConnection(cs)

    con.Open()

    Using cmd As New SqliteCommand(con)

```

`SqliteConnection`和`SqliteCommand`都实现`IDisposable`接口。 因此，它们用`Using`关键字包装。

## 创建并填充表

接下来，我们将创建一个数据库表并用数据填充它。

```vb
Option Strict On

Imports Mono.Data.Sqlite

Module Example

    Sub Main()

        Dim cs As String = "URI=file:test.db"

        Using con As New SqliteConnection(cs)

            con.Open()

            Using cmd As 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()

            End Using

            con.Close()

        End Using

    End Sub

End Module

```

在上面的代码示例中，我们创建具有 8 行的`Cars`表。

```vb
cmd.CommandText = "DROP TABLE IF EXISTS Cars"
cmd.ExecuteNonQuery()

```

首先，如果该表已经存在，则将其删除。 如果我们不想要结果集，则可以使用`ExecuteNonQuery()`方法。 例如，对于`DROP`，`INSERT`或`DELETE`语句。

```vb
cmd.CommandText = "CREATE TABLE Cars(Id INTEGER PRIMARY KEY," _
    & "Name TEXT, Price INT)"
cmd.ExecuteNonQuery()

```

`Cars`表已创建。 `INTEGER PRIMARY KEY`列在 SQLite 中自动增加。

```vb
cmd.CommandText = "INSERT INTO Cars VALUES(1,'Audi',52642)"
cmd.ExecuteNonQuery()
cmd.CommandText = "INSERT INTO Cars VALUES(2,'Mercedes',57127)"
cmd.ExecuteNonQuery()

```

我们在表中插入两行。

```vb
sqlite> .mode column  
sqlite> .headers on

```

在`sqlite3`命令行工具中，我们修改了数据在控制台中的显示方式。 我们使用列模式并打开标题。

```vb
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`表已成功创建。

## 预备语句

现在，我们将以预备语句来关注自己。 在编写预备语句时，我们使用占位符，而不是直接将值写入语句中。 预准备的语句可提高安全性和性能。

```vb
Option Strict On

Imports Mono.Data.Sqlite

Module Example

    Sub Main()

        Dim cs As String = "URI=file:test.db"

        Using con As New SqliteConnection(cs)

            con.Open()

            Using cmd As 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()

            End Using

            con.Close()

        End Using

    End Sub

End Module

```

我们向`Cars`表添加一行。 我们使用参数化命令。

```vb
cmd.CommandText = "INSERT INTO Cars(Name, Price) VALUES(@Name, @Price)"
cmd.Prepare()

```

在这里，我们创建一个预备语句。 在编写预备语句时，我们使用占位符，而不是直接将值写入语句中。 预备语句更快，并且可以防止 SQL 注入攻击。 `@Name`和`@Price`是占位符，稍后将填充。

```vb
cmd.Parameters.AddWithValue("@Name", "BMW")
cmd.Parameters.AddWithValue("@Price", 36600)

```

值绑定到占位符。

```vb
cmd.ExecuteNonQuery()

```

执行预备语句。 当我们不希望返回任何数据时，我们使用`SqliteCommand`对象的`ExecuteNonQuery()`方法。

```vb
$ 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  

```

我们有一辆新车插入表。

## 数据来源

已咨询 MSDN（Microsoft 开发者网络）来创建本教程。 该网站有几种定义。

这是 SQLite Visual Basic 教程的介绍性章节。