sqlboiler
2024-07-09 18:34:12 0 举报
AI智能生成
内部使用
作者其他创作
大纲/内容
sqlboiler
go install github.com/volatiletech/sqlboiler/v4@latest<br>go install github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-mysql@latest<br>
牢牢记住,这是v4
依赖:<br>go get github.com/volatiletech/sqlboiler/v4<br>go get github.com/volatiletech/null/v8<br>sqlboiler mysql --config xx.toml//运行
配置文件:<br>wipe = true # 先删除之前自动生成的文件再重新生成<br>no-tests = true # 不生成测试代码<br>add-global-variants = true # 生成使用全局数据源的方法,也就是带 G 后缀的方法<br>add-panic-variants = true # 生成使用当 error 不为 nil 时 panic 的方法,也就是带 P 后缀的方法<br>no-context = true # 不需要上下文参数<br><br>[mysql]<br>dbname = "dbname"<br>host = "127.0.0.1"<br>user = "root"<br>pass = "longque55"<br>sslmode = "false"<br>
注意事项:<br>[psql]<br># Removes migrations table, the name column from the addresses table, and<br># secret_col of any table from being generated. Foreign keys that reference tables<br># or columns that are no longer generated because of whitelists or blacklists may<br># cause problems.<br>blacklist = ["migrations", "addresses.name", "*.secret_col"]<br>
这个讨厌的bug,解决方案:<br>found key user in config, but it was not a string (<nil>)<br>Error: unable to initialize tables: unable to fetch table data: driver (D:\GOPATH\bin\sqlboiler-mysql.exe) exited non-zero: exit status 1<br>
go版本:1.19(使用gvm管理go版本)<br>mysql版本:8.0<br>需要使用root账户创建一个新的user:我这里叫david1<br>创建一个数据库,最好不要有_ 我的叫sqlboilerTest<br>表名和列名必须使用蛇形命名 snake_case。<br>不要修改任何生成文件,否则会导致重新生成代码出错。<br>创建一个表,最好老老实实的,不要整骚操作:<br>CREATE TABLE users (<br> id INT AUTO_INCREMENT PRIMARY KEY,<br> username VARCHAR(50) NOT NULL,<br> email VARCHAR(100) NOT NULL,<br> birthdate DATE,<br> is_active BOOLEAN DEFAULT TRUE<br>);<br>
wipe = true # 先删除之前自动生成的文件再重新生成<br>no-tests = true # 不生成测试代码<br>add-global-variants = true # 生成使用全局数据源的方法,也就是带 G 后缀的方法<br>add-panic-variants = true # 生成使用当 error 不为 nil 时 panic 的方法,也就是带 P 后缀的方>法<br>no-context = true # 不需要上下文参数<br><br>[mysql]<br>dbname = "sqlboilerTest"<br>host = "localhost"<br>user = "david1"<br>pass = "123456"<br>sslmode = "false"<br>
生成好了之后,首先设置数据源:<br>import (<br> "database/sql"<br> "fmt"<br> _ "github.com/go-sql-driver/mysql"<br> "github.com/volatiletech/sqlboiler/v4/boil"<br> "github.com/volatiletech/sqlboiler/v4/queries/qm"<br> "log"<br> "sqlboiler_test/models"<br>)<br><br>func main() {<br> // 创建数据源<br> db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/tbname?parseTime=True") <br> if err != nil {<br> log.Fatal(err)<br> }<br> // 设置全局数据源<br> boil.SetDB(db) <br>}<br><br>
增:<br>func InsertUserDemo() {<br> user := models.User{<br> Username: "david2",<br> Password: "123456",<br> NickName: "dashabi",<br> }<br> user.InsertGP(boil.Infer())<br> fmt.Printf("%+v", user)<br>}<br>
删:<br>func DeleteUserDemo() {<br> // 根据 User.ID 进行删除<br> user := models.User{ID: 1}<br> count := user.DeleteGP()<br> fmt.Println(count)<br><br> // 根据 UserSlice 批量删除<br> users := models.Users().AllGP()<br> count = users.DeleteAllGP()<br> fmt.Println(count)<br><br> // 根据条件进行删除<br> count, _ = models.Users(models.UserWhere.Username.EQ("username1")).DeleteAllG()<br> fmt.Println(count)<br>}<br>
查:<br>func SelectUserDemo() {<br> // 根据条件查询(如果不指定条件则查询全部)<br> users := models.Users(qm.Select(models.UserColumns.ID, models.UserColumns.NickName),<br> models.UserWhere.Username.EQ("username1")).AllGP()<br> fmt.Println(users)<br><br> // 查询数量<br> count := models.Users(models.UserWhere.Username.EQ("username1")).CountGP()<br> fmt.Println(count)<br><br> // 根据主键查询<br> user, err := models.FindUserG(1)<br> if err == sql.ErrNoRows {<br> // 业务处理<br> }<br> fmt.Println(user)<br>}<br>
改:<br>func UpdateUserDemo() {<br> // 根据 User.ID 进行更新<br> user := models.User{ID: 1, NickName: "nickName1001"}<br> count := user.UpdateGP(boil.Whitelist(models.UserColumns.NickName))<br> fmt.Println(count)<br><br> // 根据 UserSlice 批量更新<br> users := models.Users().AllGP()<br> count = users.UpdateAllGP(models.M{models.UserColumns.NickName: "updateAllNickName"})<br> fmt.Println(count)<br><br> // 根据条件进行更新<br> count, _ = models.Users(models.UserWhere.NickName.EQ("updateAllNickName")).<br> UpdateAllG(models.M{models.UserColumns.NickName: "updateAllNickName2"})<br> fmt.Println(count)<br>}<br>
官网配置例子:<br>output = "my_models"<br>wipe = true<br>no-tests = true<br><br>[psql]<br> dbname = "dbname"<br> host = "localhost"<br> port = 5432<br> user = "dbusername"<br> pass = "dbpassword"<br> schema = "myschema"<br> blacklist = ["migrations", "other"]<br><br>[mysql]<br> dbname = "dbname"<br> host = "localhost"<br> port = 3306<br> user = "dbusername"<br> pass = "dbpassword"<br> sslmode = "false"<br><br>[mssql]<br> dbname = "dbname"<br> host = "localhost"<br> port = 1433<br> user = "dbusername"<br> pass = "dbpassword"<br> sslmode = "disable"<br> schema = "notdbo"<br>
sqlboiler会自动生成名字,但如果你的数据库名字起的不好且无法修改,或者 sqlboiler 无法推断你的名字,<br>那么你可以使用 别名 去修改生成代码中的表名、列名:<br># 为原始表名为 user 的表设置别名<br>[aliases.tables.user]<br># 大写复数时的名字<br>up_plural = "UserInfos"<br># 大写单数时的名字<br>up_singular = "UserInfo"<br># 小写复数时的名字<br>down_plural = "userInfos"<br># 小写单数时的名字<br>down_singular = "userInfo"<br><br> # 为表user的password列设置别名 psw<br> [aliases.tables.user.columns]<br> password = "psw"<br><br>
注意事项(官方版):<br>在生成代码时忘记排除你不想要的表,比如迁移表。<br>表忘记设置主键,所有表都需要主键。<br>兼容性测试需要权限去创建一个数据库进行测试,请确保在 sqlboiler.toml 中配置足够的权限。<br>nil或者被关闭的数据源(database handle)。确保你传入的 boil.Executor 不为 nil,也就是 boil.SetDB(db) 的 db。<br>如果你使用 G (全部数据源),请确保已经初始化全局数据源并使用boil.SetDB()<br><br>命名冲突 Naming collisions,如果存在命名冲突而编译失败,请查看别名特性。<br>字段没有被插入(通常是默认值为true的布尔类型),boil.Infer把Go的所有零值都当成你不想插入。当你想插入bool类型的false时,请使用 whitelist/greylist 让sqlboiler知道你想插入什么字段。<br>decimal 库错误,比如 pq: encode: unknown type types.NullDecimal 是因为 github.com/ericlargergren/decimal 库太新或者损坏导致,请在go.mod中使用下面版本 github.com/ericlagergren/decimal v0.0.0-20181231230500-73749d4874d5<br><br>其他的错误原因可以通过查看生成的代码,或者设置 boil.DebugMode 为true 可以查看 sql和参数。也可以设置 boil.DebugWriter 重定向 debug 输出流,默认是 os.Stdout。<br><br>
官方示例:<br>CREATE TABLE pilots (<br> id integer NOT NULL,<br> name text NOT NULL<br>);<br>ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);<br><br>CREATE TABLE jets (<br> id integer NOT NULL,<br> pilot_id integer NOT NULL,<br> age integer NOT NULL,<br> name text NOT NULL,<br> color text NOT NULL<br>);<br>ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);<br><br>CREATE TABLE languages (<br> id integer NOT NULL,<br> language text NOT NULL<br>);<br>ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);<br><br>CREATE TABLE pilot_languages (<br> pilot_id integer NOT NULL,<br> language_id integer NOT NULL<br>);<br>ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);<br>
自动 CreatedAt/UpdatedAt:<br>如果你生成的 SQLBoiler models <br>包含 created_at 或 updated_at <br>列将会被自动设置为 time.Now()<br>可以通过 boil.SetLocation()设置时区。<br>
查询构造器:<br>启动方法被于构造查询模块系统(Query Mod System)。<br>启动方法使用一组 查询模块(Query Mod) 作为参数,<br>并在最后调用一个结束方法(Finisher Method)<br>
// SELECT COUNT(*) FROM user;<br>count, err := models.Users().Count(ctx, db)<br><br>// SELECT * FROM user LIMIT 5;<br>users, err := models.Users(qm.Limit(5)).All(ctx, db)<br><br>// DELETE FROM user WHERE id = 1;<br>err := models.Users(qm.Where("id = ?", 1)).DeleteAll(ctx, db)<br>// 下面是类型安全的方式<br>err := models.Users(models.UserWhere.ID.EQ(1)).DeleteAll(ctx, db)<br>//需要直接指定数据表,也可以使用models.NewQuery():<br>rows, err := models.NewQuery(qm.From("user")).Query(db)<br>
查询模块系统(Query Mod System):SQLBoiler为表、列生成了类型安全的标识符。使用这些标识符将更加安全,因为如果数据库进行修改之后会产生编译错误而不是运行时错误。<br><br>// 点 import 让我们可以直接使用里面的函数而不需要加 "qm." 前缀<br>import . "github.com/volatiletech/sqlboiler/v4/queries/qm"<br><br>// 对生成的 model 使用 raw query(原始查询)<br>// 如果这个查询模块存在,其他查询模块将被覆盖<br>SQL("select * from pilots where id=?", 10)<br>models.Pilots(SQL("select * from pilots where id=?", 10)).All()<br><br>Select("id", "name") // 指定查询列<br>Select(models.PilotColumns.ID, models.PilotColumns.Name)<br>From("pilots as p") // 指定from表<br>From(models.TableNames.Pilots + " as p")<br><br>// WHERE 语句构建<br>Where("name=?", "John")<br>models.PilotWhere.Name.EQ("John")<br>And("age=?", 24)<br>// 目前还没有等价的类型安全查询<br>Or("height=?", 183)<br>// 目前还没有等价的类型安全查询<br><br>Where("(name=? and age=?) or (age=?)", "John", 5, 6)<br>// Expr 允许手动把语句弄成一组<br>Where(<br> Expr(<br> models.PilotWhere.Name.EQ("John"),<br> Or2(models.PilotWhere.Age.EQ(5)),<br> ),<br> Or2(models.PilotAge),<br>)<br><br>// WHERE IN 语句构建<br>WhereIn("name, age in ?", "John", 24, "Tim", 33) // 生成: WHERE ("name","age") IN (($1,$2),($3,$4))<br>WhereIn(fmt.Sprintf("%s, %s in ?", models.PilotColumns.Name, models.PilotColumns.Age, "John", 24, "Tim", 33))<br>AndIn("weight in ?", 84)<br>AndIn(models.PilotColumns.Weight + " in ?", 84)<br>OrIn("height in ?", 183, 177, 204)<br>OrIn(models.PilotColumns.Height + " in ?", 183, 177, 204)<br><br>InnerJoin("pilots p on jets.pilot_id=?", 10)<br>InnerJoin(models.TableNames.Pilots + " p on " + models.TableNames.Jets + "." + models.JetColumns.PilotID + "=?", 10)<br><br>GroupBy("name")<br>GroupBy("name like ? DESC, name", "John")<br>GroupBy(models.PilotColumns.Name)<br>OrderBy("age, height")<br>OrderBy(models.PilotColumns.Age, models.PilotColumns.Height)<br><br>Having("count(jets) > 2")<br>Having(fmt.Sprintf("count(%s) > 2", models.TableNames.Jets)<br><br>Limit(15)<br>Offset(5)<br><br>// 显式锁定<br>For("update")<br><br>// With 语句<br>With("cte_0 AS (SELECT * FROM table_0 WHERE thing=? AND stuff=?)")<br>
原始查询:<br>err := queries.Raw("select * from pilots where id=?", 5).Bind(ctx, db, &obj)<br>可以使用自己的struct或生成的struct去``Bind() 。Bind()`支持绑定到单独一个对象或者一个slice。<br>queries.Raw() 也有一个不需要执行对象绑定的方法。<br>也可以使用 models.NewQuery() 去应用 查询模块系统 结合自定义的 struct。<br>
bind():<br>Bind()结束函数允许你通过原始查询或者<br>查询构造方式去绑定你自定义的struct或生成的struct。<br><br>
// 自定义 struct 使用两个生成的 structs<br>type PilotAndJet struct {<br> models.Pilot `boil:",bind"`<br> models.Jet `boil:",bind"`<br>}<br><br>var paj PilotAndJet<br>// 使用原始查询<br>err := queries.Raw(db, `<br> select pilots.id as "pilots.id", pilots.name as "pilots.name",<br> jets.id as "jets.id", jets.pilot_id as "jets.pilot_id",<br> jets.age as "jets.age", jets.name as "jets.name", jets.color as "jets.color"<br> from pilots inner join jets on jets.pilot_id=?`, 23,<br>).Bind(&paj)<br><br>// 使用查询构造<br>err := models.NewQuery(<br> Select("pilots.id", "pilots.name", "jets.id", "jets.pilot_id", "jets.age", "jets.name", "jets.color"),<br> From("pilots"),<br> InnerJoin("jets on jets.pilot_id = pilots.id"),<br>).Bind(ctx, db, &paj)<br>
对Bind()的控制可以使用下面的struct tag 模式:<br>
type CoolObject struct {<br> // 如果没有指定名字,会使用列名的 TitleCase 进行匹配<br> Frog int<br><br> // 如果指定名字,会使用列名的 titlecased 进行匹配<br> Specify an alternative name for the column, it will<br> // be titlecased for matching, can be whatever you like.<br> Cat int `boil:"kitten"`<br><br> // 忽略这个域,不绑定<br> Pig int `boil:"-"`<br><br> // 不是用正常的方式进行绑定,像 sql-able strict 如 time.Time<br> // 递归的搜索Dog struct 中的查询结果名<br> Dog `boil:",bind"`<br><br> // 同上,除了指定一个不同的表名<br> Mouse `boil:"rodent,bind"`<br><br> // 忽略这个域,不绑定<br> Bird `boil:"-"`<br>}<br>
事务:(也可以使用 boil.BeginTx() 通过全局数据源开启一个事务,<br>它利用 boil.SetDB() 设置的数据源。)<br><br>tx, err := db.BeginTx(ctx, nil)<br>if err != nil {<br> return err<br>}<br><br>users, _ := models.Pilots().All(ctx, tx)<br>users.DeleteAll(ctx, tx)<br><br>// Rollback 或 commit<br>tx.Commit()<br>tx.Rollback()<br>
debug日志:<br>boil.DebugMode = true<br><br>// 可以选择设置输出源. 默认是 os.Stdout<br>fh, _ := os.Open("debug.txt")<br>boil.DebugWriter = fh<br>
// 自定义 struct 去查询一个子集<br>type JetInfo struct {<br> AgeSum int `boil:"age_sum"`<br> Count int `boil:"juicy_count"`<br>}<br><br>var info JetInfo<br><br>// 使用查询构造<br>err := models.NewQuery(Select("sum(age) as age_sum", "count(*) as juicy_count", From("jets"))).Bind(ctx, db, &info)<br><br>// 使用原始查询<br>err := queries.Raw(`select sum(age) as "age_sum", count(*) as "juicy_count" from jets`).Bind(ctx, db, &info)<br>
函数变体:<br>函数可以生成它的变体通过 --add-global-variants 和 --add-panic-variants<br>
// 设置全局数据库把柄(数据源)G方法变体<br>boil.SetDB(db)<br><br>pilot, _ := models.FindPilot(ctx, db, 1)<br><br>err := pilot.Delete(ctx, db) // 普通模式需要db参数<br>pilot.DeleteP(ctx, db) // P变体,需要db参数并在error时panic<br>err := pilot.DeleteG(ctx) // G变体,不需要db参数<br>pilot.DeleteGP(ctx) // GP变体,不需要db参数并在error时panic<br><br>db.Begin() // 正常的方式创建一个事务<br>boil.BeginTx(ctx, nil) // 使用全局数据源创建事务<br>
结束方法:<br>// 调用方式和下面类似:<br>models.Pilots().All(ctx, db)<br><br>One() // 查询一行 (与LIMIT(1)相同)<br>All() // 查询全部 (与SELECT * FROM相同)<br>Count() // 查询行数 (与COUNT(*)相同)<br>UpdateAll(models.M{"name": "John", "age": 23}) // 更新所有匹配行<br>DeleteAll() // 删除所有匹配行<br>Exists() // 返回一个bool表示所查询的行是否存在<br>Bind(&myObj) // 绑定查询结构到你自己的struct<br>Exec() // 执行不需要任何返回的SQL查询<br>QueryRow() // 执行需要一行返回的SQL查询<br>Query() // 执行需要多行返回的SQL查询<br>
自由主题
win10的bug 找不到user对应的名字,目前没有好的解决方案<br>(github上出现的类似解决方案都无法解决)
需要配置哪个数据库都去sqlboiler_example去取<br>后续有新的需要添加再慢慢扩充<br>!!!不要改动example!!!(除非官方改动)
优点:整体替换而不是寻找文件的不同,便于开发
收藏
0 条评论
下一页
为你推荐
查看更多