Il giorno venerdì 5 gennaio 2018 16:57:04 UTC+1, Ayan George ha scritto:
>
>
>
> On 01/05/2018 10:16 AM, Manlio Perillo wrote: 
> > Recently I have developed a few web applications in Go, using a 
> > PostgreSQL database, but I have yet understand the best way to use 
> > the database/sql package. 
> > 
>
> I don't know how you're serving web pages but I typically use net/http. 
> This also means that I typically build an http.Server.  This requires 
> that I create a type that conforms to the http.Handler interface. 
>

Yes, I use the standard net/http interface, without frameworks (but I use a 
simple toolkit written by me).

>
> You can use this type to pass around all of the data you need, including 
> sql.DB instances, log.Logger, etc. 
>
> So here's the skeleton of what I normally do.  I haven't tested this -- 
> this is just to get the point across.  Finally, this may be completely 
> off base.  I'm open to any criticisms etc. anyone may have. 
>
> package main 
>
> import ( 
>   "database/sql" 
>   _ "github.com/lib/pq" 
>   "log" 
>   "net/http" 
>   "time" 
> ) 
>
> type app struct { 
>   db *sql.DB 
> } 
>
> func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
>   // here we can use all of the fields of our app struct -- including 
> the db! 
>
>   row := db.QueryRow("select current_timestamp;") 
>
>   var time string 
>   err := row.Scan(&time) 
>
>   if err != nil { 
>     // handle the error.  maybe log it?  i typically 
>     // create a log.Logger instance in my app and use it 
>     // at times like these. 
>     return 
>   } 
>
>   w.Write([]byte("<h1>hello, world!</h1>")) 
> } 
>
> func main() { 
>   db, err := sql.Open("postgres", "...") 
>
>   if err != nil { 
>     log.Fatal(err) 
>   } 
>
>   if err := db.Ping(); err != nil { 
>     log.Fatal(err) 
>   } 
>
>   myapp := app{ 
>     db: db, 
>   } 
>
>   srv := http.Server{ 
>     Addr:         ":8080", 
>     ReadTimeout:  1 * time.Second, 
>     WriteTimeout: 1 * time.Second, 
>     Handler:      &myapp, 
>   } 
>
>   log.Fatal(srv.ListenAndServe()) 
> } 
>

Thanks, this is  a very good solution.

Currently I'm using something different, however.
I have a package that exports the same API as database/sql, but as free 
functions using a global *DB configured when loading a configuration file.

However the question is the same, and it is how and what to pass to 
functions that need a connection to the database.

Passing *DB is no good; take as an example a "generic" package having

  type Table struct {
      A int
      B string
  }

  func SaveTable(t *Table, db *DB) ...

or
  func SaveTable(t *Table, tx *Tx) ...

The function does not need to know if it is inside a transaction; it is the 
responsibility of the caller.

However consider a package with

  type Table struct {
      A int
      B string
  }

  type OtherTable struct {
      Table
      C float64
      B bool
  }


Now the function SaveOtherTable may want to use a transaction to save Table 
and OtherTable separately.
You surely can not pass a *Tx, since it does not support nested 
transactions.



Thanks
Manlio Perillo


-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to