SQL Server 连接

SQL Server 在国内互联网公司不多见,但在传统企业和外企是主流选择。微软的技术栈、完善的工具链、企业级支持,让它在大型系统中占有一席之地。

驱动安装

go get -u gorm.io/driver/sqlserver

底层使用 github.com/microsoft/go-mssqldb,这是微软官方维护的 Go 驱动。

基本连接

package main

import (
    "fmt"
    "gorm.io/driver/sqlserver"
    "gorm.io/gorm"
)

func main() {
    dsn := "sqlserver://sa:Password123@localhost:1433?database=master"
    db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("连接失败")
    }
    fmt.Println("连接成功")
}

DSN 格式

SQL Server 的 DSN 使用 URL 格式:

sqlserver://username:password@host:port?database=dbname

完整参数示例:

sqlserver://sa:Password123@192.168.1.100:1433?database=myapp&encrypt=disable

参数说明

参数说明默认值
database数据库名master
encrypt是否加密连接disable
trustservercertificate是否信任服务器证书false
connection+timeout连接超时秒数30
dial+timeout拨号超时秒数15

encrypt

生产环境建议启用加密:

sqlserver://user:pass@host:1433?database=db&encrypt=true

trustservercertificate

开发环境可以跳过证书验证:

encrypt=true&trustservercertificate=true

SQL Server 特定配置

import "gorm.io/driver/sqlserver"

mssqlConfig := sqlserver.Config{
    DSN:                   dsn,
    DefaultStringSize:     256,
    DefaultDatetimePrecision: 3,
}

db, err := gorm.Open(&mssqlConfig, &gorm.Config{})

DefaultStringSize

字符串默认长度。SQL Server 的 NVARCHAR 需要指定长度,默认 256。

DefaultDatetimePrecision

时间精度。SQL Server 的 DATETIME2 支持最高 7 位小数秒。

认证方式

SQL Server 认证

最常用的方式,用户名密码在 DSN 中指定:

dsn := "sqlserver://sa:Password123@localhost:1433?database=myapp"

Windows 认证

使用当前 Windows 用户凭据:

dsn := "sqlserver://localhost:1433?database=myapp&trusted_connection=yes"

需要驱动支持,且只能在 Windows 上运行。

Schema 支持

SQL Server 的 Schema 概念和 PostgreSQL 类似:

type User struct {
    ID   uint
    Name string
}

db.Table("myapp.dbo.users").Create(&user)

默认连接到 dbo schema,可以显式指定:

dsn := "sqlserver://sa:Password123@localhost:1433?database=myapp&schema=myschema"

自增主键

SQL Server 使用 IDENTITY 实现自增:

type User struct {
    ID   uint `gorm:"primaryKey;autoIncrement"`
    Name string
}

生成的 SQL:

CREATE TABLE "users" ("id" INT IDENTITY(1,1), "name" NVARCHAR(256))

指定起始值和步长:

type User struct {
    ID uint `gorm:"primaryKey;autoIncrement;autoIncrementIncrement:100"`
}

UUID 主键

SQL Server 使用 NEWID() 或 NEWSEQUENTIALID():

import "github.com/google/uuid"

type User struct {
    ID   uuid.UUID `gorm:"primaryKey;default:NEWID()"`
    Name string
}

NEWSEQUENTIALID() 性能更好,适合索引:

ID uuid.UUID `gorm:"primaryKey;default:NEWSEQUENTIALID()"`

时间类型

SQL Server 有多种时间类型:

Go 类型SQL Server 类型
time.TimeDATETIME
time.TimeDATETIME2
time.TimeDATE
time.TimeTIME

GORM 默认使用 DATETIME2,精度更高:

type Event struct {
    ID        uint
    CreatedAt time.Time
    DateOnly  time.Time `gorm:"type:date"`
}

字符串类型

SQL Server 的字符串类型选择:

类型说明
CHAR定长,ASCII
VARCHAR变长,ASCII
NCHAR定长,Unicode
NVARCHAR变长,Unicode

推荐使用 NVARCHAR,支持中文:

type User struct {
    Name string `gorm:"type:nvarchar(100)"`
}

分页查询

SQL Server 的分页语法和 MySQL 不同:

var users []User
db.Offset(10).Limit(10).Find(&users)

GORM 会生成正确的 OFFSET FETCH 语法:

SELECT * FROM "users" ORDER BY "id" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

注意:SQL Server 要求分页查询必须有 ORDER BY。

连接池

sqlDB, _ := db.DB()
sqlDB.SetMaxOpenConns(50)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(time.Hour)

SQL Server 默认最大连接数较高,但仍需合理配置连接池。

已有连接复用

import (
    "database/sql"
    "gorm.io/driver/sqlserver"
)

func ConnectFromExisting(sqlDB *sql.DB) (*gorm.DB, error) {
    return gorm.Open(sqlserver.New(sqlserver.Config{
        Conn: sqlDB,
    }), &gorm.Config{})
}

常见错误

登录失败

Login failed for user 'sa'

检查用户名密码,确认 SQL Server 允许 SQL 认证。默认安装可能只允许 Windows 认证。

连接超时

A network-related or instance-specific error occurred

检查:

  • SQL Server 服务是否启动
  • TCP/IP 协议是否启用
  • 防火墙是否放行 1433 端口

数据库不存在

Cannot open database "myapp" requested by the login

先创建数据库:

CREATE DATABASE myapp;

证书错误

A connection was successfully established with the server, but then an error occurred during the login process

开发环境可以禁用加密或信任证书:

encrypt=true&trustservercertificate=true

与 MySQL 的差异

从 MySQL 迁移到 SQL Server,注意这些差异:

特性MySQLSQL Server
字符串引号单引号或双引号单引号
标识符引号反引号 `方括号 []
布尔类型TINYINT(1)BIT
自增AUTO_INCREMENTIDENTITY
字符串连接CONCAT()+
分页LIMIT offset, sizeOFFSET FETCH

GORM 会处理大部分差异,原生 SQL 需要适配。

性能建议

索引优化

SQL Server 的索引功能强大,合理使用:

CREATE INDEX idx_user_name ON users(name);
CREATE CLUSTERED INDEX idx_user_id ON users(id);

存储过程

复杂业务逻辑可以封装成存储过程:

db.Exec("EXEC sp_update_user_stats @user_id = ?", userID)

批量操作

大批量数据用 BULK INSERT:

db.Exec("BULK INSERT users FROM '/data/users.csv'")

小结

SQL Server 在企业级场景有独特优势,但配置和使用习惯和开源数据库有差异。理解这些差异,迁移和开发会更顺畅。下一章看连接池配置。