feat: oracle支持服务名、数据库执行超时时间配置等

This commit is contained in:
meilin.huang
2024-03-07 17:26:11 +08:00
parent 986b187f0a
commit 8589105e44
21 changed files with 110 additions and 41 deletions

View File

@@ -15,12 +15,12 @@ require (
github.com/go-playground/universal-translator v0.18.1
github.com/go-playground/validator/v10 v10.14.0
github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v5 v5.2.0
github.com/google/uuid v1.3.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.1
github.com/kanzihuang/vitess/go/vt/sqlparser v0.0.0-20231018071450-ac8d9f0167e9
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20230712084735-068dc2aee82d
github.com/microsoft/go-mssqldb v1.6.0
github.com/microsoft/go-mssqldb v1.7.0
github.com/mojocn/base64Captcha v1.3.6 //
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6
@@ -30,7 +30,7 @@ require (
github.com/sijms/go-ora/v2 v2.8.9
github.com/stretchr/testify v1.8.4
go.mongodb.org/mongo-driver v1.14.0 // mongo
golang.org/x/crypto v0.20.0 // ssh
golang.org/x/crypto v0.21.0 // ssh
golang.org/x/oauth2 v0.17.0
golang.org/x/sync v0.6.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
@@ -87,7 +87,7 @@ require (
golang.org/x/exp v0.0.0-20230519143937-03e91628a987 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619 // indirect

View File

@@ -9,6 +9,7 @@ import (
"mayfly-go/internal/db/api/form"
"mayfly-go/internal/db/api/vo"
"mayfly-go/internal/db/application"
"mayfly-go/internal/db/config"
"mayfly-go/internal/db/dbm/dbi"
"mayfly-go/internal/db/domain/entity"
msgapp "mayfly-go/internal/msg/application"
@@ -113,7 +114,7 @@ func (d *Db) ExecSql(rc *req.Ctx) {
}
// 比前端超时时间稍微快一点,可以提示到前端
ctx, cancel := context.WithTimeout(rc.MetaCtx, 58*time.Second)
ctx, cancel := context.WithTimeout(rc.MetaCtx, time.Duration(config.GetDbms().SqlExecTl)*time.Second)
defer cancel()
sqls, err := sqlparser.SplitStatementToPieces(sql, sqlparser.WithDialect(dbConn.Info.Type.Dialect()))

View File

@@ -6,7 +6,7 @@ type InstanceForm struct {
Type string `binding:"required" json:"type"` // 类型mysql oracle等
Host string `binding:"required" json:"host"`
Port int `json:"port"`
Sid string `json:"sid"`
Extra string `json:"extra"`
Username string `json:"username"`
Password string `json:"password"`
Params string `json:"params"`

View File

@@ -8,8 +8,8 @@ type InstanceListVO struct {
Host *string `json:"host"`
Port *int `json:"port"`
Type *string `json:"type"`
Params *string `json:"params"`
Sid *string `json:"sid"`
Params string `json:"params"`
Extra string `json:"extra"`
Username *string `json:"username"`
Remark *string `json:"remark"`
CreateTime *time.Time `json:"createTime"`

View File

@@ -199,7 +199,6 @@ func (d *dbAppImpl) GetDbConnByInstanceId(instanceId uint64) (*dbi.DbConn, error
func toDbInfo(instance *entity.DbInstance, dbId uint64, database string, tagPath ...string) *dbi.DbInfo {
di := new(dbi.DbInfo)
di.InstanceId = instance.Id
di.Sid = instance.Sid
di.Id = dbId
di.Database = database
di.TagPath = tagPath

View File

@@ -95,7 +95,7 @@ func (d *dbSqlExecAppImpl) Exec(ctx context.Context, execSqlReq *DbSqlExecReq) (
isSelect := strings.HasPrefix(lowerSql, "select")
if isSelect {
// 如果配置为0则不校验分页参数
maxCount := config.GetDbQueryMaxCount()
maxCount := config.GetDbms().MaxResultSet
if maxCount != 0 {
if !strings.Contains(lowerSql, "limit") &&
// 兼容oracle rownum分页
@@ -207,7 +207,8 @@ func (d *dbSqlExecAppImpl) saveSqlExecLog(isQuery bool, dbSqlExecRecord *entity.
d.dbSqlExecRepo.Insert(context.TODO(), dbSqlExecRecord)
return
}
if config.GetDbSaveQuerySql() {
if config.GetDbms().QuerySqlSave {
dbSqlExecRecord.Table = "-"
dbSqlExecRecord.OldValue = "-"
dbSqlExecRecord.Type = entity.DbSqlExecTypeQuery
@@ -220,7 +221,7 @@ func (d *dbSqlExecAppImpl) doSelect(ctx context.Context, selectStmt *sqlparser.S
if selectExprsStr == "*" || strings.Contains(selectExprsStr, ".*") ||
len(strings.Split(selectExprsStr, ",")) > 1 {
// 如果配置为0则不校验分页参数
maxCount := config.GetDbQueryMaxCount()
maxCount := config.GetDbms().MaxResultSet
// 哪些数据库跳过校验
skipped := dbi.DbTypeOracle == execSqlReq.DbConn.Info.Type || dbi.DbTypeMssql == execSqlReq.DbConn.Info.Type
if maxCount != 0 && !skipped {

View File

@@ -2,26 +2,33 @@ package config
import (
sysapp "mayfly-go/internal/sys/application"
"mayfly-go/pkg/utils/conv"
"path/filepath"
"runtime"
)
const (
ConfigKeyDbSaveQuerySQL string = "DbSaveQuerySQL" // 数据库是否记录查询相关sql
ConfigKeyDbQueryMaxCount string = "DbQueryMaxCount" // 数据库查询的最大数量
ConfigKeyDbms string = "DbmsConfig" // dbms相关配置信息
ConfigKeyDbBackupRestore string = "DbBackupRestore" // 数据库备份
ConfigKeyDbMysqlBin string = "MysqlBin" // mysql可执行文件配置
ConfigKeyDbMariadbBin string = "MariadbBin" // mariadb可执行文件配置
)
// 获取数据库最大查询数量配置
func GetDbQueryMaxCount() int {
return sysapp.GetConfigApp().GetConfig(ConfigKeyDbQueryMaxCount).IntValue(200)
type Dbms struct {
QuerySqlSave bool // 是否记录查询类sql
MaxResultSet int // 允许sql查询的最大结果集数。注: 0=不限制
SqlExecTl int // sql执行时间限制超过该时间单位执行将被取消
}
// 获取数据库是否记录查询相关sql配置
func GetDbSaveQuerySql() bool {
return sysapp.GetConfigApp().GetConfig(ConfigKeyDbSaveQuerySQL).BoolValue(false)
func GetDbms() *Dbms {
c := sysapp.GetConfigApp().GetConfig(ConfigKeyDbms)
jm := c.GetJsonMap()
dbmsConf := new(Dbms)
dbmsConf.QuerySqlSave = c.ConvBool(jm["querySqlSave"], false)
dbmsConf.MaxResultSet = conv.Str2Int(jm["maxResultSet"], 0)
dbmsConf.SqlExecTl = conv.Str2Int(jm["sqlExecTl"], 60)
return dbmsConf
}
type DbBackupRestore struct {

View File

@@ -16,7 +16,7 @@ type DbInfo struct {
Type DbType // 类型mysql postgres等
Host string
Port int
Sid string // oracle数据库需要指定sid
Extra string // 连接需要的其他额外参数json字符串oracle数据库需要指定sid
Network string
Username string
Password string

View File

@@ -4,6 +4,8 @@ import (
"database/sql"
"fmt"
"mayfly-go/internal/db/dbm/dbi"
"mayfly-go/pkg/utils/anyx"
"mayfly-go/pkg/utils/jsonx"
"strings"
go_ora "github.com/sijms/go-ora/v2"
@@ -17,12 +19,11 @@ type OraMeta struct {
}
func (md *OraMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
driverName := "oracle"
err := d.IfUseSshTunnelChangeIpPort()
if err != nil {
return nil, err
}
// 参数参考 https://github.com/sijms/go-ora?tab=readme-ov-file#other-connection-options
urlOptions := make(map[string]string)
@@ -50,9 +51,20 @@ func (md *OraMeta) GetSqlDb(d *dbi.DbInfo) (*sql.DB, error) {
}
}
}
// 从extra获取sid或serviceName
serviceName := ""
if d.Extra != "" {
extraMap := jsonx.ToMap(d.Extra)
serviceName = anyx.ConvString(extraMap["serviceName"])
if sid := anyx.ConvString(extraMap["sid"]); sid != "" {
urlOptions["SID"] = sid
}
}
urlOptions["TIMEOUT"] = "1000"
connStr := go_ora.BuildUrl(d.Host, d.Port, d.Sid, d.Username, d.Password, urlOptions)
conn, err := sql.Open(driverName, connStr)
connStr := go_ora.BuildUrl(d.Host, d.Port, serviceName, d.Username, d.Password, urlOptions)
conn, err := sql.Open("oracle", connStr)
if err != nil {
return nil, err
}

View File

@@ -15,7 +15,7 @@ type DbInstance struct {
Host string `json:"host"`
Port int `json:"port"`
Network string `json:"network"`
Sid string `json:"sid"`
Extra *string `json:"extra"` // 连接需要的其他额外参数json格式, 如oracle需要sid等
Username string `json:"username"`
Password string `json:"-"`
Params *string `json:"params"`

View File

@@ -18,7 +18,7 @@ func newConfigRepo() repository.Config {
func (m *configRepoImpl) GetPageList(condition *entity.Config, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
qd := gormx.NewQuery(condition).
Eq("key", condition.Key).
Like("`key`", condition.Key).
And("permission = 'all' OR permission LIKE ?", "%"+condition.Permission+",%").
WithOrderBy(orderBy...)
return gormx.PageQuery(qd, pageParam, toEntity)

View File

@@ -88,7 +88,7 @@ func (wf *wrapperF) QueryIntDefault(qm string, defaultInt int) int {
// 获取分页参数
func (wf *wrapperF) GetPageParam() *model.PageParam {
return &model.PageParam{PageNum: wf.QueryIntDefault("pageNum", 1), PageSize: wf.QueryIntDefault("pageSize", 10)}
return &model.PageParam{PageNum: wf.QueryIntDefault("pageNum", 1), PageSize: wf.QueryIntDefault("pageSize", 100)}
}
// 获取路径参数

View File

@@ -6,5 +6,5 @@
服务启动&重启:./startup.sh
服务关闭:./shutdown.sh
直接通过 host:ip即可访问项目
直接通过 host:config.yml里配置的端口 即可访问项目
初始账号 admin/admin123.

View File

@@ -0,0 +1,9 @@
DELETE
FROM `t_sys_config`
WHERE `key` in ('DbQueryMaxCount', 'DbSaveQuerySQL');
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('DBMS配置', 'DbmsConfig', '[{"model":"querySqlSave","name":"记录查询sql","placeholder":"是否记录查询类sql","options":"true,false"},{"model":"maxResultSet","name":"最大结果集","placeholder":"允许sql查询的最大结果集数。注: 0=不限制","options":""},{"model":"sqlExecTl","name":"sql执行时间限制","placeholder":"超过该时间(单位:秒),执行将被取消"}]', '{"querySqlSave":"false","maxResultSet":"0","sqlExecTl":"60"}', 'DBMS相关配置', 'admin,', '2024-03-06 13:30:51', 1, 'admin', '2024-03-06 14:07:16', 1, 'admin', 0, NULL);
ALTER TABLE t_db_instance CHANGE sid extra varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '连接需要的额外参数如oracle数据库需要sid等';
ALTER TABLE t_db_instance MODIFY COLUMN extra varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '连接需要的额外参数如oracle数据库需要sid等';