This is the 25th day of my participation in the August Challenge

Introduction to the

The relational database mysql is very popular, and has been for many years. It is still a solid number two in DB-Engines’ rankings, down from last year, but still very popular.

Leaderboard portal: db-engines.com/en/ranking

The installation

Quick installation with Docker, past portal: juejin.cn/post/684490…

Install mysql5.7 and set root password to 6 sixes

docker run --name mysql -e MYSQL_ROOT_PASSWORD=666666 -d -p 3306:3306 mysql:5.7
Copy the code

UI Tools bloggers use a free lightweight tool HeidiSQL: www.heidisql.com/

HeidiSQL also has the following image

If you like to use VScode, you can also install the mysql plugin directly in VScode and write SQL in VScode

The client

The go official package does not provide a database driver, but defines some standard interfaces for developing databases

We need to use third-party packages to operate mysql database. But the third party package is numerous, the most popular is: github.com/go-sql-driv…

There is also a database/ SQL extension based on the official, also very popular, portal: github.com/jmoiron/sql…

It is possible to use both packages interchangeably in this article, or to use only one without guarantee

Of course, some well-known ORM frameworks (GORM,XORM, GorOSE) are not mentioned here

API example

Initialize the

The client is defined as a global switch to facilitate subsequent use

Define a set of mysql configuration variables, and then initialize the connection

You need to create the test library before initializing the connection

var (
   UserName  string = "root"
   PassWord  string = "666666"
   IP string = "ip"
   Port int = 3306
   DbName string = "test"
   CharSet string = "utf8mb4"
   
   Db *sql.DB
   err error
)

func init() {
   dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s? charset=%s", UserName, PassWord, IP, Port, DbName, CharSet)
   Db, err = sql.Open("mysql", dsn)
   iferr ! = nil { log.Fatalln(Failed to connect to mysql:,err)
   }
}
Copy the code

Create a table

Create a user information table with primary key id and increment by 1

func createTable() {
   sql: =` create table user_info( id bigint unsigned not null auto_increment, Name varchar(100) NOT NULL DEFAULT "COMMENT", email varchar(50) NOT NULL DEFAULT "COMMENT", Age int(11) NOT NULL DEFAULT '0' COMMENT 'age ', primary key (id) ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4; `
   result, err := Db.Exec(sql)
   iferr ! = nil { log.Println(Table creation failed:,err)
   }
   log.Println(result.RowsAffected())
   log.Println(result.LastInsertId())
}
Copy the code

Insert data

Write a little loop and write 100 pieces of data

func insertData() {
   for i:=1; i<100; i++ { result,_ := Db.Exec("insert into user_info (name,age) value (? ,?) "."zhangsan" + strconv.Itoa(i),18+i)
      log.Println(result.LastInsertId())
   }
}
Copy the code

Query data

Define the structure in advance

Specify id to query a piece of data

Call the QueryRow method to return a result based on the query criteria

type UserInfo struct {
   Id  int
   Name string
   email string
   age int
}

func selectData() {
   var u UserInfo
   sqlStr: ="select id,name,age from user_info where id=?"
   _ = Db.QueryRow(sqlStr, 2).Scan(&u.Id, &u.Name, &u.age)
   fmt.Println(u.Id,u.Name,u.age)
}
Copy the code

Querying multiple pieces of Data

Call the Query method, return a result set, and loop through the output

sqlStr2 := "select id,name,age from user_info where id > ?"
rows, _ := Db.Query(sqlStr2, 0)
// The function closes the connection
defer rows.Close()

for rows.Next(){
   var u UserInfo
   _ = rows.Scan(&u.Id, &u.Name, &u.age)
   fmt.Println(u.Id,u.Name,u.age)
}
Copy the code

Update the data

Update the data whose ID1 is to change the age value to 18

func updateData() {
   sqlStr: ="update user_info set age=? where id = ?"
   exec, _ := Db.Exec(sqlStr, 18.1)
   fmt.Println(exec.RowsAffected())
}
Copy the code

Delete the data

Delete data with id 5, because id is increment, so only one data should be deleted

You can see from the RowsAffected method return how many pieces of data are affected

func deleteData() {
   sqlStr: ="delete user_info user where id = ?"
   exec, _ := Db.Exec(sqlStr, 5)
   fmt.Println(exec.RowsAffected())
}
Copy the code

Check the type

View the table database and GO language types

func columnType() {
   sqlStr: ="select * from user_info"
   query, _ := Db.Query(sqlStr)
   columns, _ := query.ColumnTypes()
   for _,column := range columns {
      fmt.Printf("Field name: %v, database type: %v,GO language mapping type: %v\n",column.Name(),column.DatabaseTypeName(),column.ScanType())
   }
}
Copy the code

Methods to summarize

  • Db.query Executes a Query and returns a value with a result, usually a SELECT
  • Db.exce executes commands that do not return the value of the result, usually update, delete, etc
  • Rows.next () iterates over the query data
  • Rows.scan () reads the value of each row
  • QueryRow queries and returns a row of data

Mysql transaction

The following theories come from the Internet

A transaction is the smallest non-divisible unit of work, usually one transaction for a complete business

Classic transaction cases take the example of a bank transfer, characterized by either success or failure and no other state

The database engine used in mysql is InnoDB, because it supports transactions

The transaction of the ACID

  • Atomicity All operations in a transaction either complete or do not complete, and do not end up somewhere in between. If a transaction fails during execution, it will be rolled back to the state before the transaction began, as if the transaction had never been executed

  • Consistency Database integrity is not compromised before and after a transaction. This means that the data written must conform to all the preset rules, including the accuracy of the data, the concatenation of the data, and the ability of the subsequent database to do its predetermined work spontaneously

  • Isolation The ability of a database to allow multiple concurrent transactions to read, write and modify its data at the same time. Isolation prevents data inconsistencies due to cross-execution when multiple transactions are executed concurrently. Transaction isolation can be divided into different levels, including Read uncommitted, Read Committed, Repeatable Read and Serializable.

  • After a persistent transaction, changes to the data are permanent and will not be lost even if the system fails

There are various isolation levels, as shown in the following figure —-. The image is from the network

Transaction example

This example does two transactions, one successful completion and one rollback

func transaction() {
   // Clear the user_info table
   sqlStr: ="truncate table user_info;"
   Db.Exec(sqlStr)

   sqlStr2: ="insert into user_info(name,age) values (? ,?) "
   tx1, _ := Db.Begin()
   result, _ := tx1.Exec(sqlStr2, "zhangsan17".17)
   fmt.Println(result.RowsAffected())
   fmt.Println(result.LastInsertId())
   tx1.Commit()

   tx2, _ := Db.Begin()
   result2, _ := tx2.Exec(sqlStr2, "zhangsan16".16)
   fmt.Println(result2.RowsAffected())
   fmt.Println(result2.LastInsertId())
   tx2.Rollback()

   sqlStr3: ="select id,name,age from user_info"
   result3, _ := Db.Query(sqlStr3)
   for result3.Next(){
      var u UserInfo
      _ = result3.Scan(&u.Id, &u.Name, &u.age)
      fmt.Println(u.Id,u.Name,u.age)
   }
}
Copy the code

conclusion

Go-sql-driver /mysql is actually based on the official database/ SQL enhancement package, example in most SQL statements are manual, if using ORM package, basically are method chain operation

For small projects, direct use of this package is small in size and fast in interaction