docs: 重写 README 匹配完整化后的驱动
This commit is contained in:
@@ -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)。
|
||||||
|
|||||||
Reference in New Issue
Block a user