<p>Hi</p>
<p>I would like to ear your suggestions regarding the way i implement my db access. I surely think there is a better way to do this as my current solution is proving to be quite difficult to manage and audit this part of the code.</p>
<p>So... here's how i currently implement the database access.</p>
<p>In main.go
package main</p>
<pre><code>import "models/user"
var user models.User
func init(){
user.InitStatements()
}
</code></pre>
<p>Then in models/user.go i have for each query something like this</p>
<pre><code>package models
const qSelectByID string = "SELECT * FROM users WHERE id=$1"
type User struct {
statements userStatements
}
type userStatements struct {
selectByID *sqlx.Stmt
}
func (u *User) InitStatements() {
var (
wg sync.WaitGroup
// Selects
selectByID *sqlx.Stmt
)
wg.Add(1)
go func() {
defer wg.Done()
var err error
selectByID, err = db.Preparex(qSelectByID)
if err != nil {
log.WithFields(log.Fields{
"query": qSelectByID,
"err": err,
}).Error("Error preparing selectByID")
}
}()
wg.Wait()
u.statements.selectByID = selectByID
}
//Then i have my Model implementation bellow, where i use the statements above and the data and error management
</code></pre>
<p>Thanks!</p>
<p>EDIT: fix wg.Add</p>
<hr/>**评论:**<br/><br/>redditter15: <pre><p>Basically you are not applying the <a href="https://en.wikipedia.org/wiki/KISS_principle" rel="nofollow">Keep it Simple Stupid principle</a>.</p>
<p>Get rid of the goroutine, it is not needed when you do not have at least 2 tasks at the same time.</p>
<p>Also, don't use prepared statement if you are not going to do batch inserts. If I remember well, PostgreSQL won't even otimize the query (by using prepared statements) unless you have a given number of executions per second.</p></pre>metamatic: <pre><p>Also, <a href="https://www.reddit.com/r/golang/comments/4v5rs0/should_simple_db_statements_be_prepared_at/" rel="nofollow">check out this recent thread</a> -- the SQL statements you are carefully preparing might get invalidated by Go's management of the SQL connection pool. You shouldn't try to keep prepared statements around for the lifetime of a long-lived application.</p></pre>grutoc: <pre><p>To answer this issue, I went for:</p>
<pre><code>type UserOP struct {
Exec func(*User) error
Close func()
}
func SelectUserByID(db sql.DB) (*UserOP, error) {
stmt, err := db.Prepare("SELECT...")
if err != nil {
return nil, err
}
return &UserOP{
Exec: func(u *User) error {
res, err := stmt.Exec(u.ID)
if err != nil {
return err
}
return nil
},
Close: func() {
stmt.Close()
},
}, nil
}
</code></pre></pre>toolateforTeddy: <pre><p>Well for one, why are you even luanching a goroutine here? This is single threaded code that you have shoved an extra thread into, and then continued to force it to be single threaded.</p>
<p>Additionally, you Add(5) to the waitgroup, but only call .Done() once, so your .Wait() at the end will never return. You have deadlocked.</p></pre>norwat: <pre><p>Yeah the go routine part was only for performance issues kinda i just wanted the initStatements part to be faster so i tried to make as parallel as possible , it doesn't really need to be there </p>
<p>The Add(5) its from the original code i forgot to edit that part out sorry</p>
<p>Overall, is it a good solution?</p></pre>KenjiTakahashi: <pre><p>The way it is now, it won't be any faster, though. If anything, it will be slower, because it will have to take the time to spawn a goroutine.</p></pre>