1、引入gorm包
import "github.com/jinzhu/gorm"
2、导入数据库驱动
import _ "github.com/go-sql-driver/mysql"
为了方便记住导入路径,GORM包装了一些驱动:
import _ "github.com/jinzhu/gorm/dialects/mysql"
// import _ "github.com/jinzhu/gorm/dialects/postgres"
// import _ "github.com/jinzhu/gorm/dialects/sqlite"
// import _ "github.com/jinzhu/gorm/dialects/mssql"
所以可以用以下两种形式来使用mysql:
1、
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
2、
import (
"github.com/jinzhu/gorm"
_ "github.com/go-sql-driver/mysql"
)
3、连接数据库
1、最简单形式
func main() {
db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
defer db.Close()
}
2、公司形式
func initDB(info config.MysqlInfo) *gorm.DB {
db, err := gorm.Open("mysql", info.DSN)
if err != nil {
panic(err)
}
db.SetLogger(gormlog.NewLogger())
db.LogMode(true)
db.DB().SetMaxOpenConns(info.MaxOpen)
db.DB().SetMaxIdleConns(info.MaxIdle)
db.DB().SetConnMaxLifetime(time.Second * 300)
if err = db.DB().Ping(); err != nil {
panic(err)
}
return db
}
表名默认是模型的复数形式,列名默认是字段名的驼峰形式
type User struct {// 默认表名是`users`
ID uint // 列名为 `id`
Name string // 列名为 `name`
Birthday time.Time // 列名为 `birthday`
CreatedAt time.Time // 列名为 `created_at`
}
基本模型定义如下,表中需要这些字段的,可以直接引入模型即可
// 基本模型的定义
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}
//引入模型:
type User struct {
gorm.Model
Name string
}
//默认id为主键
type User struct {
ID uint // 字段`ID`为默认主键
Name string
}
// 使用tag`primary_key`用来设置主键
type Animal struct {
AnimalId int64 `gorm:"primary_key"` // 设置AnimalId为主键
Name string
Age int64
}
// 获取第一条记录,按主键排序
db.First(&user);
select * from users order by id limit 1;
// 获取最后一条记录,按主键排序
db.Last(&user);
select * from users order by id desc limit 1;
// 获取所有记录
db.Find(&user);
select * from users;
// 使用主键获取记录
db.First(&user,10);
select * from users where id =10;
指定要从数据库检索的字段,默认情况下,将选择所有字段;
//简单select
db.Select("name","age").Find(&user);
select name,age from users;
db.Select([]string{"name","age"}).Find(&user);
db.Table("users").Select("COALESCE(age,?)", 42).Rows()
SELECT COALESCE(age,'42') FROM users;
// 获取第一个匹配记录
db.Where("name=?","jinzhu").First(&user);
select * from users where name='jinzhu' limit 1
// 获取所有匹配记录
db.Where("name=?","jinzhu").Find(&user);
select * from users where name='jinzhu';
//不等于
db.Where("name<>?","jinzhu").Find(&user);
//in
db.Where("name in (?) ",[]string{"jinzhu1","jinzhu2"}).Find(&user)
//like
db.Where("name like ?","%jinzhu%").Find(&user);
//and
db.Where("name =? and age=?","jinzhu",16).Find(&user);
// Time
db.Where("create_at >= ?",lastWeek).Find(&user);
db.Where("create_at between ? and ?",lastWeek,today).Find(&user);
注意:当使用struct查询时,GORM将只查询那些具有值的字段
// Struct
db.Where(&user{Name:"jinzhu",Age:16}).First(&user);
select * from users where name="jinzhu" and age=16 limit 1;
// Map
db.Where(map[string]interface{}{"name":"jinzhu","age":16}).First(&user);
// 主键的Slice
db.Where([]int64{20,30,40}).Find(&user)
select * from users where id in(20.30.40)
// Not
db.Not("name","jinzhu").First(&user);
select * from users where name <>'jinzhu' limit 1;
// Not In
db.Not("name",[]string{"jinzhu1","jinzhu2"}).Find(&user);
select * from users where name not in ("jinzhu1","jinzhu2");
//Not In slice of primary keys
db.Not([]int64{20,30,40}).First(&user);
select * from users where id not in(30,40,50);
// Plain SQL
db.Not("name=?","jinzhu").Find(&user);
select * from users where not(name="jinzhu");
// Struct
db.Not(User{Name:"jinzhu"}).Find(&user);
select * from users where name <> "jinzhu";
注意:使用主键查询时,应仔细检查所传递的值是否为有效主键,以避免SQL注入
// 按主键获取
db.First(&user,10);
select * from users where id=10 limit 1;
// 简单SQL
db.Find(&user,"name=?","jinzhu");
select * from users where name="jinzhu";
db.Find(&user,"name=? and age=?","jinzhu",10);
select * from users where name="jinzhu" and age=10;
// Struct
db.Find(&user,User{Age:20});
select * from users where age=20;
// Map
db.Find(&user,map[string]interfice{}{"age":20});
//简单sql
db.Where("name=?","jinzhu")Or("age=?",20).Find(&user)
select * from users where name="jinzhu" and age=20;
// Struct
db.Where(User{Name:"jinzhu"})Or(User{Age:20}).Find(&user);
// Map
db.Where(map[string]interface{}{"name":"jinhzu"})Or(map[string]interface{}{"age":20})
Gorm有一个可链接的API,可以这样使用:
db.Where("name <>?","jinzhu").Where("age=? and role=?",20,"admin").Find(&user);
select * from users where name <>"jinzhu" and age=20 and role="admin";
// 为Select语句添加扩展SQL选项
db.Set("gorm:query_option","FOR UPDATE").Firsr(&user,10);
select * from users where id=10 for update;
从数据库检索记录时指定顺序,将重排序设置为true
以覆盖定义的条件
db.Order("age desc,name").Find(&user);
select * from users order by age desc,name;
//Multiple orders
db.Order("age desc").Order("name").First(&user);
// ReOrder
db.Order("age desc").Find(&user1).Order("age",true).Find(&user2);
select * from users order by age desc;(user1)
select * from users order by age;(user2)
db.Limit(10).Find(&user);
select * from users limit 10;
//-1就是取消限制
db.Limit(10).Find(&user1).Limit(-1).Find(&user2);
select * from users limit 10;(user1)
select * from users;(user2)
指定在开始返回记录之前要跳过的记录数
db.Offset(3).Find(&user);
select * from users offset 3;
//-1表示取消限制
db.Offset(10).Find(&user1).Offset(-1).Find(&user2);
select * from users offset 10; (user1)
select * from users;(user2)
db.Where("name=? and age=?","jinzhu",20).Find(&user).Count(&count);
select * from users where name="jinzhu" and age=20;(users)
select count(*) from users where name="jinzhu" and age=20;(count)
db.Model(&User{}).Where("name=?","jinzhu").Count(&count);
select count(*) from users where name="jinzhu";
db.Table("person_table").Count(&count);
select count(*) from person_table;
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
for rows.Next() {
...
}
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
for rows.Next() {
...
}
type Result struct {
Date time.Time
Total int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results);
rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
...
}
db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
// 多个连接与参数
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)
将模型中的单个列作为地图查询,如果要查询多个列,可以使用Scan
var ages []int64
db.Find(&users).Pluck("age", &ages)
var names []string
db.Model(&User{}).Pluck("name", &names)
db.Table("deleted_users").Pluck("name", &names)
// 要返回多个列,做这样:
db.Select("name, age").Find(&users)
将结果扫描到另一个结构中
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
将当前数据库连接传递到func(*DB) *DB
,可以用于动态添加条件
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 1000)
}
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func PaidWithCod(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
}
}
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有信用卡订单和金额大于1000
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有COD订单和金额大于1000
db.Scopes(OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有付费,发货订单
// 使用User结构定义创建`user_person`表
db.Table("user_person").CreateTable(&User{});
var my_users []User
db.Table("my_users").Find(&my_users)
SELECT * FROM my_users;
db.Table("my_users").Where("name=?","jinzhu").Delete();
delete from my_users where name="jinzhu";
db.Preload("Orders").Find(&users)
SELECT * FROM users;
SELECT * FROM orders WHERE user_id IN (1,2,3,4);
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
SELECT * FROM users;
SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
SELECT * FROM users WHERE state = 'active';
SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
SELECT * FROM users;
SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
SELECT * FROM users;
SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
db.Preload("Orders.OrderItems").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
Save
将包括执行更新SQL时的所有字段,即使它没有更改
db.First(&user);
user.Name="jinzhu";
user.Age=18;
db.Save(&user);
UPDATE users SET name='jinzhu', age=18, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
如果只想更新更改的字段,可以使用Update
, Updates
// 更新单个属性(如果更改)
db.Model(&user).Update("name","jinzhu1");
update users set name="jinzhu1", updated_at='2010-11-17 21:34:10' where id=111;
// 使用组合条件更新单个属性
db.Model(&user).Where("active",true).Update("name","jinzhu1");
update users set name="jinzhu1", updated_at='2010-11-17 21:34:10' where active=true and id=111;
//使用`map`更新多个属性,只会更新这些更改的字段
db.Model(&user).Updates(map[string]interface{}{"name":"jinzhu2","age":30});
update users set name="jinzhu1", updated_at='2010-11-17 21:34:10' ,age=30 where id=111;
//使用`struct`更新多个属性,只会更新这些更改的和非空白字段
db.Model(&user).Updates(User{Name:"jinzhu1",Age:20});
update users set name="jinzhu1", updated_at='2010-11-17 21:34:10' ,age=20 where id=111;
// 警告:当使用struct更新时,FORM将仅更新具有非空值的字段
// 对于下面的更新,什么都不会更新为"",0,false是其类型的空白值
db.Model(&user).Updates(User{Name:"",Age:0,active:false});
如果您只想在更新时更新或忽略某些字段,可以使用Select
, Omit
//更新选择的字段
db.Model(&user).Select("name").Updates(map[string]interface{}{"name":"jinzhu","age":10,"acitive":true});
update users set name="jinzhu1",updated_at='2010-11-17 21:34:10'
where id=111;
//忽略选择字段
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name":"jinzhu","age":10,"acitive":true});
update users set age=10,acitive=true,updated_at='2010-11-17 21:34:10'
where id=111;
以上更新操作将执行模型的BeforeUpdate
, AfterUpdate
方法,更新其UpdatedAt
时间戳,在更新时保存它的Associations
,如果不想调用它们,可以使用UpdateColumn
, UpdateColumns
// 更新单个属性,类似于`Update`
db.Model(&user).UpdateColumn("name", "hello")
UPDATE users SET name='hello' WHERE id = 111;
// 更新多个属性,与“更新”类似
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
UPDATE users SET name='hello', age=18 WHERE id = 111;
Callbacks
在批量更新时不会运行
db.Table("users").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
// 使用struct更新仅适用于非零值,或使用map[string]interface{}
db.Model(User{}).Updates(User{Name: "hello", Age: 18})
UPDATE users SET name='hello', age=18;
// 使用`RowsAffected`获取更新记录计数
db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
DB.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
DB.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';
DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;
如果要使用BeforeUpdate
, BeforeSave
更改回调中的更新值,可以使用scope.SetColumn
,例如
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
}
// 为Update语句添加额外的SQL选项
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello");
UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
警告 删除记录时,需要确保其主要字段具有值,GORM将使用主键删除记录,如果主要字段为空,GORM将删除模型的所有记录
// 删除存在的记录
db.Delete(&email);
delete from email where id=10;
// 为Delete语句添加额外的SQL选项
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email);
DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
删除所有匹配记录
db.Where("name like ?","%jin%").Delete(Email{});
delete emails where name like '%jinzhu%';
db.Delete(Email{},"name like ?","%jin%");
delete emails where name like '%jinzhu%';
如果模型有DeletedAt
字段,它将自动获得软删除功能! 那么在调用Delete
时不会从数据库中永久删除,而是只将字段DeletedAt
的值设置为当前时间。
db.Delete(&user);
UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// 批量删除
db.Where("age =?",20).Delete(&user);
UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
//软删除的记录将在查询时被忽略
db.Where("age = 20").Find(&user)
SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
// 使用Unscoped查找软删除的记录
db.Unscoped().Where("age=?",20).Find(&user);
SELECT * FROM users WHERE age = 20 ;
// 使用Unscoped永久删除记录
db.Unscoped().Delete(&user);
DELETE FROM orders WHERE id=10;
备注