ZetCode

SQLite Visual Basic 教程介绍

最后修改于 2020 年 7 月 6 日

在 SQLite Visual Basic 教程的第一章中,我们将提供必要的定义。 我们将展示如何安装 Mono 和 Visual Basic。 本教程中的所有示例都将在 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 是基于 ECMA 标准的 Microsoft .NET Framework 的开源实现,用于 C# 和公共语言运行时。 我们需要安装 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 .NET 数据适配器等。

$ 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 的软链接,它位于 gac 子目录中。)

Visual Basic

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

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

我们从 Mono 项目网站下载源代码。 我们解压文件并进入新创建的子目录。

$ ./configure
$ make
$ sudo make install

我们构建并安装编译器。

$ 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 语言。

SqliteConnectionSqliteCommandSqliteDataReaderSqliteDataAdapter 是 .NET 数据提供程序模型的核心元素。 SqliteConnection 创建与特定数据源的连接。 SqliteCommand 对象对数据源执行 SQL 语句。 SqliteDataReader 从数据源读取数据流。 SqliteDataAdapterDataSet 和数据源之间的中介。 它填充 DataSet 并使用数据源解析更新。

DataSet 对象用于离线处理大量数据。 这是一个断开连接的数据表示,可以保存来自各种不同来源的数据。 SqliteDataReaderDataSet 都用于处理数据;它们在不同的情况下使用。 如果我们只需要读取查询的结果,则 SqliteDataReader 是更好的选择。 如果我们需要对数据进行更广泛的处理,或者我们想将 Winforms 控件绑定到数据库表,则首选 DataSet

SQLite 版本

如果第一个程序,我们检查 SQLite 数据库的版本。

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 版本。

Imports Mono.Data.Sqlite

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

Dim con As SqliteConnection
Dim cmd As SqliteCommand

我们声明两个变量。 它们放置在 Try 关键字之前,因为我们稍后将调用 DisposeClose 方法。

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

这是连接字符串。 它由数据提供程序用于建立与数据库的连接。 我们创建一个内存数据库。

con = New SqliteConnection(cs)

创建 SqliteConnection 对象。 此对象用于打开与数据库的连接。

con.Open()

此行打开数据库连接。

Dim stm As String = "SELECT SQLITE_VERSION()"

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

Dim cmd As New SqliteCommand(stm, con)

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

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

有些查询只返回一个标量值。在我们的例子中,我们想要一个指定数据库版本的简单字符串。在这种情况下使用 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

SqliteCommand 类实现了 IDisposable 接口。 因此,它必须在 Finally 块中显式释放。

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。)

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

我们编译我们的示例。 提供了 SQLite 数据提供程序 DLL 的路径。

$ mono version.exe 
SQLite version : 3.7.7

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

Using 语句

Visual Basic 语言实现垃圾回收。 这是一个自动释放不再需要的对象的过程。 该过程是不确定的。 我们无法确定 CLR(公共语言运行时)何时决定释放资源。 对于有限的资源,例如文件句柄或网络连接,最好尽快释放它们。 使用 Using 语句,程序员控制何时释放资源。 当程序退出 Using 块时,要么到达它的末尾,要么抛出异常,资源就会被释放。

在内部,Using 语句被转换为 TryFinally 块,并在 Finally 块中调用 Dispose。 请注意,您可能更喜欢使用 TryCatchFinally 块而不是 Using 语句。 特别是,如果您想显式使用 Catch 块。 在本教程中,我们选择了 Using 语句。

通常,当我们使用 IDisposable 对象时,我们应该在 Using 语句中声明和实例化它。(或在 Finally 块中调用 Dispose。)对于 SQLite ADO.NET 驱动程序,我们对 SqliteConnectionSqliteCommandSqliteDataReaderSqliteCommandBuilderSqliteDataAdapter 类使用 Using 语句。 我们不必对 DataSetDataTable 类使用它。 它们可以留给垃圾收集器。

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 关键字。

Using con As New SqliteConnection(cs)

    con.Open()

    Using cmd As New SqliteCommand(con)

SqliteConnectionSqliteCommand 都实现了 IDisposable 接口。 因此,它们被包装在 Using 关键字中。

创建和填充表

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

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

在上面的代码示例中,我们创建了一个 Cars 表,其中包含 8 行。

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

首先,如果表已经存在,我们删除它。 如果我们不需要结果集,我们可以使用 ExecuteNonQuery 方法。 例如,对于 DROPINSERTDELETE 语句。

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

预处理语句

现在我们将关注预处理语句。当我们编写预处理语句时,我们使用占位符而不是直接将值写入语句中。预处理语句可以提高安全性和性能。

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 表添加一行。 我们使用参数化命令。

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  

我们向表中插入了一辆新车。

来源

咨询了 MSDN(Microsoft 开发人员网络)以创建本教程。 几个定义来自该网站。

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