GithubHelp home page GithubHelp logo

gohouse / gorose Goto Github PK

View Code? Open in Web Editor NEW
1.1K 48.0 126.0 14.71 MB

GoRose(go orm), a mini database ORM for golang, which inspired by the famous php framwork laravle's eloquent. It will be friendly for php developer and python or ruby developer. Currently provides six major database drivers: mysql,sqlite3,postgres,oracle,mssql, Clickhouse.

License: MIT License

Go 100.00%
go orm eloquent laravel golang db database php databases gorose

gorose's Introduction

GoRose ORM V3

PHP Laravel ORM 的 go 实现, 与 laravel 官方文档保持一致 https://laravel.com/docs/10.x/queries .
分为 go 风格 (struct 结构绑定用法) 和 php 风格 (map 结构用法).
php 风格用法, 完全可以使用 laravel query builder 的文档做参考, 尽量做到 1:1 还原.

安装

目前还处于beta阶段, 请谨慎使用. 由于没有打 tag, 只能使用 go mod 的方式引入

# go.mod

require github.com/gohouse/gorose/v3 master

概览

go风格用法

package main

import (
    gorose "github.com/gohouse/gorose/v3"
    // 引入mysql驱动
    _ "github.com/go-sql-driver/mysql"
)

type User struct {
	Id    int64  `db:"id,pk"`   // 这里的 pk 是指主键
	Name  string `db:"name"`
	Email string `db:"email"`
    
    // 定义表名字,等同于 func (User) TableName() string {return "users"}, 二选一即可
	// TableName string `db:"users" json:"-"` 
}
func (User) TableName() string {
    return "users"
}

var rose = gorose.Open("mysql", "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true")

func db() *gorose.Database {
	return rose.NewDatabase()
}
func main() {
    // select id,name,email from users limit 1;
    var user User
    db().To(&user)

    // insert into users (name,email) values ("test","[email protected]");
    var user = User{Name: "test", Email: "[email protected]"}}
    db().Insert(&user)

    // update users set name="test2" where id=1;
    var user = User{Id: 1, Name: "test2"}
    db().Update(&user)

    // delete from users where id=1;
    var user = User{Id: 1}
    db().Delete(&user) 
}

php风格用法 和 go风格用法对比

// select id,name,email from users where id=1 and name="test"
db().Table("users").
    Select("id","name","email").
    Where("id", "=", 1).Where("name", "test").
    First()
// 等同于
var user = User{Id: 1, Name: "test"}
db().To(&user)

由此可以看出, 除了对 表 模型的绑定区别, 其他方法通用

配置

单数据库连接, 可以直接同官方接口一样用法

var rose = gorose.Open("mysql", "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true")

也可以用

var conf1 = gorose.Config{
    Driver:          "mysql",
    DSN:             "root:123456@tcp(localhost:3306)/test?charset=utf8mb4&parseTime=true",
    Prefix:          "tb_",
    Weight:          0,
    MaxIdleConns:    0,
    MaxOpenConns:    0,
    ConnMaxLifetime: 0,
    ConnMaxIdleTime: 0,
}
var rose = gorose.Open(conf)

或者使用读写分离集群,事务内,自动强制从写库读数据

var rose = gorose.Open(
    gorose.ConfigCluster{
        WriteConf: []gorose.Config{
            conf1,
            conf2,
        },
        ReadConf: []gorose.Config{
            conf3,
            conf4,
        }
    },
)

事务

// 全自动事务, 有错误会自动回滚, 无错误会自动提交
// Transaction 方法可以接收多个操作, 同用一个 tx, 方便在不同方法内处理同一个事务
db().Transaction(func(tx gorose.TxHandler) error {
    tx().Insert(&user)
    tx().Update(&user)
    tx().To(&user)
}

// 手动事务
tx = db().Begin()
tx().Insert(&user)
tx().Update(&user)
tx().To(&user)
tx().Rollback()
tx().Commit()

// 全自动嵌套事务
db().Transaction(func(tx gorose.TxHandler) error {
    tx().Insert(&user)
    ...
    // 自动子事务
    tx().Transaction(func(tx2 gorose.TxHandler) error {
        tx2().Update(&user)
        ...
    }
}

// 手动嵌套事务
var tx = db().Begin()
// 自动子事务
tx().Begin() // 自动 savepoint 子事务
...
tx().Rollback()   // 自动回滚到上一个 savepoint
...
// 手动子事务
tx().SavePoint("savepoint1")    // 手动 savepoint 到 savepoint1(自定义名字)
...
tx().RollbackTo("savepoint1") // 手动回滚到自定义的 savepoint
tx().Commit()

update

在插入和更新数据时,如果使用 struct 模型作为数据对象的时候, 默认忽略类型零值,如果想强制写入,则可以从第二个参数开始传入需要强制写入的字段即可,如:

var user = User{Id: 1, Name: "test"}
// 这里不会对 sex 做任何操作, 
//update user set name="test" where id=1
db().Update(&user)
// 这里会强制将sex更改为0
//update user set name="test", sex=0 where id=1
db().Update(&user, "sex")
// 等同于
db().Table(&user).Where("id", 1).Update(map[string]any{"name": "test", "sex": 0}))

如果没有where条件,则会自动添加tag中指定了pk的字段作为条件,如: db:"id,pk", 因为指定了 pk,如果 id 的值不为0值, 则 id 会作为主键条件更新

insert

参考 update

delete

var user = User{Id: 1}
db().Delete(&user)
// 等同于
db().Table(&user).Where("id", 1).Delete()
// 要加上字段0值条件,只需要传入第二个字段,如:
// delete from users where id=1 and sex=0 and name=""
db().Delete(&user, "sex", "name")

table

  • 参数
    table 参数, 可以是字符串, 也可以是 User 结构体
db().Table(User{})
db().Table("users")
  • 取别名
db().Table(User{}, "u")
db().Table("users", "u")
  • 结果集查询
sub := db().Table("users").Select("id", "name")
db().Table(sub).Where("id", ">", 1).Get()

join

type UserInfo struct {
    UserId      int64   `db:"user_id"`
    TableName   string  `db:"user_info"`
}
  • 简单用法
db().Table("users").Join(UserInfo{}, "user.id", "=", "user_info.user_id").Get()
  • 取别名
// select * from users a inner join user_info b on a.id=b.user_id
db().Table("users", "u").Join(gorose.As(UserInfo{}, "b"), "u.id", "=", "b.user_id").Get()
// 等同于
db().Table(User{}, "u").Join(gorose.As("user_info", "b"), "u.id", "=", "b.user_id").Get()

gorose.As(UserInfo{}, "b") 中, user_info 取别名 b

  • 复杂用法
db().Table("users").Join(UserInfo{}, func(wh builder.IJoinOn) {
    wh.On("a.id", "b.user_id").OrOn("a.sex", "b.sex")
}).Get()
// 等同于
db().Table("users").JoinOn(UserInfo{}, func(wh builder.IJoinOn) {
    wh.On("a.id", "b.user_id").OrOn("a.sex", "b.sex")
}).Get()

Join的第二个参数为builder.IJoinOn时,等同于JoinOn用法(第二个参数有强类型提醒,方便ide快捷提示)

where sub

// where id in (select user_id from user_info)
sub := db().Table("user_info").Select("user_id")
db().Table(User{}).Where("id", "in", sub).Get()
  • where sub query
// where id in (select user_id from user_info)
db().Table(User{}).WhereSub("id", "in", func(tx *builder.Context) {
    tx.Table("user_info").Select("user_id")
}).Get()
  • where sub builder
// where id in (select user_id from user_info)
sub := db().Table("user_info").Select("user_id")
db().Table(User{}).WhereBuilder("id", "in", sub).Get()

以上3种用法等同

where nested

// where id>1 and (sex=1 or sex=2)
db().Table(User{}).Where("id",">", 1).Where(func(wh builder.IWhere) {
    wh.Where("sex", 1).OrWhere("sex", 2)
})
// where id>1 and (sex=1 or sex=2)
db().Table(User{}).Where("id",">", 1).WhereNested(func(wh builder.IWhere) {
    wh.Where("sex", 1).OrWhere("sex", 2)
})

以上两种用法等同

子查询

Table,Where,Join内都可以用子查询

sub := db().Table("user").Where().OrWhere()
sub2 := db().Table("address").Select("user_id").Where().OrWhere()
sub3 := db().Table("user_info").Select("user_id").Where().OrWhere()

用在 Table,Where,Join 内

db().
    Table(sub, "a").
    Join(gorose.As(sub2, "b"), "a.id", "=", "b.user_id")).
    WhereIn("a.id", sub3).
    Get()

用在 Union,UnionAll 内

db().
    Table("users").
    Union(sub).
    Get()
var sub2222 = db().Table("user").Where().OrWhere()
var to []User
db().
    Table("users").
    UnionAll(sub, sub2222).
    To(&to)

Pluck

返回两列数据到一个map中,第一列为value,第二列为key

// select id,name from users
db().Table("users").Pluck("name", "id")
// 返回 map[<id>]<name>, 实际得到 map[int64]string{1: "张三", 2: "李四"}

List

返回一列数据到一个数组中

// select id,name from users
db().Table("users").List("id")
// 返回 []<id>, 实际得到 []int64{1,2,3}

To 查询结果绑定到对象

使用结构体字段作为 select 字段
使用结构体字段值作为 where 条件
查询结果绑定到结构体,支持一条或多条

// 查询一条数据
var user User
db().To(&user)

// 查询条件,一条数据
// select id,name,email from users where id=1
var user = User{Id: 1}
db().To(&user)

// 查询多条数据
var users []User
db().To(&users)

// 查询条件,多条数据
var users []User
db().Where("id", ">", 1).To(&users)

Bind 查询结果绑定到对象

仅仅用作查询结果的绑定
结构体字段,不作为查询字段和条件
常用作join或者手动指定字段查询绑定

type Result struct {
    Id    int64  `db:"id"`
    Aname string `db:"aname"`
    Bname string `db:"bname"`
}
var res Result
// select a.id, a.name aname, b.name bname from a inner join b on a.id=b.id where a.id>1
db().Table("a").Join("b", "a.id","b.aid").Select("a.id", "a.name aname","b.name bname").Where("a.id", ">", 1).Bind(&res)

查询字段的显示名字一定要跟 结构体的字段 tag(db) 名字相同, 否则不会被赋值
字段数量可以不一样

ListTo,PluckTo,ValueTo

var list []int
db().Table("users").ListTo("age", &list)
var pluck map[int64]string
db().Table("users").PluckTo("name","id", &pluck)
var value int
db().Table("users").ValueTo("age", &value)

SumTo,MaxTo,MinTo

var sum int
db().Table("users").SumTo("age", &sum)
var max int
db().Table("users").MaxTo("age", &max)
var min int
db().Table("users").MinTo("age", &min)

日志

默认采用 官方库的 slog debug level, 如果不想显示sql日志, 只需要设置slog的level到debug以上即可, 如: Info, Warn, Error

驱动

只要实现了 gorose/driver.IDriver 接口即可,理论上可以支持任意数据库, 目前实现了mysql的支持, 可以开发更多接口的支持

数据库字段为null的处理

type User struct {
    Id  int64  `db:"id,pk"`
    Sex *int8  `db:"sex"` // 使用指针可以绑定 null 值
    Age sql.NullInt64 `db:"age"` // 使用sql.NullInt64 可以绑定 null 值
}

指针赋值

var sex = int8(1)
var user = User{Id: 1, Sex: &sex}
// 或者,快捷用法
var user = User{Id: 1, Sex: gorose.Ptr(int8(1))}

sql.Null* 赋值

var age = sql.NullInt64{Int64: 18, Valid: true}

sql.Null* 使用

if age.Valid {
    fmt.Println(age.Int64)
}

由此可见,null处理起来还是有点麻烦,所以,建议在设计表的时候,不要允许null即可,给定默认值,而大部分默认值刚好可以与go的类型零值对应

已经支持的 laravel query builder 方法

  • Table

  • Select

  • SelectRaw

  • AddSelect

  • Join

  • GroupBy

  • Having

  • HavingRaw

  • OrHaving

  • OrHavingRaw

  • OrderBy

  • Limit

  • Offset

  • Where

  • WhereRaw

  • OrWhere

  • OrWhereRaw

  • WhereBetween

  • OrWhereBetween

  • WhereNotBetween

  • OrWhereNotBetween

  • WhereIn

  • OrWhereIn

  • WhereNotIn

  • OrWhereNotIn

  • WhereNull

  • OrWhereNull

  • WhereNotNull

  • OrWhereNotNull

  • WhereLike

  • OrWhereLike

  • WhereNotLike

  • OrWhereNotLike

  • WhereExists

  • WhereNotExists

  • WhereNot

  • Get

  • First

  • Find

  • Insert

  • Update

  • Delete

  • Max

  • Min

  • Sum

  • Avg

  • Count

  • InsertGetId

  • Upsert

  • InsertOrIgnore

  • Exists

  • DoesntExist

  • Pluck

  • List

  • Value

  • Increment

  • Decrement

  • IncrementEach

  • DecrementEach

  • Truncate

  • Union

  • UnionAll

  • SharedLock

  • LockForUpdate

额外增加的 api

  • Replace

  • Page

  • LastSql

  • WhereBuilder

  • OrWhereBuilder

  • WhereSub

  • OrWhereSub

  • WhereNested

  • OrWhereNested

  • To

  • Bind

  • ListTo

  • PluckTo

  • ValueTo

  • SumTo

  • MaxTo

  • UnionTo

  • UnionAllTo

gorose's People

Contributors

cloudwebrtc avatar dmskys avatar felix021 avatar fizzday avatar holdno avatar icefoxhz avatar imgbed avatar kkkkkkkkkkkkklllk avatar lazyneo avatar objcoding avatar wall-js avatar wuyumin avatar yangyuclub avatar yourenf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gorose's Issues

多条件查询无法使用

你好,我很喜欢gorose这个工具,但是我发现如果要用切片组合多个条件的时候,where无法使用,会报错,文档里面的例子也是有问题的,麻烦大佬能够指点12

Page和Count方法会进行配套是用,但其各自都会进行Reset操作

同一个connection中,再一次db.Table也没有帮助,看了代码,貌似是一个connection中,对象只创建一次,需要重新创建一个connection,才可以解决这个问题。
而Page和Count经常是配套使用的(原因很简单,要分页,总要知道分页的总数),Page了以后Get等方法也同样会Reset查询,甚至Count的时候也会进行Reset

OrWhere使用not in时报错

func (this *DemoModel)List() (int,[]map[string]interface{},error){ userM:=this.GetTable() count,err := userM.Count("*") result,err:=userM.OrWhere("name", "not in", []string{"小米"}).Get()//这里报错 lastsql := db.LastSql() log.Debug(lastsql) if(err!=nil){ return 0,result,err } this.UseGetter(result) return count,result,nil }
interface conversion: interface {} is *runtime.TypeAssertionError, not string

使用orWhere时报错,求大大指教。

Execute()执行insert以后无法取到插入的行数量

Execute()执行insert以后无法取到插入的行数量,只能返回上一次插入的最后一个ID,在某些情况下不方便使用。我看了database.go,parseExecute()时要不只返回LastInsertId,要不只返回RowsAffected,并且没有保存:

func (dba *Database) parseExecute(stmt *sql.Stmt, operType string, vals []interface{}) (int64, error) {
	var res int64
	var err error
	result, errs := stmt.Exec(vals...)
	if errs != nil {
		return 0, errs
	}

	switch operType {
	case "insert":
		res, err = result.LastInsertId()
	case "update":
		res, err = result.RowsAffected()
	case "delete":
		res, err = result.RowsAffected()
	}

	return res, err
}

能否改进一下?

有个比较低级的错误

utils/util.go中的AddSingleQuotes有2个问题
一个是启用了stmt,但是仍然是通过拼接SQL,这部分就不展开说了,但是在数据的外层添加单引号以后,数据内部的单引号没有被替换掉,导致执行SQL直接出错。
另外一个在对数据加单引号的时候,竟然先对数据进行了trim……如果我就是想在数据库中保存空格怎么办?
代码修改如下:
return "'" + strings.Replace(ParseStr(data), "'", "\'", -1) + "'"

gorose.Open读取文件配置时,会默认走集群配置的解析。

        if strings.Contains(strFp, "Slave") &&
		strings.Contains(strFp, "Master") {
		err = json.Unmarshal(fp, dbConfCluster)
	} else {
		//err = json.Unmarshal([]byte(fp), &conf.Master)
		err = jsonDecoder(fp, dbConfCluster) //即使配置文件设置的单一服务器配置,也会通过反射解析集群配置报错
	}

建议要么定死配置文件格式,将slave留空,要么这里的代码改成单一配置的interface。

go mod 引用不了

require github.com/gohouse/gorose v1.0.0,报 unknown revision v1.0.0,但你的tag是有这个版本的

你们怎么可以随便修改函数的返回值??

今天换了台电脑,重新get了gorose,发现编译出来的系统出问题了,跟踪发现insert返回的值始终为1,而不是原来的LastInsertID了!
我系统中用到了大量的Insert,然后获得返回的ID在其它地方使用,现在突然全部要改了,还得小心不要漏了哪里。
做为一个稳定的系统,API是不应该允许随便修改参数和返回值,有新需求应该增加新函数来完成,而不是修改原来的函数,这样很容易导致老代码出问题的,有时候真会害死人啊!

Update/Insert时数据如何使用数据库表达式?

例如:
res, err := db.Table("area").Data(map[string]interface{}{"names": "fizz3", "age": 3, "time": “now()” }).Where("id",10).Update()
希望生成的SQL语句:
Update area set names='fizz3', age=3, time=now() where id=10
但是目前好像不支持数据库表达式,只支持值直接代入。
能否实现类似表达式功能:
res, err := db.Table("area").Data(map[string]interface{}{"names": "fizz3", "age": 3, "time": map[string]interface{}{"exp":"now()"} }).Where("id",10).Update()
这个功能还是很实用的,比如用于插入NULL值、直接调用数据库函数或存储过程生成更新值等,否则所有需要表达式的更新都必须写原生SQL不方便。
谢谢!

使用ssl模式的mysql数据库如何建立连接

rootCertPool := x509.NewCertPool()
pem, _ := ioutil.ReadFile("/var/www/html/BaltimoreCyberTrustRoot.crt.pem")
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
log.Fatal("Failed to append PEM.")
}
mysql.RegisterTLSConfig("custom", &tls.Config{RootCAs: rootCertPool})
var connectionString string
connectionString = fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?allowNativePasswords=true&tls=custom",'myadmin@mydemoserver' , 'yourpassword', 'mydemoserver.mysql.database.azure.com', 'quickstartdb')
db, _ := sql.Open("mysql", connectionString)

这是微软云的mysql ssl下go的连接代码,这部分代码如何移植到gorose上?

like 模糊查询 SqlLogs日志显示不正确

count, _ := utils.DB.Table("T_Goods").Where("GoodsName", "like", name).Count()

期望的sql日志是select count(*) from T_Goods where GoodsName like '%name%' ,

但是通过SqlLogs 发现日志SQL变成 `SELECT count(*) as count FROM T_Goods WHERE GoodsName like '%!a(MISSING)bc%!'(MISSING) '

真是执行的sql没问题, 但是日志显示有问题
`

在postgres数据库上,insert语句会执行失败

result, err := db.Table("user").Data(data).Insert()
生成的SQL语句为:insert into user (nick_name,type,account) values ('ttt','1','tt')
在postgres上执行result的结果会始终返回0
因为生成的语句在postgres上执行会报语法错误,需要user加上双引号后才可以成功执行
insert into “user” (nick_name,type,account) values ('ttt','1','tt')

挺喜欢这种链式风格的

1,有没有相应的struct转换的?这种场景还是挺多的,而不仅仅是map。
2,有没有与其它orm相应的性能对比出来?

关于实现with方法的建议

关于关联模型#20 ,用Join实现的并不是我想要的。
thinkphp5中有个with方法,可以实现关联模型,以单独查询一个对象为例。
系统有user、user_info、user_category三个表,其数据结构分别为:

user: id,name,gender,c_id(对应user_category的id);
user_info: id,u_id(对应user的id),id_card
user_category: id,name

在tp中可以通过:UserModel->Where("Id","=",1)->with("user_info","user_category")->find();获取如下格式的数据:


id:1,
name:"小明",
user_info:{u_id:1,id_card:"411423333333333333"},
user_category:{id:11,name:"老师"}

这样用起来特别方便,建议gorose实现with方法。
提供一个不成熟的思路:

1.先忽略with方法,执行解析的sql语句,得到table1的一个记录。
2.定义with("relation","table2_name","table1.key","table2.key");
3.取1中记录的table1.key的value,和with方法构成第二条sql语句,并执行。
4.将执行的结果挂载到1中的记录上。
5.返回数据

对于列表的获取,为了避免多次循环查询,可以基于步骤一做些改变,具体如下。

1.先忽略with方法,执行解析的sql语句,得到table1的记录集合
2.定义with("relation","table2_name","table1.key","table2.key");
3.取1中记录集合的table1.key的value构成一个IN (table1.key.v1,table1.key.v2,table1.key.v3....),和with方法构成第二条sql语句,查询出table2的集合。
4.对两个集合进行合成,基于with中的table1.key和table2.key合并集合。
5.返回列表。

如果表达的不清楚,欢迎追问。

Execute函数中的stmt没有Close?

database.go中的Execute函数中最后一段代码:
stmt, err := DB.Prepare(sqlstring)
if err != nil {
return 0, err
}
return dba.parseExecute(stmt, operType, vals)
这个stmt不用Close?
我在一个项目中大量操作数据库,结果产生了Can't create more than max_prepared_stmt_count statements (current value: 16382)这个错误,不知道跟这个stmt没有Close有没有关系。

tag

大佬,麻烦在项目里再建一个tag v1.0.2 标签

同时使用多个连接配置,每次都要重新Open一个新配置?

一个简单的例子:业务逻辑需要用到多个库(或用户),这可以在ConnectionConfigs里面配置。但是每次到切换配置时,都会用Open去建立一个新的Connection来覆盖之前Connect全局变量,之前的Connection则被“丢弃”。

PS:一开始我以为gorose.Open()会返回一条新的Connection,所以我使用map将配置对应的Connection关联,这样就不用重复Open相同的配置,结果不行,发现map中的Connection都是同一个(且最后一次Open的那个);接着尝试GetInstance()来返回一个新的DataBase指针,利用Map对应配置,最后发现所有的DataBase指针都会去找那个全局的Connet变量。故,提出问题,望得到正解!

go get error!

run:

go get -u github.com/gohouse/gorose

get:

cd /Users/petaflops/work/golang/src/github.com/gohouse/gorose; git submodule update --init --recursive

fatal: No url found for submodule path 'docs/gorose' in .gitmodules
package github.com/gohouse/gorose: exit status 128

嵌套查询好像不好用。

嵌套查询好像不好用。
`

User := ConnectionMS.NewSession().Table(t.TableName())
User.Where("name", ">", 1)
User.Where(func() {
	User.OrWhere("name", "fizz").OrWhere(func() {
		User.Where("name", "fizz2").Where(func() {
			User.Where("name", "fizz53").OrWhere("website", "like", "fizzday%")
		})
	})
})

fmt.Println(User.BuildSql())

`

居然生成SELECT * FROM T_Room_Order WHERE name > 1 and ()

是不是有什么bug

查询不到记录,会返回错误:sql: no rows in result set

var db = *DefaultConn.NewSession()
// 查询全部system配置数据
var user models.User
err := db.Table(&user).Where("name", name).Select()
return &user, err

这样的情况下,如果查询不到匹配的记录,err会不为空(sql: no rows in result set)
但是实际上很多业务逻辑,查询不到是正常的,不需要报错,只需要判断结果是否为空

建议

  1. 使用 Go 依赖管理器(我觉得 Glide 不错 https://github.com/Masterminds/glide )。我看了一下源码,目前已使用几个外部库 github.com/gohouse/utils 和 github.com/go-sql-driver/mysql ,这些外部库可以使用依赖管理器进行管理的,方便用户快速使用。
  2. laravel 框架目前是支持MySQL、PostgreSQL、SQLite、SQL Server等数据库,代码架构需要考虑这些吧。
  3. 使用GitHub的“projects”进行项目管理规划,这样可以管理TODO及任务安排。

Reset方法将this.trans = false,导致事务无效

db.Begin以后,进行任何的查询,都会调用Reset方法,this.trans = false使得剩余的查询使用stmt, err := DB.Prepare(sqlstring),而非stmt, err := Tx.Prepare(sqlstring)。
既然起了事务,应保持用户在commit或rollback之前在同一个连接中继续使用事务,而不应该粗暴的将this.trans设置为false

Count()函数不能代入参数,默认都是select count(*)...但有时候需要代入1或者具体字段名

在优化某些数据库查询时,Count(1)、Count(*)、Count(FieldName)还是有一定差异的。建议为Count()函数添加可变参数:

// Count : select count rows
func (dba *Database) Count(args ...string) (int, error) {
        fields := "*"
        if len(args) >0 {
                fields = args[0]
        }
	res, err := dba.buildUnion("count", fields)
	if err != nil {
		return 0, err
	}
	return int(res.(int64)), nil
}

无参数时默认为select count(*),有参数时默认为Select count(args[0])。
谢谢!

fatal: No url found for submodule path 'docs/gorose' in .gitmodules

➜  src git:(master) ✗ go get -u github.com/gohouse/gorose

# cd /Users/admin/go/src/github.com/gohouse/gorose; git submodule update --init --recursive
fatal: No url found for submodule path 'docs/gorose' in .gitmodules
package github.com/gohouse/gorose: exit status 128

发现压测pool不管用

是我使用的姿势不对么?


package main

import (
	"fmt"
	"log"

	"net/http"

	_ "github.com/go-sql-driver/mysql"
	"github.com/gohouse/gorose"
)

// MysqlPool mysql pool
func InitMysqlPool() gorose.Connection {
	var dbConfig = map[string]interface{}{
		"Default":         "mysql_xx", // 默认数据库配置
		"SetMaxOpenConns": 100,        // (连接池)最大打开的连接数,默认值为0表示不限制
		"SetMaxIdleConns": 10,         // (连接池)闲置的连接数, 默认1
		"Connections": map[string]map[string]string{
			"mysql_xx": map[string]string{ // 定义名为 mysql_dev 的数据库配置
				"host":     "127.0.0.1", // 数据库地址
				"username": "root",      // 数据库用户名
				"password": "root",      // 数据库密码
				"port":     "3306",      // 端口
				"database": "j20_api",   // 链接的数据库名字
				"charset":  "utf8mb4",   // 字符集
				"protocol": "tcp",       // 链接协议
				"prefix":   "",          // 表前缀
				"driver":   "mysql",     // 数据库驱动(mysql,sqlite,postgres,oracle,mssql)
			}}}
	db, err := gorose.Open(dbConfig)
	if err != nil {
		fmt.Println(err)
		panic(err)
		return db
	}
	return db
}

func main() {
	startHttpServer()
}

func startHttpServer() {
	http.HandleFunc("/pool", pool)
	err := http.ListenAndServe(":7099", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
func pool(w http.ResponseWriter, r *http.Request) {
	db := InitMysqlPool()
	record, _ := db.Table("user").First()
	fmt.Println(record)
	fmt.Fprintln(w, "finish")
}


狂报错.
Error 1040: Too many connections.
使用原生的 没这个问题.

func init() {
	var err error
	db, err = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/j20_api?charset=utf8mb4")
	if err != nil {
		panic(err)

	}
	db.SetMaxOpenConns(100)

	db.SetMaxIdleConns(5)

	db.Ping()

}

utils.AddSingleQuotes

utils.AddSingleQuotes 这个里只对单引号进行了转义, 反斜杠没有转义,导致插入内容中的反斜杠丢失了
gorose v1.0.4

我只能自己加了个预处理函数

func AddSlashes(str string) string {
	str = strings.Replace(str, "\\", "\\\\", -1)
	str = strings.Replace(str, "\"", "\\\"", -1)
	return str
}

相关资料: https://www.yangyu.club/p-251.html

Change table name on the same db, the conditions should be cleared?

connection, err := gorose.Open(DbConfig)
if err != nil {
	fmt.Println("error")
	return
}

defer connection.Close()

db := connection.GetInstance()

table1 := db.Table("table1")
count1, _ := table1.Where("id > 2").count()
// select count(*) from table1 where id > 2

table2 := db.Table("table2")
count2, _ := table2.Where("id < 3").count()
// select count(*) from table2 where id > 2 and id < 3

for循环下where的条件会叠加

代码如下:

personTable := db.Table("person")
  for i := 1; i < 15; i++ {
    f := "随机字符"
    l := "随机字符"
    n, err := personTable.Data(map[string]interface{}{"first_name": f,"last_name": l}).Where("id", i).Update()
    if (err != nil) {
      fmt.Println(err)
    }
    fmt.Println(db.LastSql)
    updateNum += n
  }

where的条件会一直叠加

update person set first_name='7bd8da474d85c4f8af9d29364e2e95d6',last_name='7d7e0d887e969e738536f3d726529ba8' WHERE  id = '1' and id = '2' and id = '3' and id = '4'and id = '5' and id = '6' and id = '7' and id = '8' and id = '9' and id = '10' and id = '11' and id = '12' and id = '13' and id = '14'

dbconfig配置参数不方便存储到外部json/yaml等格式配置文件中,能否改进?

dbconfig配置参数为map[string]interface{}格式,数据库连接配置是map[string]string格式,数据库配置项不固定,很难使用struct进行定义并加载。而且使用json/simplejson等解析工具从外部读取配置文件后,数据库配置项自动变成了map[string]interface{}格式,gorose认为是不正确的配置。能否将配置文件中的数据库配置项改成数组,以方便动态加载并自动适配?如下:

``type DBConfig struct {

Default string `json:"default"`

SetMaxOpenConns int `json:"SetMaxOpenConns"`

SetMaxIdleConns int `json:"SetMaxIdleConns"`

DBList []map[string]string `json:"dblist"`    \\ 适配可变数据库连接配置,方便进行配置文件持久化

}``

是否可行?

Get方法调用之后没有Reset吗?

版本0.9.2
db.Table("user").Fields("*").Where("user_id", id).Get()
id通过传参赋值,每次传入不同的id,可以看到打出来的LastSql也保存了之前所有传入的id。
看了Get的实现,没有在执行完成之后进行重置。

好像不支持多数据源同时使用

通过源码发现DB和Connect是全局的,如果gorose.Open打开了多个不同数据库,这些Connect都调用的是同一个驱动DB,实际是只能用最后一个数据库

oracle部分

oracle的sql语句中没有limit,有关oracle中limit部分会报错

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.