Explorar o código

fasthttp: use prepared statements

Aliaksandr Valialkin %!s(int64=10) %!d(string=hai) anos
pai
achega
53ce2eaf2b
Modificáronse 1 ficheiros con 31 adicións e 21 borrados
  1. 31 21
      frameworks/Go/fasthttp/src/hello/hello.go

+ 31 - 21
frameworks/Go/fasthttp/src/hello/hello.go

@@ -33,25 +33,17 @@ type Fortune struct {
 
 // Databases
 const (
-	// Go 1.4's sql.DB has scalability problem when using (explicitly reused) prepared statement.
-	// https://github.com/golang/go/issues/9484
-	//
-	// Using db.Query() instead of stmt.Query() avoid the issue.
-	// But it makes 3 round trips per query: prepare, execute and close.
-	// `interpolateParams=true` enables client side parameter interpolation.
-	// It reduces round trips without prepared statement.
-	//
-	// Before Go 1.5 is released, we can see real power of Go with this benchmark.
-	// After Go 1.5 is released, we can see prepared statement vs interpolation by comparing
-	// this and another lightweight Go framework.
 	connectionString   = "benchmarkdbuser:benchmarkdbpass@tcp(localhost:3306)/hello_world?interpolateParams=true"
-	worldSelect        = "SELECT id, randomNumber FROM World WHERE id = ?"
-	worldUpdate        = "UPDATE World SET randomNumber = ? WHERE id = ?"
-	fortuneSelect      = "SELECT id, message FROM Fortune;"
 	worldRowCount      = 10000
 	maxConnectionCount = 256
 )
 
+var (
+	worldSelectStmt   *sql.Stmt
+	worldUpdateStmt   *sql.Stmt
+	fortuneSelectStmt *sql.Stmt
+)
+
 const helloWorldString = "Hello, World!"
 
 var (
@@ -79,9 +71,17 @@ func main() {
 	var err error
 	db, err = sql.Open("mysql", connectionString)
 	if err != nil {
-		log.Fatalf("Error opening database: %v", err)
+		log.Fatalf("Error opening database: %s", err)
+	}
+	if err = db.Ping(); err != nil {
+		log.Fatalf("Cannot connect to db: %s", err)
 	}
 	db.SetMaxIdleConns(maxConnectionCount)
+	db.SetMaxOpenConns(maxConnectionCount * 2)
+
+	worldSelectStmt = mustPrepare(db, "SELECT id, randomNumber FROM World WHERE id = ?")
+	worldUpdateStmt = mustPrepare(db, "UPDATE World SET randomNumber = ? WHERE id = ?")
+	fortuneSelectStmt = mustPrepare(db, "SELECT id, message FROM Fortune")
 
 	s := &fasthttp.Server{
 		Handler: func(ctx *fasthttp.RequestCtx) {
@@ -94,9 +94,11 @@ func main() {
 			case fasthttp.EqualBytesStr(path, "/db"):
 				dbHandler(ctx)
 			case fasthttp.EqualBytesStr(path, "/queries"):
-				dbHandler(ctx)
+				queriesHandler(ctx)
 			case fasthttp.EqualBytesStr(path, "/fortune"):
 				fortuneHandler(ctx)
+			case fasthttp.EqualBytesStr(path, "/update"):
+				updateHandler(ctx)
 			default:
 				ctx.Error("unexpected path", fasthttp.StatusBadRequest)
 			}
@@ -110,6 +112,14 @@ func main() {
 	}
 }
 
+func mustPrepare(db *sql.DB, query string) *sql.Stmt {
+	stmt, err := db.Prepare(query)
+	if err != nil {
+		log.Fatalf("Error when preparing statement %q: %s", query, err)
+	}
+	return stmt
+}
+
 func doPrefork() (listener net.Listener) {
 	var err error
 	var fl *os.File
@@ -172,7 +182,7 @@ func jsonHandler(ctx *fasthttp.RequestCtx) {
 // Test 2: Single database query
 func dbHandler(ctx *fasthttp.RequestCtx) {
 	var world World
-	err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
+	err := worldSelectStmt.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world.Id, &world.RandomNumber)
 	if err != nil {
 		log.Fatalf("Error scanning world row: %s", err)
 	}
@@ -191,7 +201,7 @@ func queriesHandler(ctx *fasthttp.RequestCtx) {
 
 	world := make([]World, n)
 	for i := 0; i < n; i++ {
-		err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber)
+		err := worldSelectStmt.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber)
 		if err != nil {
 			log.Fatalf("Error scanning world row: %s", err)
 		}
@@ -202,7 +212,7 @@ func queriesHandler(ctx *fasthttp.RequestCtx) {
 
 // Test 4: Fortunes
 func fortuneHandler(ctx *fasthttp.RequestCtx) {
-	rows, err := db.Query(fortuneSelect)
+	rows, err := fortuneSelectStmt.Query()
 	if err != nil {
 		log.Fatalf("Error preparing statement: %v", err)
 	}
@@ -236,11 +246,11 @@ func updateHandler(ctx *fasthttp.RequestCtx) {
 	}
 	world := make([]World, n)
 	for i := 0; i < n; i++ {
-		if err := db.QueryRow(worldSelect, rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
+		if err := worldSelectStmt.QueryRow(rand.Intn(worldRowCount)+1).Scan(&world[i].Id, &world[i].RandomNumber); err != nil {
 			log.Fatalf("Error scanning world row: %s", err)
 		}
 		world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
-		if _, err := db.Exec(worldUpdate, world[i].RandomNumber, world[i].Id); err != nil {
+		if _, err := worldUpdateStmt.Exec(world[i].RandomNumber, world[i].Id); err != nil {
 			log.Fatalf("Error updating world row: %s", err)
 		}
 	}