1. Basic Concepts

Object Relational Mapping (ORM).

The database will provide an official client-side driver, but will need to handle the SQL and structure conversion itself.

Using the ORM framework lets us avoid transformations and write boring, redundant code. In theory, the ORM framework can get you out of SQL, but in practice you still need to know SQL to use ORM.

I am personally very averse to using ORM frameworks for two reasons.

I. Without freedom, I can’t control my database as I want.

Second, poor performance, than the official client drive directly write SQL 3-5 times lower efficiency.

However, ORM also has many advantages, and it can avoid slow SQL to some extent for novices.

Several articles have also discussed the pros and cons of ORM. For example, orM_is_AN_antipattern.

In general, whether or not to use the ORM framework depends on the developer organization of a project.

Old hands want freedom, new hands need rules. There are so many novices in the world that old hands have to make some concessions.

Gorm is an ORM framework developed with Golang, which has become one of the most popular ORM frameworks in Golang Web development. This article will explain the COMMON APIS used in GORM to help you quickly learn gorM.

Besides GORM, you have other options, such as SQLX and SQLC.

MySQL > connect to MySQL

Gorm can connect to a variety of databases, requiring only different drivers. Currently, only four databases are supported: MySQL, PostgreSQL, SQlite, and SQL Server. However, other databases can be accessed through customized methods.

The following uses mySQL as an example. You need to install two packages.

import (
    "gorm.io/driver/mysql" // gorm mysql driver package
	"gorm.io/gorm"// gorm
)
Copy the code

Connection code.

// MySQL configuration information
username := "root"              / / account
password := "xxxxxx" / / password
host := "127.0.0.1"             / / address
port := 3306                    / / port
DBname := "gorm1"               // Database name
timeout := "10s"                // Connection timed out, 10 seconds
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s? charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
/ / Open connections
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
iferr ! =nil {
    panic("failed to connect mysql.")}Copy the code

Declare the model

Each table corresponds to a model (structure).

Let’s say you have a goods table in your database.

CREATE TABLE'GORm1'. 'no title' (' id ')int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
  `price` decimal(10.2) NULL DEFAULT NULL.PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
Copy the code

That would correspond to something like this.

type Goods struct {
    Id    int
    Name  string
    Price int
}
Copy the code

convention

Gorm makes a lot of conventions and works with the idea of convention over configuration.

For example, it looks for the table name based on the complex number of the structure, uses ID as the primary key, and represents the creation, update, and delete times based on CreateAt, UpdateAt, and DeletedAt.

Gorm provides a Model structure that you can embed in your own structure, omitting the above fields.

type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}
Copy the code

Embedded in the goods structure.

type Goods struct {
    gorm.Model
    Id    int
    Name  string
    Price int
}
Copy the code

This allows you to omit the creation ID, CreatedAt, UpdatedAt, and DeletedAt fields each time you create a different structure.

Field tag

When you create the model, you can tag a field to define some of its properties.

For example, to create a Post structure, we want the Title to be mapped to T, set the maximum length to 256, and the field to be unique.

type Post struct {
	Title string `gorm:"column:t, size:256, unique:true"`
}
Copy the code

Equivalent to the following SQL.

CREATE TABLE `posts` (`t, size:256.unique:true` longtext)
Copy the code

For more information, see the table below.

Tag name instructions
column Specify the DB column name
type Column data type. The compatible general type is recommended. For example, all databases support bool, int, Uint, float, string, time, bytes and can be used together with other tags.not null,size.autoIncrement… likevarbinary(8)Specifying database data types in this way is also supported. When using the specified database data type, it needs to be the full database data type, such as:MEDIUMINT UNSIGNED not NULL AUTO_INSTREMENT
size Specify the column size, for example:size:256
primaryKey Specifies the column primary key
unique Specifying a unique column
default Specifies the default value for the column
precision Specifies the precision of the column
scale Specify column size
not null Specifies the column NOT NULL
autoIncrement Specifies an automatic growth column
embedded Nested fields
embeddedPrefix The column name prefix of the embedded field
autoCreateTime Tracing the current time at creation time, forintField, which tracks the number of timestamp seconds that you can usenano/milliTo track nanosecond and millisecond timestamps, for example:autoCreateTime:nano
autoUpdateTime Track the current time when creating/updating, forintField, which tracks the number of timestamp seconds that you can usenano/milliTo track nanosecond and millisecond timestamps, for example:autoUpdateTime:milli
index Create an index based on the parameter. Create a compound index if multiple fields use the same nameThe indexFor more details
uniqueIndex withindexSame, but create a unique index
check Create check constraints, for examplecheck:age > 13To see theThe constraintFor more details
<- Set the field write permission,<-:createOnly the creation,<-:updateUpdate only,<-:falseNo write permission,<-Create and update permissions
-> Set the field read permission,->:falseNo read permission
Ignore this field,-No read and write permission

Automatic migration

Gorm can automatically create tables based on the specified structure when the tables of the database are not initialized.

The db.AutoMigrate method is used to automatically create the User table according to the User structure. If the table already exists, this method does nothing.

type User struct {
	gorm.Model
	UserName string
	Password string
}

db.AutoMigrate(&User{})
Copy the code

The table building rules adjust user to plural and automatically add several fields in gorm.model. Because many databases are case insensitive, if using camelCase style naming, in the migration of the database will encounter many problems, so the database field naming style is using underscorecase style naming, GORM will automatically help us convert.

Equivalent to the following SQL.

CREATE TABLE'GORm1'. 'no title' (' id ')bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT,
  `created_at` datetime(3) NULL DEFAULT NULL,
  `updated_at` datetime(3) NULL DEFAULT NULL,
  `deleted_at` datetime(3) NULL DEFAULT NULL,
  `user_name` longtext CHARACTER SET utf8 COLLATE utf8_bin NULL,
  `password` longtext CHARACTER SET utf8 COLLATE utf8_bin NULL.PRIMARY KEY (`id`) USING BTREE,
  INDEX `idx_users_deleted_at`(`deleted_at`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
Copy the code

Create Craete Insert

Create using the db.create method, passing in a pointer to the structure.

user := User{UserName: "l", Password: "ddd"}
result := db.Create(&user)
Copy the code

Equivalent to the following SQL.

INSERT INTO
    `users` ( `created_at`.`updated_at`.`deleted_at`.`user_name`.`password` )
VALUES
	(
		'the 2020-12-03 17:19:00. 249'.'the 2020-12-03 17:19:00. 249',
		NULL,
	'l'.'ddd')
Copy the code

Gorm automatically maintains creATED_AT, UPDATed_AD, and deleted_AT fields.

Commonly used data returned after insertion

Here are some common insert data.

fmt.Println("ID:", user.ID)                       // Insert the primary key
fmt.Println("error:", result.Error)               // Return error
fmt.Println("rowsAffected:", result.RowsAffected) // The number of inserts
Copy the code

Only the specified fields are inserted

Select the specified field by Select.

user := User{UserName: "lzq", Password: "ccc"}
result := db.Select("UserName").Create(&user)
Copy the code

Equivalent to the following SQL.

INSERT INTO `users` (`user_name`) VALUES ('lzq')
Copy the code

_ Note: CreATED_AT, UPDATed_AD, and deleted_AT are not automatically maintained with select.

The specified field is not inserted

Use a Omit method to filter fields.

result := db.Omit("UserName").Create(&user)
Copy the code

Bulk insert

When batch inserts are needed, pass in a slice.

users := []User{
    {UserName: "lzq", Password: "aaa"},
    {UserName: "qqq", Password: "bbb"},
    {UserName: "gry", Password: "ccc"},
}
db.Create(&users)
Copy the code

Equivalent to the following SQL.

INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
	( 'the 2020-12-03 18:08:47. 478'.'the 2020-12-03 18:08:47. 478'.NULL.'lzq'.'aaa'), ('the 2020-12-03 18:08:47. 478'.'the 2020-12-03 18:08:47. 478'.NULL.'qqq'.'bbb'), ('the 2020-12-03 18:08:47. 478'.'the 2020-12-03 18:08:47. 478'.NULL.'gry'.'ccc')
Copy the code

Batch insertion

In some cases, the number of Users may be very large, and batches of batches can be inserted using the CreateInBatches method.

Suppose you have six pieces of user data and you want to insert two at a time, which will result in three SQL executions.

users := []User{
    {UserName: "lzq", Password: "aaa"},
    {UserName: "qqq", Password: "bbb"},
    {UserName: "gry", Password: "ccc"},
    {UserName: "lzq", Password: "aaa"},
    {UserName: "qqq", Password: "bbb"},
    {UserName: "gry", Password: "ccc"},
}

db.CreateInBatches(&users, 2)
Copy the code

This is equivalent to executing the following three SQL statements in sequence.

INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
	( 'the 2020-12-03 18:15:20. 602'.'the 2020-12-03 18:15:20. 602'.NULL.'lzq'.'aaa'), ('the 2020-12-03 18:15:20. 602'.'the 2020-12-03 18:15:20. 602'.NULL.'qqq'.'bbb')
Copy the code
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
	( 'the 2020-12-03 18:15:20. 616'.'the 2020-12-03 18:15:20. 616'.NULL.'gry'.'ccc'), ('the 2020-12-03 18:15:20. 616'.'the 2020-12-03 18:15:20. 616'.NULL.'lzq'.'aaa')
Copy the code
INSERT INTO `users` ( `created_at`, `updated_at`, `deleted_at`, `user_name`, `password` )
VALUES
	( 'the 2020-12-03 18:15:20. 621'.'the 2020-12-03 18:15:20. 621'.NULL.'qqq'.'bbb'), ('the 2020-12-03 18:15:20. 621'.'the 2020-12-03 18:15:20. 621'.NULL.'gry'.'ccc'
	)
Copy the code

The interior of the CreateInBatches method is sliced using for rather than Goroutine.

Read Selete

Querying a Single object

Gorm provides First, Take, and Last methods. They are all implemented by LIMIT 1, primary key ascending, unsorted, and primary key descending, respectively.

user := User{}

// Get the first record (primary key ascending order)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;

// Get a record without specifying the sort field
db.Take(&user)
// SELECT * FROM users LIMIT 1;

// Get the last record (primary key descending order)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
Copy the code

If no object is found, an ErrRecordNotFound error is returned.

result := db.First(&user)
errors.Is(result.Error, gorm.ErrRecordNotFound)
result.RowsAffected
Copy the code

Query by primary key

Set the second argument, which is treated as ID, in the First/Take/Last functions. The value can be an int or string.

db.First(&user, 10)

db.First(&user, "10")
Copy the code

When selecting variables of type string, be aware of SQL injection issues.

Querying multiple objects (lists)

Use the Find method to query multiple objects.

users := []User{}
result := db.Find(&users)
Copy the code

The return value is mapped to the Users slice.

You can still get the exception and the affected line number by accessing the Error and RowsAffected fields on the return value.

result.Error
result.RowsAffected
Copy the code

Set the search condition Where

Gorm provides a universal Where method, can implement =, <>, IN, LIKE, AND, >, <, BETWEEN, etc., using? As placeholders.

db.Where("name = ?"."l").First(&user)
// SELECT * FROM users WHERE user_name = 'l' ORDER BY id LIMIT 1;

// Get all matched records
db.Where("name <> ?"."l").Find(&users)
// SELECT * FROM users WHERE user_name <> 'l';

// IN
db.Where("name IN ?"And []string{"lzq"."qqq"}).Find(&users)
// SELECT * FROM users WHERE user_name IN ('lzq','qqq');

// LIKE
db.Where("name LIKE ?"."%l%").Find(&users)
// SELECT * FROM users WHERE user_name LIKE '%l%';

// AND
db.Where("name = ? AND age = ?"."lzq"."aaa").Find(&users)
// SELECT * FROM users WHERE user_name = 'lzq' AND password = aaa;

// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2020-11-01 00:00:00' AND '2020-11-08 00:00:00';
Copy the code

Where a method for quickly setting conditions

When passing structs, maps, and slices, it is easier to set conditions.

db.Where(&User{UserName:"lzq", Password:"aaa"}).Find(&user)
db.Where(map[string]interface{} {"user_name": "lzq"."password": "aaa"}).Find(&user)
Copy the code

Structures and maps have almost equal effects.

SELECT
	*
FROM
	`users`
WHERE
	`users`.`user_name` = 'lzq'
	AND `users`.`password` = 'aaa'
	AND `users`.`deleted_at` IS NULL
Copy the code

The only difference is that zero-valued fields in structs are not queried. Such as 0, “”, false.

Slicing is the query primary key.

db.Where([]int{10.11}).Find(&user)
Copy the code

Equivalent to the following SQL.

SELECT
	*
FROM
	`users`
WHERE
	`users`.`id` IN ( 10.11 )
	AND `users`.`deleted_at` IS NULL
Copy the code

For all queries, GORM sets tabel.deleted_at to NULL by default.

In addition to the Where method, there are inline queries, but using both styles is not recommended.

db.Find(&user, "user_name = ?"."lzq")
// SELECT * FROM users WHERE user_name = "lzq";
Copy the code

Other queries Not & Or

Gorm also provides Not and Or methods, but it’s Not recommended because Where can do both, and memorizing additional apis is a mental burden.

db.Where("password = ?"."aaa").Not("user_name"."l").Or("id > ?".10).Find(&users)
Copy the code

Equivalent to the following SQL.

SELECT * FROM `users` WHERE (( PASSWORD = 'aaa' )
	AND `user_name` <> 108
	OR id > 10
)
AND `users`.`deleted_at` IS NULL
Copy the code

Select the specific field Select

Use the Select method.

db.Select("password").Where(&User{UserName:"lzq"}).Find(&user)
Copy the code

Equivalent to the following SQL.

SELECT
	`password`
FROM
	`users`
WHERE
	`users`.`user_name` = 'lzq'
	AND `users`.`deleted_at` IS NULL
Copy the code

Other operating

The sorting Order

db.Order("user_name desc, password").Find(&users)
Copy the code

Equivalent to the following SQL.

SELECT
	*
FROM
	`users`
WHERE
	`users`.`deleted_at` IS NULL
ORDER BY
	user_name DESC,
PASSWORD
Copy the code

Paging Limit Offset

Limit and Offset can be used individually or in combination.

db.Limit(3).Find(&users)
db.Offset(3).Find(&users)

db.Limit(2).Offset(3).Find(&users)
Copy the code

Equivalent to the following SQL.

SELECT
	*
FROM
	`users`
WHERE
	`users`.`deleted_at` IS NULL
	LIMIT 2 OFFSET 3
Copy the code

Group Group Having

Count the number of duplicate user names based on username.

result := []map[string]interface{}{}
db.Model(&User{}).
  Select("user_name, SUM( id ) AS nums").
  Group("user_name").
  Find(&result)
Copy the code

Equivalent to the following SQL.

SELECT
	user_name,
	SUM( id ) AS nums
FROM
	users
GROUP BY
	user_name;
Copy the code

To heavy Distinct

result := []string{}
db.Model(&User{}).
  Distinct("user_name").
  Find(&result)
Copy the code

Equivalent to the following SQL.

SELECT DISTINCT
	user_name
FROM
	users
Copy the code

Even the table Join

It is not recommended to use joins in business, but to use multiple queries to associate multiple tables.

Update data

Update all fields

Update all fields, even zero values, with the Save method.

db.First(&user)
user.UserName = ""
db.Save(&user)
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `created_at` = 'the 2020-12-03 15:12:08. 548',
`updated_at` = 'the 2020-12-04 09:17:40. 891',
`deleted_at` = NULL,
`user_name` = ' ',
`password` = 'ddd'
WHERE
	`id` = 1
Copy the code

Update a single

Update a single column using the Model and Update methods.

You can use the structure as the selection criteria and select only the ID.

user.ID = 12
db.Model(&user).Update("user_name"."lzq")
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `user_name` = 'lzq',
`updated_at` = 'the 2020-12-04 09:16:45. 263'
WHERE
	`id` = 12
Copy the code

You can also set an empty structure in the Model, using the Where method to select your own conditions.

db.Model(&User{}).Where("user_name"."gry").Update("user_name"."gry2")
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `user_name` = 'gry2',
`updated_at` = 'the 2020-12-04 09:21:17. 043'
WHERE
	`user_name` = 'gry'
Copy the code

You can also combine selection criteria.

user.ID = 20
db.Model(&user).Where("username"."gry").Update("password"."123")
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `password` = '123',
`updated_at` = 'the 2020-12-04 09:25:30. 872'
WHERE
	`username` = 'gry'
	AND `id` = 20
Copy the code

Update more columns

Update multiple columns using the Updates method. Support for struct and map updates. When the update condition is struct, the zero value is not updated. If a column is guaranteed to be updated, use Select to Select that column.

Update selected field Selete Omit

Use Select and Omit methods.

Batch update

If the ID is not set in the Model, the default is batch updates.

Delete data

To delete a single

Delete a single piece of data using the Delete method. The ID must be specified; otherwise, the system will delete the data in batches.

user.ID = 20
db.Delete(&user)
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `deleted_at` = 'the 2020-12-04 09:45:32. 389'
WHERE
	`users`.`id` = 20
	AND `users`.`deleted_at` IS NULL
Copy the code

Set delete Conditions

Use the Where method to set the condition.

db.Where("user_name"."lzq").Delete(&user)
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `deleted_at` = 'the 2020-12-04 09:47:30. 544'
WHERE
	`user_name` = 'lzq'
	AND `users`.`deleted_at` IS NULL
Copy the code

Delete by primary key

The second argument can be int, string. You need to pay attention to SQL injection when using strings.

db.Delete(&User{}, 20)
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `deleted_at` = 'the 2020-12-04 09:49:05. 161'
WHERE
	`users`.`id` = 20
	AND `users`.`deleted_at` IS NULL
Copy the code

You can also use slices []int, []string for batch deletion by ID.

db.Delete(&User{}, []string{"21"."22"."23"})
Copy the code

Equivalent to the following SQL.

UPDATE `users`
SET `deleted_at` = 'the 2020-12-04 09:50:38. 46'
WHERE
	`users`.`id` IN ( '21'.'22'.'23' )
	AND `users`.`deleted_at` IS NULL
Copy the code

Batch delete

Empty structures are batch deleted.

Soft delete (logical delete)

If the structure contains the gorm.DeletedAt field, the soft delete capability is automatically acquired.

When all Delete methods are called, they automatically become update statements.

UPDATE users SET deleted_at="The 2020-12-04 09:40"WHERE id = 31;
Copy the code

The soft deleted data is automatically ignored during query.

SELECT * FROM users WHERE user_name = 'gry' AND deleted_at IS NULL;
Copy the code

Example Query soft delete data

Use the Unscoped method to find soft deleted data.

db.Unscoped().Where("user_name = gry").Find(&users)
Copy the code

Permanent delete (hard delete Physical delete)

Permanently delete data using the Unscoped method.

user.ID = 14
db.Unscoped().Delete(&user)
Copy the code

Native SQL

In addition to the encapsulation method above, GORM also provides the ability to execute native SQL.

Execute the SQL and map the results to variables

Use the Raw method and Scan method.

A single piece of data can be queried and scanned and mapped to a structure or map.

db.
  Raw("SELECT id, record_id, user_name, password FROM users WHERE id = ?".25).
  Scan(&user)
Copy the code

You can also map to other types.

var userCount int
db.
  Raw("SELECT count(id) FROM users").
  Scan(&userCount)
Copy the code

If the returned result does not match the type of the mapping variable passed in, the value of the variable will not change.

Only SQL is executed without results

Use the Exec method to execute SQL.

db.Exec("UPDATE users SET password=? WHERE id = ?"."abcdefg".22)
Copy the code

The Hook Hook

Gorm provides Hook functionality. Some logic can be executed automatically before and after creation, query, update, and delete.

create

Gorm provides four create hooks, BeforeCreate, AfterCreate and BeforeSave, AfterSave.

Suppose you now want to add a RecordID and generate a 16-bit UUID each time you create it.

type User struct {
	gorm.Model
	RecordID string
	UserName string
	Password string
}
Copy the code

In addition, you want to print the generated UUID before storage and the created ID after storage.

This is done by adding BeforeCreate and AfterCreate methods to the User model structure.

func (u *User) BeforeCreate(tx *gorm.DB) error {
	u.RecordID = uuid.New().String()
	fmt.Println("When creating User, UUID is:", u.RecordID)
	return nil
}

func (u *User) AfterCreate(tx *gorm.DB) error {
	fmt.Println("User created, ID = :", u.ID)
	return nil
}
Copy the code

update

Update hooks are BeforeUpdate, AfterUpdate and BeforeSave, AfterSave, used the same as create.

The query

The Hook for a query is AfterFind, and the usage is consistent with the creation.

delete

Delete hooks are BeforeDelete and AfterDelete, which are used the same as create.

All hooks except query hooks run on transactions, which are rolled back when an error is returned in a function.

Xi. Business

Transactions guarantee transaction consistency, but reduce some performance. Gorm creation, modification, and deletion are all performed in transactions.

If not, you can disable transactions at initialization, which can improve performance by about 30%.

Globally closed transaction

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  SkipDefaultTransaction: true,})Copy the code

The session level closes the transaction

tx := db.Session(&Session{SkipDefaultTransaction: true})
// Use tx objects to continue SQL execution
tx.First(&user)
Copy the code

Execute SQL in a transaction

Suppose you now want to add a company table to store company information and create a Company_Users table to associate information about users and companies.

// Create a structure
type Company struct {
	gorm.Model
	RecordID string
	Name     string
}

type CompanyUser struct {
	gorm.Model
	RecordID  string
	UserID    string
	CompanyID string
}

// Automatic migration
db.AutoMigrate(&Company{})
db.AutoMigrate(&CompanyUser{})

// Create a company
company := Company{Name: "gxt"}
company.RecordID = uuid.New().String()
db.Save(&company)

// Execute in transaction
db.Transaction(func(tx *gorm.DB) error {
    // Create a user
    u := User{UserName: "ztg", Password: "333"}
    result := tx.Create(&u)
    iferr := result.Error; err ! =nil {
        return err
    }
    // Query the company information
    company2 := Company{}
    tx.First(&company2, company.ID)
    // Associate the user with the company
    result = tx.Create(&CompanyUser{UserID: u.RecordID, CompanyID: company2.RecordID})
    iferr := result.Error; err ! =nil {
        return err
    }
    return nil
})
Copy the code

Xii. Journal

Gorm implements a Logger by default, which outputs only slow SQL.

newLogger := logger.New(
    log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
    logger.Config{
        SlowThreshold: time.Second, // Slow SQL threshold
        LogLevel:      logger.Info, // Log level
        Colorful:      false.// Disable color printing},)Copy the code

The log level can be set to Silent, Error, Warn, and Info.

Global Mode on

db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  Logger: newLogger,
})
Copy the code

Enable session mode

tx := db.Session(&Session{Logger: newLogger})
Copy the code

Custom Logger

Gorm provides an Interface Interface that you can implement to customize loggers.

type Interface interface {
	LogMode(LogLevel) Interface
	Info(context.Context, string.interface{})
	Warn(context.Context, string.interface{})
	Error(context.Context, string.interface{})
	Trace(ctx context.Context, begin time.Time, fc func(a) (string.int64).err error)
}
Copy the code