docs: 重写 README 匹配完整化后的驱动

This commit is contained in:
2026-08-08 10:44:39 +08:00
parent 9154afab6b
commit 83fbcd99f7
+152 -21
View File
@@ -1,40 +1,171 @@
# GORM Oracle Driver # GORM Oracle Driver
基于 [go-ora](https://github.com/sijms/go-ora) 实现的 GORM Oracle 数据库驱动,内置**版本感知**能力、**驱动抽象层**go-ora / godror 可切换)、自定义回调体系(INSERT/UPDATE/DELETE/QUERY)与完整测试套件。
## Description ## 特性
GORM Oracle driver for connect Oracle DB and Manage Oracle DB, Based on [CengSin/oracle](https://github.com/CengSin/oracle) - **版本感知**:自动识别 Oracle 数据库版本,按版本适配 SQL 语法与类型
not recommended for use in a production environment - 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 CONFLICT``MERGE 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 保留字自动加引号
- 命名策略统一转换为大写
## Required dependency Install ## 环境要求
- Oracle 12C+ - Oracle 11g、12c 及以上(支持 21c、23ai 等新版本)
- Oracle 11g - Golang 1.22+
- Golang 1.13+ - GORM v1.31.2+
- see [ODPI-C Installation.](https://oracle.github.io/odpi/doc/installation.html) - 底层驱动默认使用 [go-ora v2](https://github.com/sijms/go-ora)(纯 Go 实现,**无需**安装 [ODPI-C](https://oracle.github.io/odpi/doc/installation.html)
- gorm 1.24.0+
## 安装
## Quick Start
### how to install
```bash ```bash
go get github.com/dzwvip/oracle go get git.charlienet.top/go/oracle
``` ```
### usage
## 快速开始
```go ```go
import ( import (
"fmt" "gorm.io/gorm"
"github.com/dzwvip/oracle"
"gorm.io/gorm" oracle "git.charlienet.top/go/oracle"
"log"
) )
func main() { func main() {
db, err := gorm.Open(oracle.Open("system/oracle@127.0.0.1:1521/XE"), &gorm.Config{}) dsn := "oracle://user:password@127.0.0.1:1521/XE?SSL=false"
db, err := gorm.Open(oracle.Open(dsn), &gorm.Config{})
if err != nil { if err != nil {
// panic error or log error info panic(err)
} }
// do something...
// do somethings
} }
``` ```
### 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{})` 可获得更多配置能力:
```go
import (
"gorm.io/gorm"
oracle "git.charlienet.top/go/oracle"
"git.charlienet.top/go/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.go``go: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` 自动探测,无需手动配置。
## 常用操作示例
```go
// 创建(自动回填自增主键/默认值字段)
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 数据库:
```bash
ORACLE_DSN="oracle://user:password@host:1521/service" go test ./tests/...
```
驱动单元测试(无需数据库):
```bash
go test ./...
```
## License
见 [License](License)。