vb连接数据库怎么用:从准备到完成的实操步骤

vb连接数据库怎么用:从准备到完成的实操步骤

vb连接数据库怎么用:从准备到完成的实操步骤

VB 连接数据库,核心工作通常是准备数据库驱动、配置连接字符串、打开连接、执行 SQL,再妥善处理结果和异常。本文以 VB.NET + SQL Server + Microsoft.Data.SqlClient 为例,从环境准备写到可运行的增删改查程序,并说明参数化查询能解决什么、不能解决什么。

“VB”可能指 VB.NET,也可能指较早的 VB6。本文代码适用于 VB.NET,不适用于 VB6。VB6 常见做法是通过 ADO、OLE DB 等组件连接数据库,不能直接照搬本文使用的 .NET 类。若你维护的是 VB6 项目,应按其运行环境和数据库驱动另行处理。

一、先确认适用场景和组件

示例适合桌面程序、后台服务、命令行工具等通过 .NET 访问 SQL Server 的场景。代码使用 Microsoft.Data.SqlClient,这是面向 .NET 的 SQL Server 数据访问库。它不负责安装或启动 SQL Server,也不会替你创建数据库;数据库服务、账号权限和网络连通性仍需单独准备。

  • 已安装 .NET SDK,并能创建、运行 VB.NET 项目。
  • 有可访问的 SQL Server 实例,以及创建表、读取和写入数据所需的权限。
  • 项目引用 Microsoft.Data.SqlClient NuGet 包。

创建 VB.NET 控制台项目并安装依赖,可以使用以下命令:

dotnet new console -lang VB -n VbDatabaseDemo
cd VbDatabaseDemo
dotnet add package Microsoft.Data.SqlClient

如果你使用 Visual Studio,也可以新建 VB 控制台项目,再通过“管理 NuGet 程序包”安装 Microsoft.Data.SqlClient。项目目标框架应与本机已安装的 .NET SDK 相匹配。

二、准备数据库和数据表

先在 SQL Server 中创建一个数据库,再在该数据库内执行下面的建表语句。示例表用于保存联系人姓名和邮箱,邮箱允许为空。

CREATE TABLE dbo.Contacts
(
    Id int IDENTITY(1,1) NOT NULL
        CONSTRAINT PK_Contacts PRIMARY KEY,
    Name nvarchar(100) NOT NULL,
    Email nvarchar(254) NULL
);

可使用 SQL Server Management Studio、Azure Data Studio,或其他支持 SQL Server 的管理工具执行这段 SQL。表创建完成后,程序使用的数据库账号至少需要对该表拥有相应的读取、插入、更新和删除权限。日常应用不宜直接使用服务器管理员账号。

三、配置连接字符串

连接字符串描述程序要连接哪个实例、使用哪个数据库,以及采用哪种身份验证方式。为了避免把密码写进源代码,下面通过环境变量读取连接字符串。

Windows PowerShell 示例:

$env:VB_DB_CONNECTION = "Server=localhost;Database=VbDemo;Integrated Security=True;TrustServerCertificate=True"

Linux 或 macOS shell 示例:

export VB_DB_CONNECTION='Server=localhost;Database=VbDemo;Integrated Security=True;TrustServerCertificate=True'

请将 VbDemo 替换成实际数据库名称。如果使用 SQL Server 登录名和密码,连接字符串可采用类似格式:

Server=db.example.com;Database=VbDemo;User ID=app_user;Password=替换为实际密码;Encrypt=True;TrustServerCertificate=False

应根据 SQL Server 版本、部署环境和组织策略配置加密与证书验证。TrustServerCertificate=True 会跳过服务器证书的验证,适合某些本地开发测试情形,但不能把它当成生产环境的通用安全设置。生产部署应正确配置服务器证书,并遵循实际环境的 TLS 要求。

环境变量比把密码直接写进代码或提交到版本库更合适,但并不等于完整的密钥管理方案。生产系统可使用受控的机密管理服务或部署平台的密钥配置功能,并限制可读取凭据的人员和进程。

四、完整示例:新增、查询、更新和删除

将项目的 Program.vb 内容替换为下面代码。程序会先插入一条记录,再查询、更新、重新查询并删除它。运行前请确认数据库和 dbo.Contacts 表已经创建,并已设置连接字符串环境变量。

Option Strict On

Imports System
Imports Microsoft.Data.SqlClient

Module Program
    Sub Main()
        Dim connectionString As String =
            Environment.GetEnvironmentVariable("VB_DB_CONNECTION")

        If String.IsNullOrWhiteSpace(connectionString) Then
            Console.Error.WriteLine(
                "请先设置 VB_DB_CONNECTION 环境变量。")
            Return
        End If

        Try
            Dim newId As Integer = InsertContact(
                connectionString,
                "陈小明",
                "[email protected]")

            Console.WriteLine("已新增记录,Id = " & newId)
            ShowContact(connectionString, newId)

            UpdateContact(
                connectionString,
                newId,
                "陈小明",
                "[email protected]")

            Console.WriteLine("更新后:")
            ShowContact(connectionString, newId)

            DeleteContact(connectionString, newId)
            Console.WriteLine("已删除测试记录。")

        Catch ex As SqlException
            Console.Error.WriteLine(
                "数据库操作失败:" & ex.Message)
        Catch ex As Exception
            Console.Error.WriteLine(
                "程序运行失败:" & ex.Message)
        End Try
    End Sub

    Private Function InsertContact(
        connectionString As String,
        name As String,
        email As String) As Integer

        Const sql As String =
            "INSERT INTO dbo.Contacts (Name, Email) " &
            "OUTPUT INSERTED.Id " &
            "VALUES (@Name, @Email);"

        Using connection As New SqlConnection(connectionString)
            Using command As New SqlCommand(sql, connection)
                command.Parameters.Add(
                    "@Name", SqlDbType.NVarChar, 100).Value = name

                command.Parameters.Add(
                    "@Email", SqlDbType.NVarChar, 254).Value = email

                connection.Open()
                Return Convert.ToInt32(command.ExecuteScalar())
            End Using
        End Using
    End Function

    Private Sub ShowContact(
        connectionString As String,
        id As Integer)

        Const sql As String =
            "SELECT Id, Name, Email " &
            "FROM dbo.Contacts WHERE Id = @Id;"

        Using connection As New SqlConnection(connectionString)
            Using command As New SqlCommand(sql, connection)
                command.Parameters.Add(
                    "@Id", SqlDbType.Int).Value = id

                connection.Open()

                Using reader As SqlDataReader = command.ExecuteReader()
                    If Not reader.Read() Then
                        Console.WriteLine("没有找到该记录。")
                        Return
                    End If

                    Dim emailText As String =
                        If(reader.IsDBNull(2), "(无邮箱)", reader.GetString(2))

                    Console.WriteLine(
                        "Id={0}, Name={1}, Email={2}",
                        reader.GetInt32(0),
                        reader.GetString(1),
                        emailText)
                End Using
            End Using
        End Using
    End Sub

    Private Sub UpdateContact(
        connectionString As String,
        id As Integer,
        name As String,
        email As String)

        Const sql As String =
            "UPDATE dbo.Contacts " &
            "SET Name = @Name, Email = @Email " &
            "WHERE Id = @Id;"

        Using connection As New SqlConnection(connectionString)
            Using command As New SqlCommand(sql, connection)
                command.Parameters.Add(
                    "@Name", SqlDbType.NVarChar, 100).Value = name

                command.Parameters.Add(
                    "@Email", SqlDbType.NVarChar, 254).Value = email

                command.Parameters.Add(
                    "@Id", SqlDbType.Int).Value = id

                connection.Open()
                Dim affectedRows As Integer = command.ExecuteNonQuery()

                If affectedRows = 0 Then
                    Console.WriteLine("没有记录被更新。")
                End If
            End Using
        End Using
    End Sub

    Private Sub DeleteContact(
        connectionString As String,
        id As Integer)

        Const sql As String =
            "DELETE FROM dbo.Contacts WHERE Id = @Id;"

        Using connection As New SqlConnection(connectionString)
            Using command As New SqlCommand(sql, connection)
                command.Parameters.Add(
                    "@Id", SqlDbType.Int).Value = id

                connection.Open()
                Dim affectedRows As Integer = command.ExecuteNonQuery()

                If affectedRows = 0 Then
                    Console.WriteLine("没有记录被删除。")
                End If
            End Using
        End Using
    End Sub
End Module

运行命令:

dotnet run

五、代码里的关键步骤

1. 创建并打开连接

SqlConnection 表示到 SQL Server 的连接。创建对象不等于已经连接;调用 Open() 后才会实际建立连接。连接字符串错误、服务器未启动、网络受阻或账号权限不足,都可能导致打开连接失败。

示例在每个数据库操作中使用 Using。代码离开 Using 块时,连接、命令和读取器都会释放,即使中途发生异常也会执行释放逻辑。连接池会复用已经释放的连接资源,因此通常不应为了“复用”而长期保持一个连接打开。常见做法是按操作打开连接、完成后及时释放。

2. 执行 SQL 并选择正确的方法

  • ExecuteNonQuery() 常用于插入、更新、删除等不需要读取结果集的语句,返回受影响行数。
  • ExecuteScalar() 返回结果集第一行第一列,适合读取单个值。本例通过 SQL Server 的 OUTPUT INSERTED.Id 取回新记录的主键。
  • ExecuteReader() 用于读取多行或多列结果。读取器使用完毕后应释放。

受影响行数为 0 不一定是异常,可能表示条件没有匹配到记录;具体处理方式要由业务逻辑决定。

3. 使用参数,而不是拼接用户输入

示例用 @Name、@Email 和 @Id 作为参数占位符,再通过 Parameters.Add 指定数据库类型和长度。参数值作为数据传递,不会被当成 SQL 代码解析。这是减少 SQL 注入风险、避免引号和转义处理错误的基本做法。

参数化并不意味着可以跳过输入校验。程序仍应按业务规则验证必填项、字符串长度、格式和范围;数据库也应设置合适的约束。参数类型和长度最好与数据库列定义相符,例如表中 Name 是 nvarchar(100),参数也指定为 SqlDbType.NVarChar、长度 100。

SQL 参数用于表示值,不能直接代替表名、列名、关键字或排序方向。例如,下面这种想法不能通过给表名加参数实现:

SELECT * FROM @TableName

如果确实需要动态表名或排序列,应从程序内的固定白名单中选择允许的标识符,并按数据库规则正确引用;不要把用户提供的任意文本直接拼接进 SQL。参数也不能自动实现权限控制,数据库账号仍需遵循最小权限原则。

4. 处理空值

数据库的 NULL 不是 VB 的普通字符串空值。向数据库写空值时,应使用 DBNull.Value,而不是把字符串 Nothing 当作 SQL NULL 的通用写法。示例中的邮箱列允许为空,但示例输入的是非空邮箱;若要支持空邮箱,可在赋值时显式转换:

Dim emailValue As Object =
    If(String.IsNullOrEmpty(email),
       CType(DBNull.Value, Object),
       email)

command.Parameters.Add(
    "@Email", SqlDbType.NVarChar, 254).Value = emailValue

读取数据库可空列时,先用 reader.IsDBNull 判断,再调用 GetString 等类型化读取方法。直接对 SQL NULL 调用 GetString 会引发异常。

六、事务:让多步操作一起成功或一起回滚

如果一项业务需要执行多条必须保持一致的写操作,可以使用事务。例如,转账需要同时扣除一个账户余额并增加另一个账户余额;若只完成其中一步,就会产生错误数据。下面是事务结构示例,表名和业务校验应按实际系统设计:

Using connection As New SqlConnection(connectionString)
    connection.Open()

    Using transaction As SqlTransaction = connection.BeginTransaction()
        Try
            Using command As New SqlCommand(
                "UPDATE dbo.Accounts " &
                "SET Balance = Balance - @Amount " &
                "WHERE Id = @FromId AND Balance >= @Amount;",
                connection,
                transaction)

                command.Parameters.Add(
                    "@Amount", SqlDbType.Decimal).Value = 50D
                command.Parameters("@Amount").Precision = 18
                command.Parameters("@Amount").Scale = 2
                command.Parameters.Add(
                    "@FromId", SqlDbType.Int).Value = 1

                Dim changed As Integer = command.ExecuteNonQuery()
                If changed <> 1 Then
                    Throw New InvalidOperationException(
                        "扣款失败或余额不足。")
                End If
            End Using

            ' 在此处执行同一事务中的其他数据库操作,
            ' 并将 transaction 传给对应的 SqlCommand。

            transaction.Commit()
        Catch
            transaction.Rollback()
            Throw
        End Try
    End Using
End Using

事务中的所有命令必须使用同一个连接,并把同一个事务对象传给命令。事务能保证数据库事务范围内操作的原子性,但不能自动撤销已经发送的邮件、调用的外部接口等数据库之外的副作用。长期事务会占用资源、持有锁,应尽量缩短执行时间。

七、常见错误及排查方向

连接字符串环境变量为空

确认变量名完全一致,并确认它是在启动程序的同一个终端或运行环境中设置的。使用 Visual Studio 启动时,系统终端中的临时环境变量未必会自动传入调试进程,可在项目调试配置中设置环境变量。

无法连接服务器或登录失败

检查实例名称、数据库名称、端口、防火墙、网络访问规则、SQL Server 服务状态,以及当前采用的是 Windows 身份验证还是 SQL Server 身份验证。登录成功后仍可能因权限不足而无法读写目标表。

找不到表或列

确认建表语句执行在连接字符串指定的数据库中,并检查对象名称、架构和列名。示例明确写了 dbo.Contacts;如果表建在其他架构,需要同步修改 SQL。

参数类型或长度不匹配

参数应与列类型相符,特别是整数、日期、小数和 Unicode 文本。小数参数可设置 Precision 和 Scale;字符串参数长度应与列定义及业务限制一致。不要仅靠数据库截断或报错来做用户输入验证。

把查询结果当成一行或一个值

ExecuteScalar 只返回一个单元格,不适合读取多行;需要逐行处理时应使用 ExecuteReader。查询可能没有结果,读取前应检查 Read() 的返回值,并根据字段是否可空处理 NULL。

直接拼接输入导致查询异常或安全问题

不要把姓名、邮箱、搜索文本等输入通过字符串连接拼成 SQL。除了增加注入风险,输入中的引号、特殊字符也可能造成语法错误。用参数传递数据值,并另行处理动态标识符的白名单。

八、关于参数数量的准确边界

参数不是无限的,限制取决于数据库引擎、驱动和具体操作。对于 SQL Server,一条语句或存储过程最多可包含 2100 个参数,这属于 SQL Server 的限制,不应误认为所有数据库和驱动都使用同一上限。批量写入时,若每行占用多个参数,参数总数会随行数增长;超出限制时,应分批执行,或评估表值参数、批量复制等适合该场景的方案。选择方案时仍要结合目标 SQL Server 版本、数据规模和事务需求。

不要因为存在参数上限,就把参数化改成直接拼接数据。分批参数化、结构化批量传输等方式都可以在保持数据与 SQL 分离的基础上处理大数据量。参数化主要防止数据值被解释成 SQL 代码,并帮助明确数据类型;它不是防止越权、保障机密、加密连接或验证业务规则的万能机制。

九、实操检查清单

  • 确认项目是 VB.NET,并已安装 Microsoft.Data.SqlClient。
  • 确认 SQL Server 实例可访问,数据库和目标表已经创建。
  • 连接字符串来自受控配置,且数据库账号遵循最小权限原则。
  • 所有外部输入作为参数传入,不拼接成 SQL 值。
  • 参数类型、长度与数据库列定义相符,空值使用 DBNull.Value。
  • 连接、命令和读取器都妥善释放,必要时使用短事务保证多步写入一致。
  • 生产环境正确配置传输加密和证书验证,并避免将异常中的敏感信息直接展示给终端用户。

掌握这些步骤后,连接数据库并不只是“调用 Open”:还要同时考虑驱动、配置、参数、权限、空值和资源生命周期。先用本文的小型控制台示例验证连接与 CRUD,再把数据访问逻辑按项目结构封装,通常比一开始就把 SQL、界面事件和业务规则写在同一个地方更容易维护。

© 版权声明

相关文章