我是Golang和MySQL的新手,我正在使用开发框创建一个简单的网页,使用golang(来自下面两个文件的代码)来获取输入,将输入存储到数据库并显示输入一个网页。目前在本地使用MySQL作为我的数据库,我的用户名为root,密码为abc,我的数据库也被命名为abc。
我已导入顶部:
import (
_"github.com/go-sql-driver/mysql"
"database/sql"
)
当我服务我的网页时,我调用了我的connectDB函数:
func init(){
INDEX_HTML , _ = ioutil.ReadFile("./templates/index.html")
connectDb()
}
func connectDb(){
//socket : var/run/mysqld/mysqld.sock
/* connection string examples :
db, err := sql.Open("mysql", "user:password@/dbname")
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
TCP using default port (3306) on localhost:
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
Use the default protocol (tcp) and host (localhost:3306):
user:password@/dbname
No Database preselected:
user:password@/
*/
db, err := sql.Open("mysql", "root:abc@/abc")
log.Println("DB: ", db)
checkErr(err)
// Open doesn't open a connection. Validate DSN data:
checkErr(err)
}
我的理解并根据https://github.com/go-sql-driver/mysql SQL.open返回一个* sql.DB,当程序点击上面的代码时:
/* At the top of my code i have var db = *sql.DB */
log.Println("DB: ", db)
我在命令提示符中获得以下代码注释中注明的所有类型的示例连接字符串:
DB:& {0x99c410 root:abc @ / abc 0 {0 0} [] [] 0 0xc820072180 false map [] map [] 0 0 0< nil>}
我的MySQL数据库在本地通过命令行使用给定的用户名和密码正常运行,我可以获得一些项目,手动插入以下查询。
mysql>
mysql> select * from ListItems
-> ;
+-------+
| items |
+-------+
| item1 |
| item2 |
+-------+
我正在尝试了解消息是什么以及如何连接到mysql数据库以运行查询并插入数据库。
我的连接字符串可能有问题吗?尝试插入数据库时出现错误的示例:
016/06/20 02:22:36 http: panic serving 10.1.0.5:41861:
runtime error: invalid
memory address or nil pointer dereference
goroutine 7 [running]:
net/http.(*conn).serve.func1(0xc82006c380)
/usr/local/go/src/net/http/server.go:1389 +0xc1
panic(0x74ef00, 0xc82000a0c0)
/usr/local/go/src/runtime/panic.go:443 +0x4e9
database/sql.(*DB).conn(0x0, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:778 +0xac9
database/sql.(*DB).exec(0x0, 0x812b60, 0x26, 0xc82003fa70, 0x1, 0x1, 0xc82000b201, 0x0, 0x0, 0x0, ...)
/usr/local/go/src/database/sql/sql.go:1021 +0x87
database/sql.(*DB).Exec(0x0, 0x812b60, 0x26, 0xc82003fa70, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:1009 +0xbe
main.AddListHandler(0x7f56da7ac9b0, 0xc82006f6c0, 0xc8200f21c0)
/home/cabox/workspace/src/github.com/user/hello/main.go:26 +0x36c **<---**
net/http.HandlerFunc.ServeHTTP(0x859f70, 0x7f56da7ac9b0, 0xc82006f6c0, 0xc8200f21c0)
/usr/local/go/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820010b10, 0x7f56da7ac9b0, 0xc82006f6c0, 0xc8200f21c0)
/usr/local/go/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc82006c180, 0x7f56da7ac9b0, 0xc82006f6c0, 0xc8200f21c0)
/usr/local/go/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc82006c380)
/usr/local/go/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:2137 +0x44e
当我看到main.go中的第26行时,我有:
db.Exec("INSERT INTO ListItems(items) Values(?)" , (r.Form["item"][0]))
以下是最小代码示例:
project / templates / index.html:
<!doctype html>
<h1>Enter item to add to list:</h1><br>
<form action="/addlist" method="post">
<input type="text" name="item" placeholder="Enter Item to add to list"><br>
<input type ="submit" class="add" value="Add To List"><br>
</form>
projects / main.go ..使用go build main.go
package main
import (
"net/http"
"fmt"
"io/ioutil"
"log"
_"github.com/go-sql-driver/mysql"
"database/sql"
)
var INDEX_HTML []byte // holds the raw html of index.html inside /templates
var db *sql.DB // pointer to sql.open which returns a sql.db
func main(){
fmt.Println("starting server on port 8080")
http.HandleFunc("/", IndexHandler)
http.HandleFunc("/addlist", AddListHandler)
http.ListenAndServe(":8080", nil)
}
func AddListHandler(w http.ResponseWriter, r *http.Request){
r.ParseForm()
log.Println("adding list: ", r.Form["item"][0])
db.Exec("INSERT INTO ListItems(items) Values(?)" , (r.Form["item"][0])) /*error*/
if(db == nil){log.Println("DB is nill")}
http.Redirect(w,r,"/", http.StatusTemporaryRedirect)
}
func IndexHandler(w http.ResponseWriter, r *http.Request){
log.Println("GET /")
w.Write(INDEX_HTML)
}
func init(){
INDEX_HTML , _ = ioutil.ReadFile("./templates/index.html")
connectDb()
}
func connectDb(){
//socket : var/run/mysqld/mysqld.sock
/* connection string examples :
db, err := sql.Open("mysql", "user:password@/dbname")
user:password@tcp(localhost:5555)/dbname?tls=skip-verify&autocommit=true
TCP using default port (3306) on localhost:
user:password@tcp/dbname?charset=utf8mb4,utf8&sys_var=esc%40ped
Use the default protocol (tcp) and host (localhost:3306):
user:password@/dbname
No Database preselected:
user:password@/
*/
db, err := sql.Open("mysql", "root:abc@/abc")
log.Println("DB: ", db)
checkErr(err)
// Open doesn't open a connection. Validate DSN data:
checkErr(err)
}
func checkErr(err error) {
if err != nil {
log.Println(err)
}else{
log.Println(err)
}
}
答案 0 :(得分:0)
问题是,db
声明的全局var db *sql.DB
变量永远不会赋值。所以它保持默认值nil
。尝试取消引用nil指针会给你错误。
您可能认为在init
函数中,您要为新创建的DB
实例分配此变量。但是:=
创建了一个新的局部变量来保存新的DB
实例。全局db
变量保持不变。请参阅example。
反之,
var err error
db, err = sql.Open("mysql", "root:abc@/abc")
另外根据我使用全局变量的经验,当你可以避免它导致难以调试的错误。 (就像这一个。)我认为你可以通过connectDb
返回一个DB
实例来避免它。