golang Gorm orm & org sqllite

install sqlite3

code
go get -u github.com/mattn/go-sqlite3
http://tw.gitbook.net/sqlite/sqlite_create_database.html

create sqlite3 database

code
CREATE TABLE `userinfo` (
    `uid` INTEGER PRIMARY KEY AUTOINCREMENT,
    `username` VARCHAR(64) NULL,
    `department` VARCHAR(64) NULL,
    `created` DATE NULL
);

CREATE TABLE `userdetail` (
    `uid` INT(10) NULL,
    `intro` TEXT NULL,
    `profile` TEXT NULL,
    PRIMARY KEY (`uid`)
);

code
func main() {
        http.HandleFunc("/endpoint-2", handler2)
}
func handler2(w http.ResponseWriter, r *http.Request) {
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    fmt.Println("all nowgoroutine :", runtime.NumGoroutine())
    go func() {
        // Block until there are fewer than cap(smallPool) hard-work
        // goroutines running.
        smallPool <- struct{}{}
        defer func() { <-smallPool }() // Let everyone that we are done
        fmt.Println("working!")
        time.Sleep(5 * time.Second)

        fmt.Println("work done")
        processImage(b)
    }()
    // w.WriteHeader(http.StatusAccepted)
    a += 1
    // time.Sleep(2 * time.Second)

    if runtime.NumGoroutine() < 20 {

        db, err := sql.Open("sqlite3", "./foo.db")
        checkErr(err)
        rows, err := db.Query("SELECT * FROM userinfo")
        checkErr(err)
        var output string = ""
        for rows.Next() {
            var uid int
            var username string
            var department string
            var created time.Time
            err = rows.Scan(&uid, &username, &department, &created)
            checkErr(err)
            output += strconv.Itoa(uid) + "|" + username + "|" + department + "|" + created.Format("2006-01-02 15:04:05") + "\n"
        }

        w.Write([]byte(output))
        w.WriteHeader(http.StatusAccepted)
        db.Close()
    } else {
        // w.Write([]byte("pleass wait" + strconv.Itoa(a)))
        w.WriteHeader(http.StatusNotFound)
        return
        // http.ErrUseLastResponse
    }

}

orm

https://blog.csdn.net/cnwyt/article/details/118904882

code
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
code
func main (){
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    // Migrate the schema
    db.AutoMigrate(&Product{})

    // 插入內容
    db.Create(&Product{Title: "新款手機", Code: "D42", Price: 1000})
    db.Create(&Product{Title: "新款電腦", Code: "D43", Price: 3500})

    // 讀取內容
    var product Product
    db.First(&product, 1)                 // find product with integer primary key
    db.First(&product, "code = ?", "D42") // find product with code D42
    fmt.Println("%v", product)
    // 更新操作: 更新單個字段
    db.Model(&product).Update("Price", 2000)

    // 更新操作: 更新多個字段
    db.Model(&product).Updates(Product{Price: 2000, Code: "F42"}) // non-zero fields
    db.Model(&product).Updates(map[string]interface{}{"Price": 2000, "Code": "F42"})

    // 刪除操作:
    db.Delete(&product, 1) 
}

sql pool & http pool

https://codertw.com/%E4%BC%BA%E6%9C%8D%E5%99%A8/154458/ https://gorm.io/docs/connecting_to_the_database.html 實際上在經過查詢可以發現,預設的http 或者 sql 其實底層都是goroutines,則我們也不用像以前的程式去寫 pool 之類的我們只要全局的去宣告就好 global variable

code
func connDB(lifeTime int, maxCon int, idle int) *gorm.DB {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }
    sqlDB, err := db.DB()
    if err != nil {
        panic(err)
    }

    sqlDB.SetConnMaxLifetime(time.Duration(lifeTime) * time.Second) // 每條連線的存活時間
    sqlDB.SetMaxOpenConns(maxCon)                                   // 最大連線數
    sqlDB.SetMaxIdleConns(idle)                                     // 最大閒置連線數
    return db
}

func init() {
    DBConn = connDB(1, 200, 10)

    // Migrate the schema
    DBConn.AutoMigrate(&Product{})

    // 插入內容
    DBConn.Create(&Product{Title: "新款手機", Code: "D42", Price: 1000})
    DBConn.Create(&Product{Title: "新款電腦", Code: "D43", Price: 3500})

    // 讀取內容
    var product Product
    DBConn.First(&product, 1)                 // find product with integer primary key
    DBConn.First(&product, "code = ?", "D42") // find product with code D42
    fmt.Println("%v", product)
    // 更新操作: 更新單個字段
    DBConn.Model(&product).Update("Price", 2000)

    // 更新操作: 更新多個字段
    DBConn.Model(&product).Updates(Product{Price: 2000, Code: "F42"}) // non-zero fields
    DBConn.Model(&product).Updates(map[string]interface{}{"Price": 2000, "Code": "F42"})

    // 刪除操作:
    DBConn.Delete(&product, 1)
}
func main (){
        http.HandleFunc("/endpoint-2", handler2)

}

func handler2(w http.ResponseWriter, r *http.Request) {
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    fmt.Println("all nowgoroutine :", runtime.NumGoroutine())
    go func() {
        // Block until there are fewer than cap(smallPool) hard-work
        // goroutines running.
        smallPool <- struct{}{}
        defer func() { <-smallPool }() // Let everyone that we are done
        fmt.Println("working!")
        time.Sleep(5 * time.Second)

        fmt.Println("work done")
        processImage(b)
    }()
    // w.WriteHeader(http.StatusAccepted)
    a += 1
    // time.Sleep(2 * time.Second)

    if runtime.NumGoroutine() < 20 {

        // 讀取內容
        var product Product
        DBConn.First(&product, 1)                 // find product with integer primary key
        DBConn.First(&product, "code = ?", "D42") // find product with code D42
        fmt.Println("%v", product)
        // 更新操作: 更新單個字段
        DBConn.Model(&product).Update("Price", 2000)
        b, err := json.Marshal(product)
        if err != nil {
            fmt.Println(err)
            return
        }

        w.Write([]byte(string(b)))
        w.WriteHeader(http.StatusAccepted)
        // db.Close()
    } else {
        // w.Write([]byte("pleass wait" + strconv.Itoa(a)))
        w.WriteHeader(http.StatusNotFound)
        return
        // http.ErrUseLastResponse
    }

}

這樣我們的grom 就可以有pool 了 https://ithelp.ithome.com.tw/articles/10238565

http request 阻塞(?

預設 golang 的 http 都是非阻塞,原因就是chrome or edge 會將當前頁面去做緩存之類的東西,所以假設同一個畫面不同分頁可能會出現順序返回,但是實際上是瀏覽器的關係,每一個request 都是 一個Goroutine則 下面畫面是同時訪問http://localhost:8080/endpoint-2 但是在同一個瀏覽器的畫面,可以看到右邊會有出現阻塞現象 下面是一個edge 和 chrome 同時訪問可以看到時間戳相差不遠