Saya menggunakan API yang dibuat menggunakan Go dan MySQl untuk database ke Heroku. Saya mengikuti panduan ini dan menyiapkan semuanya tetapi sekarang saya mencoba mengeksekusi skrip MySQL untuk mengatur tabel dengan beberapa data dummy. Tetapi saya terus-menerus mendapatkan kesalahan yang mengatakan bahwa skripnya salah meskipun saya telah menggunakannya secara lokal tanpa masalah. Saya telah menghubungkan database MySQL ke lingkungan Heroku dan memulai database tidak ada kesalahan.

Berikut adalah log yang menunjukkan kesalahan saat menerapkannya ke Heroku:

2021-06-05T12:49:16.442359+00:00 app[web.1]: ERROR  2021/06/05 12:49:16 main.go:45: Error executing SQL script : Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'USE assessment;

schema.sql

CREATE DATABASE assessment;

USE assessment;

CREATE TABLE users (
    id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 
    email VARCHAR(255) NOT NULL
);
INSERT INTO `users` VALUES (1,"test1@gmail.com");
INSERT INTO `users` VALUES (2,"test2@gmail.com");
INSERT INTO `users` VALUES (3,"test3@gmail.com");
INSERT INTO `users` VALUES (4,"test4@gmail.com");
INSERT INTO `users` VALUES (5,"test5@gmail.com");

CREATE TABLE features (
    feature_id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
    user_id INTEGER NOT NULL,
    feature_name VARCHAR(100) NOT NULL,
    can_access BOOLEAN NOT NULL DEFAULT FALSE,
    FOREIGN KEY (user_id) REFERENCES users(id) 
);

INSERT INTO `features` VALUES (1, 1, "automated-investing", 1);
INSERT INTO `features` VALUES (2, 1, "crypto", 0);
INSERT INTO `features` VALUES (3, 2, "crypto", 0);
INSERT INTO `features` VALUES (4, 3, "automated-investing", 0);
INSERT INTO `features` VALUES (5, 4, "automated-investing", 1);
INSERT INTO `features` VALUES (7, 1, "financial-tracking", 1);
INSERT INTO `features` VALUES (8, 2, "financial-tracking", 0);
INSERT INTO `features` VALUES (9, 3, "financial-tracking", 1);
INSERT INTO `features` VALUES (10, 4, "financial-tracking", 0);

main.go

package main

import (
    "io/ioutil"
    "log"
    "net/http"
    "os"
    "time"

    _ "github.com/go-sql-driver/mysql"
    "github.com/gorilla/mux"
    "github.com/joho/godotenv"

    "github.com/yudhiesh/api/controller"
    "github.com/yudhiesh/api/middleware"
)

func main() {
    router := mux.NewRouter()
    router.Use(middleware.ResponseHeaders)
    router.Use(middleware.LogRequest)
    errorLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)
    infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
    err := godotenv.Load(".env")
    port := os.Getenv("PORT")
    if port == "" {
        errorLog.Fatal("$PORT is not set")
    }
    dsn := os.Getenv("DSN")
    if dsn == "" {
        errorLog.Fatal("$DATABASE_URL is not set")
    }
    db, err := controller.OpenDB(dsn)
    if err != nil {
        errorLog.Fatal(err)
    }
    defer db.Close()
    c, ioErr := ioutil.ReadFile("./schema.sql")
    sqlScript := string(c)
    if ioErr != nil {
        errorLog.Fatalf("Error loading SQL schema : %s", ioErr)
    }
    _, err = db.Exec(sqlScript)
    if err != nil {
        // FAILS HERE!
        errorLog.Fatalf("Error executing SQL script : %s", err)
    }
    app := &controller.Application{
        DB:       db,
        ErrorLog: errorLog,
        InfoLog:  infoLog,
    }
    addr := ":" + port
    server := &http.Server{
        Handler:      router,
        Addr:         addr,
        WriteTimeout: 15 * time.Second,
        ReadTimeout:  15 * time.Second,
    }
    router.HandleFunc("/feature", app.GetCanAccess).Methods("GET")
    router.HandleFunc("/feature", app.InsertFeature).Methods("POST")
    http.Handle("/", router)
    infoLog.Printf("Connected to port %s", port)
    errorLog.Fatal(server.ListenAndServe())
}
0
yudhiesh 5 Juni 2021, 16:06

2 jawaban

Jawaban Terbaik

Sebagian besar antarmuka untuk menjalankan kueri terhadap MySQL tidak mendukung multi-kueri. Dengan kata lain, mereka tidak mengizinkan beberapa pernyataan SQL dipisahkan oleh titik koma, mereka hanya mendukung satu pernyataan SQL per panggilan.

Dalam kasus Anda, ini mengembalikan kesalahan sintaks pada USE ... karena mengingat input diuraikan sebagai satu pernyataan, tidak ada USE di BUAT pernyataan DATABASE.

CREATE DATABASE assessment; USE assessment;

Ini berarti jika Anda ingin memproses file dari banyak pernyataan SQL, Anda tidak bisa hanya melakukan apa yang Anda lakukan dan memperlakukan seluruh file sebagai satu string untuk diteruskan ke satu panggilan Exec():

c, ioErr := ioutil.ReadFile("./schema.sql")
sqlScript := string(c)
...
_, err = db.Exec(sqlScript)

Anda harus membagi konten file itu menjadi pernyataan SQL individual, dan kemudian mengulang pernyataan tersebut, menjalankan setiap pernyataan pada satu waktu.

Ini lebih rumit daripada kedengarannya, karena:

  • Skrip SQL mungkin berisi pernyataan DELIMITER yang mengubah karakter antara pernyataan dari titik koma ke sesuatu yang lain.

  • Mungkin ada titik koma di dalam literal string atau komentar di dalam.

  • Beberapa pernyataan seperti CREATE PROCEDURE, CREATE TRIGGER, dll. mungkin berisi titik koma di antara pernyataan di badan rutin. Anda tidak ingin titik koma ini menjadi akhir dari pernyataan, Anda ingin memasukkan semua konten ke akhir definisi rutin.

  • Pernyataan DELIMITER itu sendiri tidak bisa dieksekusi oleh Server MySQL. Itu hanya mengontrol klien. Jadi, Anda harus memperlakukannya sebagai pengecualian yang tidak dikirim ke server di loop Anda. Sebenarnya, ada banyak perintah bawaan klien mysql< /a> yang harus diperlakukan sama jika Anda menemukannya dalam skrip SQL.

Jika Anda akhirnya mengkodekan semua logika ini, pada dasarnya Anda telah mengimplementasikan kembali klien baris perintah MySQL di Go.

Akan jauh lebih cepat dan sederhana jika Anda melewati semua pekerjaan pengkodean itu, dan jalankan saja klien baris perintah MySQL menggunakan os.exec.Command. Pikirkan tentang hal ini — ini akan menghemat berminggu-minggu pekerjaan pengkodean, menduplikasi semua fitur bernuansa menjalankan skrip SQL yang sudah diterapkan di klien MySQL.

3
Bill Karwin 5 Juni 2021, 15:15

Ok jadi saya memutuskan untuk langsung terhubung ke database mysql menggunakan kredensial yang diberikan dari Heroku.

Ini mengembalikan URL ke database.

heroku config | grep CLEARDB_DATABASE_URL

Ini terlihat seperti ini:

mysql://alphanum-username:alphanum-password@us-cdbr-iron-east-01.cleardb.net/heroku_alphanum_name?reconnect=true

Kemudian hubungkan menggunakan mysql -u username -h host -p host berasal dari URL yang dalam hal ini adalah us-cdbr-iron-east-01.cleardb.net. Sandi berasal dari alphanum-password.

Saya menjalankan kueri yang sama tetapi mendapatkan kesalahan ini yang berarti saya tidak memiliki akses ke database.

ERROR 1044 (42000): Access denied for user 'bbf806af82a4c9'@'%' to database 'assessment'

Menjalankan show databases; menunjukkan bahwa ada database tertentu yang dapat Anda sambungkan sebagai pengguna.

mysql> SHOW DATABASES;
+------------------------+
| Database               |
+------------------------+
| information_schema     |
| herokusdfhsdfhsdfsfsdf |
+------------------------+

Dari sini saya menjalankan USE herokusdfhsdfhsdfsfsdf dan menjalankan sisa kueri saya tanpa masalah.

0
yudhiesh 5 Juni 2021, 15:13