I use Gorm for Golang like this code,
func Connect() (*gorm.DB, error) {
var (
err error
db *gorm.DB
)
dsn := "sqlserver://User:12345#127.0.0.1:1433?database=gorm"
db, err = gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
err = db.Debug().AutoMigrate(&models.CompanyName{}, &models.CarModel{}, &models.CreateYear{}, &models.Diversity{})
if err != nil {
return nil, err
}
return db, nil
}
and in main.go
func main() {
db, err := Connect()
if err != nil {
panic("database connection failed")
}
ech := echo.New()
}
Ok in the first time when we run code, gorm create tables in database,but in the second time I got an error thet
mssql: There is already an object named 'table_names' in the database.
Do I have to delete db.Debug().AutoMigrate)(?
Related
Let's assume that I want to make a client, for example, MySQL client (but my question is generic and not just for MySQL client, any client), this is a sample code
func main() {
db, err := sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
defer db.Close()
}
I want to move it into a function so I don't have to initialize it all over the place and here my question begins I can do it in various ways and I want to know which one is the recommended way
Here is functional way
func client() (client *sql.DB, err error) {
client, err = sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
return
}
Global variable way
var client, err = sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
init func way
var Client *sql.DB
func init() {
Client, err := sql.Open("mysql", "root:root#tcp(localhost:3306)/otp")
if err != nil {
panic(err.Error())
}
}
and finally struct way
type MSQL struct {
// Fields...
}
func (m *MSQL) Client() *sql.DB {
client, err := sql.Open("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
if err != nil {
panic(err.Error())
}
return client
}
// NewMysql().where(...)
I'm really confused here to select which one to follow
Exposing a public variable var Client *sql.DB is error prone as I can do <package>.Client = null from anywhere.
struct way is the way to go, As you can work with multiple connection each to a specific database at any time.
You can also use New() to pass in a config object or other props to customise other db props. like Max Connection.
package database;
type Db struct{
*db sql.DB
}
func New(driver, connection string) *Db {
db, err := sql.Open(driver, connection)
if err != nil {
panic(err)
}
if err = db.Ping(); err != nil {
panic(err)
}
/* configure details
db.SetConnMaxLifetime(conLifeTime)
db.SetMaxOpenConns(maxOpenConns)
db.SetMaxIdleConns(maxIdleConns)
*/
return &Db{db}
}
func (d *Db) Close() error {
return d.db.Close();
}
Its generic, you can pass any driver & connection string for creating a connection to any database.
connection database.New("mysql", "root:<yourMySQLdatabasepassword>#tcp(127.0.0.1:3306)/test")
usage database.Db.Where(...)
close connection database.Db.Close()
Im newbie in Golang, so it may be simple for professionals but I got stuck with no idea what to do next.
I'm making some migration app that extract some data from oracle DB and after some conversion insert it to Postges one-by-one.
The result of native Query in DB console returns about 400k of rows and takes about 13 sec to end.
The data from Oracle extracts with rows.Next() with some strange behavior:
First 25 rows extracted fast enough, then about few sec paused, then new 25 rows until it pauses "forever".
Here is the function:
func GetHrTicketsFromOra() (*sql.Rows, error) {
rows, err := oraDB.Query("select id,STATE_ID,REMEDY_ID,HEADER,CREATE_DATE,TEXT,SOLUTION,SOLUTION_USER_LOGIN,LAST_SOLUTION_DATE from TICKET where SOLUTION_GROUP_ID = 5549")
if err != nil {
println("Error while getting rows from Ora")
return nil, err
}
log.Println("Finished legacy tickets export")
return rows, err
}
And here I export data:
func ConvertRows(rows *sql.Rows, c chan util.ArchTicket, m chan int) error {
log.Println("Conversion start")
defer func(rows *sql.Rows) {
err := rows.Close()
if err != nil {
log.Println("ORA connection closed", err)
return
}
}(rows)
for rows.Next() {
log.Println("Reading the ticket")
ot := util.OraTicket{}
at := util.ArchTicket{}
err := rows.Scan(&ot.ID, &ot.StateId, &ot.RemedyId, &ot.Header, &ot.CreateDate, &ot.Text, &ot.Solution, &ot.SolutionUserLogin, &ot.LastSolutionDate)
if err != nil {
log.Println("Error while reading row", err)
return err
}
at = convertLegTOArch(ot)
c <- at
}
if err := rows.Err(); err != nil {
log.Println("Error while reading row", err)
return err
}
m <- 1
return nil
}
UPD. I use "github.com/sijms/go-ora/v2" driver
UPD2. Seems like the root cause of the problem is in TEXT and SOLUTION fields of the result rows. They are varchar and can be big enough. Deleting them from the direct query changes the time of execution from 13sec to 258ms. But I still have no idea what to do with that.
UPD3.
Minimal reproducible example
package main
import (
"database/sql"
_ "github.com/sijms/go-ora/v2"
"log"
)
var oraDB *sql.DB
var con = "oracle://login:password#ora_db:1521/database"
func InitOraDB(dataSourceName string) error {
var err error
oraDB, err = sql.Open("oracle", dataSourceName)
if err != nil {
return err
}
return oraDB.Ping()
}
func GetHrTicketsFromOra() {
var ot string
rows, err := oraDB.Query("select TEXT from TICKET where SOLUTION_GROUP_ID = 5549")
if err != nil {
println("Error while getting rows from Ora")
}
for rows.Next() {
log.Println("Reading the ticket")
err := rows.Scan(&ot)
if err != nil {
log.Println("Reading failed", err)
}
log.Println("Read:")
}
log.Println("Finished legacy tickets export")
}
func main() {
err := InitOraDB(con)
if err != nil {
log.Println("Error connection Ora")
}
GetHrTicketsFromOra()
}
I would like to import package and create new struct in main() func.
// main.go
import "testapp/app"
a := app.GetApp()
db, err := a.ConnectDatabase()
if err != nil {
panic(err.Error())
}
// testapp/app.go
func (a *App) ConnectDatabase() {
db, err := sql.Open()
if err != nil {
panic(err.Error())
}
a.db = db
}
I've got error:
app.ConnectDatabase() used as value
How can I fix that?
you might want to solve this like:
// main.go
import "testapp/app"
func main(){
a := app.GetApp()
err := a.ConnectDatabase()
if err != nil {
panic(err.Error())
}
a.db. //interesting db code here
}
// testapp/app.go
func (a *App) ConnectDatabase() error{
db, err := sql.Open()
if err != nil {
return err
}
a.db = db
return nil
}
I am beginner at Go, I had wrote small server to testing and deploy it on heroku platform. I have /logout request, which almost works, but sometimes I see something like this:
PANIC: write tcp 172.17.110.94:36641->10.11.189.195:9951: use of closed network connection
I don't know why it happens, and why sometimes it works perfectly.
My steps:
I send 1st POST request to /token-auth with body then generate token and send as response.
At 2nd I do /logout GET request with that token, and set token to Redis store
Here is full code of my redil_cli.go
package store
import (
"github.com/garyburd/redigo/redis"
)
type RedisCli struct {
conn redis.Conn
}
var instanceRedisCli *RedisCli = nil
func Connect() (conn *RedisCli) {
if instanceRedisCli == nil {
instanceRedisCli = new(RedisCli)
var err error
//this is works!!!
instanceRedisCli.conn, err = redis.Dial("tcp", "lab.redistogo.com:9951")
if err != nil {
panic(err)
}
if _, err := instanceRedisCli.conn.Do("AUTH", "password"); err != nil {
//instanceRedisCli.conn.Close()
panic(err)
}
}
return instanceRedisCli
}
func (redisCli *RedisCli) SetValue(key, value string, expiration ...interface{}) error {
_, err := redisCli.conn.Do("SET", key, value)
if err == nil && expiration != nil {
redisCli.conn.Do("EXPIRE", key, expiration[0])
}
return err
}
func (redisCli *RedisCli) GetValue(key string) (interface{}, error) {
data, err := redisCli.conn.Do("GET", key)
if err != nil{
panic(err)
}
return data, err
}
After that my function that checks Authorization header will panic while trying to do GetValue(key string) method
func (redisCli *RedisCli) GetValue(key string) (interface{}, error) {
data, err := redisCli.conn.Do("GET", key)
if err != nil{
panic(err)
}
return data, err
}
Can anyone point me, what I doing wrong?
I'm trying to understand variable scopes in golang with the following code.
In this example, calling in http a page will echo the uri query combined with a stored value in Boltdb.
The problem is that the database driver doesn't seem to run correctly in the http handler context: it doesn't print anything to stdout nor to the http request.
I was expecting it to print :
He's loving <'uri query content'> but prefers pizza (data from bolt.db driver)
How to fix this code?
package main
import (
"fmt"
"net/http"
"log"
"github.com/boltdb/bolt"
)
var db bolt.DB
func handler(w http.ResponseWriter, r *http.Request) {
dberr := db.Update(func(tx *bolt.Tx) error {
log.Println("here")
b := tx.Bucket([]byte("MyBucket"))
loving := b.Get([]byte("loving"))
log.Printf("He's loving %s but prefers %s",r.URL.Path[1:], string(loving))
fmt.Fprintf(w,"He's loving %s but prefers %s",r.URL.Path[1:], string(loving) )
return nil
})
if dberr != nil {
fmt.Errorf("db update: %s", dberr)
}
log.Printf("Finished handling")
}
func main() {
db, err := bolt.Open("my.db", 0600, nil)
if err != nil {
log.Fatal(err)
}else{
log.Println("database opened")
}
dberr := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
if err != nil {
return fmt.Errorf("create bucket: %s", err)
}
err2 := b.Put([]byte("loving"), []byte("pizza"))
if err2 != nil {
return fmt.Errorf("put loving: %s", err2)
}
loving := b.Get([]byte("loving"))
log.Printf("He's loving %s", string(loving))
return nil
})
if dberr != nil {
fmt.Errorf("db update: %s", err)
}
defer db.Close()
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
I think I see your bug. This one is usually a little difficult to track because its just the : in front of the equals. It was basically a scoping issue because you declared db as a global while at the same time creating a db variable that was scoped to your main function.
You used db, err := ... to assign the values instead of just =. := will both declare and infer the type. Since its also doing declaration, the db you're using in the main function is not the db you have declared in the global scope. Meanwhile the handler is still attempting to use the db that was declared in the global scope. The below code is the same code as you initially had with a few comments in the code to outline what the working changes are. Hope this helps!
package main
import (
"fmt"
"log"
"net/http"
"github.com/boltdb/bolt"
)
var db *bolt.DB // this is going to be a pointer and is going to be nil until its set by the main function
func handler(w http.ResponseWriter, r *http.Request) {
dberr := db.Update(func(tx *bolt.Tx) error {
log.Println("here")
b := tx.Bucket([]byte("MyBucket"))
loving := b.Get([]byte("loving"))
log.Printf("He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
fmt.Fprintf(w, "He's loving %s but prefers %s", r.URL.Path[1:], string(loving))
return nil
})
if dberr != nil {
fmt.Errorf("db update: %s", dberr)
}
log.Printf("Finished handling")
}
func main() {
var err error // this will have to be declared because of the next line to assign db the first value returned from `bolt.Open`
db, err = bolt.Open("my.db", 0600, nil) // notice that this has changed and is no longer `db, err := ...` rather its `db, err = ...`
if err != nil {
log.Fatal(err)
} else {
log.Println("database opened")
}
dberr := db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte("MyBucket"))
if err != nil {
return fmt.Errorf("create bucket: %s", err)
}
err2 := b.Put([]byte("loving"), []byte("pizza"))
if err2 != nil {
return fmt.Errorf("put loving: %s", err2)
}
loving := b.Get([]byte("loving"))
log.Printf("He's loving %s", string(loving))
return nil
})
if dberr != nil {
fmt.Errorf("db update: %s", err)
}
defer db.Close()
http.HandleFunc("/", handler)
http.ListenAndServe(":3000", nil)
}