oracle

package module
v1.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 24 Imported by: 0

README

GORM Oracle Driver

基于 go-ora 实现的 GORM Oracle 数据库驱动,内置版本感知能力、驱动抽象层(go-ora / godror 可切换)、自定义回调体系(INSERT/UPDATE/DELETE/QUERY)与完整测试套件。

特性

  • 版本感知:自动识别 Oracle 数据库版本,按版本适配 SQL 语法与类型
    • 12c+:原生 IDENTITY 列、OFFSET / FETCH 分页、DEFAULT <seq>.NEXTVAL
    • 11g:自动创建序列 + BEFORE INSERT 触发器模拟自增,分页改写为 ROWNUM
    • 21c+:原生 BOOLEAN 列类型(更早版本用 NUMBER(1) 模拟)
    • 23ai:支持 VECTOR 类型(AI Vector Search)
    • 12c+(Extended):VARCHAR2 支持最大 32k 字节,超出自动降级为 CLOB
  • 驱动抽象层driver_adapter):统一 go-ora(纯 Go)与 godror(基于 ODPI-C)的差异,通过 Config.DriverType 一键切换
  • 自定义回调体系
    • INSERT ... RETURNING INTO:支持默认值/自增字段回填,批量插入逐行执行保证一致性与返回值正确性
    • ON CONFLICTMERGE INTO:自动改写为 Oracle MERGE 语法
    • 单行 UPDATE/DELETE ... RETURNING INTO
    • WHERE 安全检查:无有效 WHERE 条件时拒绝执行 UPDATE/DELETE,避免全表误操作(软删除条件除外)
    • 软删除支持
  • 数据迁移(Migrator):
    • 表/列/索引/约束的增删改查,列名大小写自动映射(Oracle 返回大写列名)
    • 从数据字典(USER_TAB_COLUMNS)获取真实数据类型,避免 AutoMigrate 误判触发多余 ALTER
    • Oracle 不支持原生 ON UPDATE 外键操作,自动生成触发器模拟 CASCADE / SET NULL
    • Oracle 保留字自动加引号
  • 命名策略统一转换为大写

环境要求

  • Oracle 11g、12c 及以上(支持 21c、23ai 等新版本)
  • Golang 1.22+
  • GORM v1.31.2+
  • 底层驱动默认使用 go-ora v2(纯 Go 实现,无需安装 ODPI-C

安装

go get github.com/charlienet/oracle

快速开始

import (
    "gorm.io/gorm"

    oracle "github.com/charlienet/oracle"
)

func main() {
    dsn := "oracle://user:password@127.0.0.1:1521/XE?SSL=false"
    db, err := gorm.Open(oracle.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }
    // do something...
}
DSN 格式

DSN 使用 go-ora 的 URL 格式:

oracle://user:password@host:port/service?SSL=false&CONNECTION TIMEOUT=90&SOCKET TIMEOUT=90

常用参数:

  • SSL:是否启用 TLS 加密
  • CONNECTION TIMEOUT:连接建立超时(秒),go-ora v2.9.0 起该参数只控制连接建立
  • SOCKET TIMEOUT:socket 读写超时(秒),需要读超时保护时配合 CONNECTION TIMEOUT 一起设置
  • LANGUAGE / TERRITORY:会话语言与地区,如 LANGUAGE=SIMPLIFIED+CHINESE&TERRITORY=CHINA

配置项

使用 oracle.New(Config{}) 可获得更多配置能力:

import (
    "gorm.io/gorm"

    oracle "github.com/charlienet/oracle"
    "github.com/charlienet/oracle/driver_adapter"
)

db, err := gorm.Open(oracle.New(oracle.Config{
    DSN:                  "oracle://user:password@127.0.0.1:1521/XE",
    DriverType:           driver_adapter.DriverGoOra, // 驱动类型:go-ora(默认)或 godror
    SkipQuoteIdentifiers: false,                      // 是否跳过标识符引用
    DBName:               "SCOTT",                    // 指定 Schema(表名将带 Schema 前缀)
    // Conn: 传入已存在的 *sql.DB 连接池
}), &gorm.Config{})
配置项 说明
DSN 连接串
DriverType 底层驱动类型:driver_adapter.DriverGoOra(默认)/ driver_adapter.DriverGodror
SkipQuoteIdentifiers true 时不引用标识符
DBName 指定 Schema 名,开启后表名自动带上 SCHEMA.TABLE 前缀
Conn 直接传入已建立的连接池(*sql.DB),此时忽略 DSN
DefaultStringSize 字符串字段未指定大小时的默认长度(默认 1024)
驱动抽象层

driver_adapter 包统一了不同 Oracle 驱动的差异(输出参数、LOB、批量数据、多行 RETURNING 等能力探测),默认使用 go-ora(纯 Go,无需本地依赖)。如需切换到 godror:

  1. 在代码中显式指定 DriverType: driver_adapter.DriverGodror
  2. 引入 godror 依赖并使用 -tags godror 构建(driver_adapter/godror.gogo:build godror 约束)

版本适配行为

特性 Oracle 11g Oracle 12c+ Oracle 21c+ Oracle 23ai
自增主键 序列 + BEFORE INSERT 触发器 GENERATED BY DEFAULT AS IDENTITY 同 12c 同 12c
DEFAULT <seq>.NEXTVAL 建表后创建触发器实现 原生 DEFAULT 子句 同 12c 同 12c
分页(Limit/Offset) ROWNUM 改写 OFFSET n ROWS FETCH NEXT n ROWS ONLY 同 12c 同 12c
BOOLEAN NUMBER(1) NUMBER(1) 原生 BOOLEAN 原生 BOOLEAN
超长字符串(>4000) CLOB VARCHAR2(n)(32k) 同 12c 同 12c
VECTOR 类型 不支持 不支持 不支持 支持

版本通过连接后执行 select version from product_component_version where rownum = 1 自动探测,无需手动配置。

常用操作示例

// 创建(自动回填自增主键/默认值字段)
user := User{Name: "Alice", Email: "alice@example.com"}
db.Create(&user) // user.ID 自动回填

// 批量插入
users := []User{{Name: "A"}, {Name: "B"}}
db.Create(&users)

// Upsert(自动改写为 MERGE INTO)
db.Clauses(clause.OnConflict{DoUpdates: clause.AssignmentColumns([]string{"name"})}).
    Create(&user)

// 更新(无 WHERE 条件会被拒绝)
db.Model(&User{}).Where("id = ?", 1).Update("name", "Bob")

// 删除(无 WHERE 条件会被拒绝;带 DeletedAt 字段时自动软删除)
db.Delete(&User{}, 1)
db.Unscoped().Delete(&User{}, 1) // 强制物理删除

注意事项与已知限制

  • UPDATE / DELETE 执行了 WHERE 安全检查:缺少有效条件(包括仅有软删除条件)时返回 missing WHERE condition 错误
  • Oracle 仅支持单行 RETURNING:多行 UPDATE 不启用 RETURNING 回填;go-ora 不支持批量 INSERT + RETURNING,驱动采用逐行插入保证返回值正确
  • 创建表时若关联关系声明了 ON UPDATE CASCADE / SET NULL,驱动会自动生成同名触发器;删除表时需先删除依赖的表或使用 CASCADE CONSTRAINTS(已内置)
  • 11g 下通过序列 + 触发器模拟自增时,触发器和序列按 SEQ_<table> / TRG_<table> 命名,删除表会级联清理
  • 布尔值在写入时转换为 1/0,读取时转换回 Go bool

测试

tests/ 目录下为集成测试套件(创建、查询、更新、删除、软删除、Hook、迁移、序列、MERGE 等),需要真实的 Oracle 数据库:

ORACLE_DSN="oracle://user:password@host:1521/service" go test ./tests/...

驱动单元测试(无需数据库):

go test ./...

License

License

Documentation

Index

Constants

View Source
const (
	OracleVersion10 = 10 // Oracle 10g
	OracleVersion11 = 11 // Oracle 11g(不含 IDENTITY 列、OFFSET/FETCH 分页)
	OracleVersion12 = 12 // Oracle 12c(引入 IDENTITY 列、OFFSET/FETCH 分页;12.1 起支持 Extended 32k VARCHAR2)
	OracleVersion18 = 18 // Oracle 18c(12.2 的再版)
	OracleVersion19 = 19 // Oracle 19c
	OracleVersion21 = 21 // Oracle 21c(引入原生 BOOLEAN 列类型)
	OracleVersion23 = 23 // Oracle 23ai(引入 VECTOR 类型)
)

Oracle 版本主版本号常量(对应各版本引入的数据库特性)

View Source
const RowNumberAliasForOracle11 = "ROW_NUM"

Variables

View Source
var ReservedWordsList = []string{}/* 201 elements not displayed */

Functions

func ConvertNameToFormat

func ConvertNameToFormat(x string) string

func Create

func Create(db *gorm.DB)

func Delete

func Delete(db *gorm.DB)

func IsReservedWord

func IsReservedWord(v string) bool

func MapStringToInterface

func MapStringToInterface(slice []string) []any

辅助函数:将字符串切片转换为接口切片

func New

func New(config Config) gorm.Dialector

func Open

func Open(dsn string) gorm.Dialector

func Query

func Query(db *gorm.DB)

Query 是 Oracle 特定的查询回调函数 处理查询前后的数据转换和列名映射

func Update

func Update(db *gorm.DB)

Types

type Config

type Config struct {
	DriverName           string
	DSN                  string
	Conn                 gorm.ConnPool //*sql.DB
	DefaultStringSize    uint
	DBName               string
	DBVer                string
	DriverType           driver_adapter.DriverType // 新增:驱动类型(go-ora 或 godror)
	SkipQuoteIdentifiers bool                      // 新增:是否跳过标识符引用
}

type Dialector

type Dialector struct {
	*Config
}

func (Dialector) BindVarTo

func (d Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v any)

func (Dialector) ClauseBuilders

func (d Dialector) ClauseBuilders() map[string]clause.ClauseBuilder

func (Dialector) DataTypeOf

func (d Dialector) DataTypeOf(field *schema.Field) string

func (Dialector) DefaultValueOf

func (d Dialector) DefaultValueOf(*schema.Field) clause.Expression

func (Dialector) DummyTableName

func (d Dialector) DummyTableName() string

func (Dialector) Explain

func (d Dialector) Explain(sql string, vars ...any) string

func (Dialector) GetAdapter

func (d Dialector) GetAdapter() driver_adapter.Adapter

func (Dialector) Initialize

func (d Dialector) Initialize(db *gorm.DB) (err error)

func (Dialector) Migrator

func (d Dialector) Migrator(db *gorm.DB) gorm.Migrator

func (Dialector) Name

func (d Dialector) Name() string

func (Dialector) QuoteTo

func (d Dialector) QuoteTo(writer clause.Writer, str string)

func (Dialector) RewriteLimit

func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder)

func (Dialector) RewriteLimit11

func (d Dialector) RewriteLimit11(c clause.Clause, builder clause.Builder)

Oracle11 Limit

func (Dialector) RollbackTo

func (d Dialector) RollbackTo(tx *gorm.DB, name string) error

func (Dialector) SavePoint

func (d Dialector) SavePoint(tx *gorm.DB, name string) error

type Migrator

type Migrator struct {
	migrator.Migrator
}

func (Migrator) AddColumn

func (m Migrator) AddColumn(value any, field string) error

func (Migrator) AlterColumn

func (m Migrator) AlterColumn(value any, field string) error

func (Migrator) AlterDataTypeOf

func (m Migrator) AlterDataTypeOf(stmt *gorm.Statement, field *schema.Field) (expr clause.Expr)

func (Migrator) ColumnTypes

func (m Migrator) ColumnTypes(value any) ([]gorm.ColumnType, error)

ColumnTypes return columnTypes []gorm.ColumnType and execErr error

func (Migrator) CreateConstraint

func (m Migrator) CreateConstraint(value any, name string) error

func (Migrator) CreateOnUpdateTrigger

func (m Migrator) CreateOnUpdateTrigger(value any, rel *schema.Relationship) error

CreateOnUpdateTrigger 创建 ON UPDATE 触发器 Oracle 不支持原生的 ON UPDATE 外键操作,需要通过触发器模拟

func (Migrator) CreateTable

func (m Migrator) CreateTable(values ...any) error

func (Migrator) CurrentDatabase

func (m Migrator) CurrentDatabase() (name string)

func (Migrator) DropColumn

func (m Migrator) DropColumn(value any, name string) error

func (Migrator) DropConstraint

func (m Migrator) DropConstraint(value any, name string) error

func (Migrator) DropIndex

func (m Migrator) DropIndex(value any, name string) error

func (Migrator) DropOnUpdateTrigger

func (m Migrator) DropOnUpdateTrigger(value any, rel *schema.Relationship) error

DropOnUpdateTrigger 删除 ON UPDATE 触发器

func (Migrator) DropTable

func (m Migrator) DropTable(values ...any) error

func (Migrator) FullDataTypeOf

func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr)

FullDataTypeOf 返回字段的完整数据库类型(版本感知的默认值处理)。 GORM 标准实现会把 DefaultValue 直接拼成 "DEFAULT xxx",对 11g 下引用序列的 NEXTVAL 默认值会生成非法 SQL(ORA-00984),因此在此重写: 11g 下 NEXTVAL 默认值不生成 DEFAULT 子句,改由 CreateTable 流程在建表后 创建 BEFORE INSERT 触发器实现等价语义(见 createSequenceDefaultTrigger)。

func (Migrator) HasColumn

func (m Migrator) HasColumn(value any, field string) bool

func (Migrator) HasConstraint

func (m Migrator) HasConstraint(value any, name string) bool

func (Migrator) HasIndex

func (m Migrator) HasIndex(value any, name string) bool

func (Migrator) HasTable

func (m Migrator) HasTable(value any) bool

func (Migrator) RenameIndex

func (m Migrator) RenameIndex(value any, oldName, newName string) error

https://docs.oracle.com/database/121/SPATL/alter-index-rename.htm

func (Migrator) RenameTable

func (m Migrator) RenameTable(oldName, newName any) (err error)

func (Migrator) TryRemoveOnUpdate

func (m Migrator) TryRemoveOnUpdate(values ...any) error

type Namer

type Namer struct {
	NamingStrategy schema.Namer
	DBName         string
}

func (Namer) CheckerName

func (n Namer) CheckerName(table, column string) (name string)

func (Namer) ColumnName

func (n Namer) ColumnName(table, column string) (name string)

func (Namer) IndexName

func (n Namer) IndexName(table, column string) (name string)

func (Namer) JoinTableName

func (n Namer) JoinTableName(table string) (name string)

func (Namer) RelationshipFKName

func (n Namer) RelationshipFKName(relationship schema.Relationship) (name string)

func (Namer) SchemaName

func (n Namer) SchemaName(table string) string

func (Namer) TableName

func (n Namer) TableName(table string) (name string)

func (Namer) UniqueName

func (n Namer) UniqueName(table, column string) string

Directories

Path Synopsis
Package driver_adapter 提供 Oracle 驱动抽象层 支持 go-ora 和 godror 两种底层驱动的切换
Package driver_adapter 提供 Oracle 驱动抽象层 支持 go-ora 和 godror 两种底层驱动的切换

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL