此客户端不依赖oracle库文件,但是只能在linux上编译,windows上gcc环境无法适配
package main
import (
"database/sql"
"flag"
"fmt"
"log"
"strings"
"syscall"
_ "github.com/sijms/go-ora/v2"
"golang.org/x/crypto/ssh/terminal"
)
// 全局变量定义
var (
username = flag.String("u", "", "数据库用户名")
password = flag.String("p", "", "数据库密码")
dsn = flag.String("dsn", "", "Oracle DSN (数据源名称) 例如 192.168.1.100:1521/orcl")
execSQL = flag.String("e", "select * from dual", "要执行的 SQL 语句")
)
// 初始化数据库连接
func initDB() (*sql.DB, error) {
// 构建连接字符串
connString := fmt.Sprintf("oracle://%s:%s@%s", *username, *password, *dsn)
db, err := sql.Open("oracle", connString)
if err != nil {
return nil, err
}
// 测试数据库连接
if err := db.Ping(); err != nil {
return nil, err
}
return db, nil
}
// 查询数据库并格式化输出
func queryDB(db *sql.DB, query string) {
// 执行查询语句
rows, err := db.Query(query)
if err != nil {
log.Fatalf("查询失败: %v", err)
}
defer rows.Close()
// 获取列名
cols, err := rows.Columns()
if err != nil {
log.Fatalf("获取列名失败: %v", err)
}
// 创建一个接收列值的切片
values := make([]sql.RawBytes, len(cols))
scanArgs := make([]interface{}, len(cols))
for i := range values {
scanArgs[i] = &values[i]
}
// 用来存储每列的最大宽度
maxWidths := make([]int, len(cols))
for i, col := range cols {
maxWidths[i] = len(col) // 初始化为列名的长度
}
// 存储每行的数据,用于最后的输出
var results [][]string
// 读取数据行
for rows.Next() {
if err := rows.Scan(scanArgs...); err != nil {
log.Fatalf("扫描行数据失败: %v", err)
}
rowStrings := make([]string, len(cols))
for i, val := range values {
strVal := string(val)
rowStrings[i] = strVal
// 更新列的最大宽度
if len(strVal) > maxWidths[i] {
maxWidths[i] = len(strVal)
}
}
results = append(results, rowStrings)
}
if err := rows.Err(); err != nil {
log.Fatalf("读取行数据失败: %v", err)
}
// 打印列名
for i, col := range cols {
fmt.Printf("%-*s ", maxWidths[i], col)
}
fmt.Println()
// 打印所有行
for _, rowStrings := range results {
for i, val := range rowStrings {
fmt.Printf("%-*s ", maxWidths[i], val)
}
fmt.Println()
}
}
// 执行数据库命令(增、删、改)
func execDB(db *sql.DB, query string) {
// 执行 SQL 语句
result, err := db.Exec(query)
if err != nil {
log.Fatalf("执行失败: %v", err)
}
// 获取受影响的行数
rowsAffected, err := result.RowsAffected()
if err != nil {
log.Fatalf("获取受影响的行数失败: %v", err)
}
fmt.Printf("操作成功! 受影响的行数: %d\n", rowsAffected)
}
// 交互输入密码
func promptPassword() string {
fmt.Print("Enter Password: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
log.Fatalf("Error reading password: %v", err)
}
fmt.Println() // 读完密码后换行
return string(bytePassword)
}
func main() {
flag.Parse()
// 检查是否缺少必要的参数
if *username == "" || *dsn == "" {
fmt.Println("缺少必要的参数.")
flag.Usage()
return
}
// 如果没有通过参数提供密码,则交互式输入密码
if *password == "" {
*password = promptPassword()
}
// 初始化数据库连接
db, err := initDB()
if err != nil {
log.Fatalf("数据库初始化失败: %v", err)
}
defer db.Close()
// 判断 SQL 语句类型,并调用相应的函数
if strings.HasPrefix(strings.ToLower(*execSQL), "select") || strings.HasPrefix(strings.ToLower(*execSQL), "with") {
queryDB(db, *execSQL)
} else {
execDB(db, *execSQL)
}
}
// 初始化函数定义帮助信息
func init() {
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", flag.CommandLine.Name())
flag.PrintDefaults()
}
}
输出示例:
./gooracli -u scott -p tiger -dsn 192.168.1.100:1521/orcl -e "select * from emp"
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7902 FORD ANALYST 7566 1981-12-03T00:00:00+08:00 3000 20
7369 SMITH CLERK 7902 1980-12-17T00:00:00+08:00 800 20
7499 ALLEN SALESMAN 7698 1981-02-20T00:00:00+08:00 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22T00:00:00+08:00 1250 500 30
7566 JONES MANAGER 7839 1981-04-02T00:00:00+08:00 2975 20
7654 MARTIN SALESMAN 7698 1981-09-28T00:00:00+08:00 1250 1400 30
7698 BLAKE MANAGER 7839 1981-05-01T00:00:00+08:00 2850 30
7782 CLARK MANAGER 7839 1981-06-09T00:00:00+08:00 2450 10
7788 SCOTT ANALYST 7566 1987-04-19T00:00:00+08:00 3000 20
7839 KING PRESIDENT 1981-11-17T00:00:00+08:00 5000 10
7844 TURNER SALESMAN 7698 1981-09-08T00:00:00+08:00 1500 0 30
7876 ADAMS CLERK 7788 1987-05-23T00:00:00+08:00 1100 20
7900 JAMES1 CLERK 7698 1981-12-03T00:00:00+08:00 950 30
7934 MILLER CLERK 7782 1982-01-23T00:00:00+08:00 1300 10
./gooracli -u scott -p tiger -dsn 192.168.1.100:1521/orcl -e "update emp set ename='JAMES1' where EMPNO=7900"
操作成功! 受影响的行数: 1
./gooracli -u scott -p tiger -dsn 192.168.1.100:1521/orcl -e "insert into emp(EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) values (7902, 'FORD', 'ANALYST', 7566, to_date('03-12-1981', 'dd-mm-yyyy'), 3000.00, null, 20)"
操作成功! 受影响的行数: 1
./gooracli -u scott -p tiger -dsn 192.168.1.100:1521/orcl -e "delete from emp where EMPNO=7902"
操作成功! 受影响的行数: 0
./gooracli -u scott -dsn 192.168.1.100:1521/orcl
Enter Password:
DUMMY
X
「欢迎关注我们的公众号,获取更多技术分享与经验交流。」
文章转载自数据库驾驶舱,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




