I got a problem when using database/sql, when i'm using it with a middleware in my api, the first time i hit an endpoint the database is accessible, but at the moment i'm hitting another endpoint i got the error sql error: database is closed. I got this error even if i didn't do db.Close() and when this happen the db file (duckdb) is stilll in use by go. I manage to make it in a smaller project here's the link of the file (to big for discord) https://online-clipboard.online/online-clipboard/ with the id : 1511
#DB Closing error without closing it
40 messages · Page 1 of 1 (latest)
Maybe it wasn't open to begin with? Check your sqlite logs
sorry i mad a mistake i'm using duckdb, but it's actually open at the start cause i can query the db.
No data find.
I can't find anything when I enter 1511
My bad, the site is shitty, i'm gonna send it back when arrive home sorry
Here's the repo i made to show the error
on line 26, the := creates a new local variable called db shadowing the global db
you need to use = to assign to the global
Yeah but it's returning a pointer, and anyway why is this available in the first end point but not on the second one ?
the fact that it’s a pointer is totally irrelevant
the global is nil
oh, you mean initDB is, i see
The endpoint are getting the db by the middleware it's not using the global variable
Yeah
It's so strange
Do you have the same problème if you try on your computer ?
Your problem is that fiber closes the db after the first use.
So don't use the middleware to store something you want to persist through requests because fiber will close everything you pass through it like that.
So instead, do this:
func routes(app *fiber.App, db *sql.DB) {
And then remove the middleware bits and pass the db to the routes function instead.
Also, remove the global db variable. Don't forget to close the db in main using defer db.Close() after you've initialized it.
Locals makes it possible to pass interface{} values under keys scoped to the request and therefore available to all following routes that match the request.
All the values are removed from ctx after returning from the top RequestHandler. Additionally, Close method is called on each value implementing io.Closer before removing the value from ctx.
I also recommend not generating the ID or the timestamp in your code, let the database/driver do it for you.
Example:
CREATE SEQUENCE IF NOT EXISTS user_id START 1000;
CREATE TABLE IF NOT EXISTS users (
id INTEGER DEFAULT NEXTVAL('user_id') PRIMARY KEY,
name VARCHAR NOT NULL,
email VARCHAR NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
)
The id will be like a serial starting at 1000. Change it to whatever you want.
Then don't pass id or created_at. The database will fill that in for you.
So when you insert, just do INSERT INTO users (name, email) VALUES (?, ?)
Oooh okay thanks, i really didn't get how the fuck was it closed but thanks ! Bro you're saving me for real !
You're welcome! 🙂
We advise against using fiber unless you have a proven use case for it where it will make a difference.
Oh, why ? I found it quiet easy to work with because i come from a js background so it's really similar
This is the first time I used fiber. I tried running your code and I ran into the same problem. It took me a while to find what caused it.
fiber isn't compatible with net/http.
Is that a big deal ?
I believe so, because you'll find way more things that are compatible with net/http and you're more likely going to find people who will be able to help you.
For example, you can use echo from labstack. It's similar to what you'd find in JS.
But learning how to use net/http is really nice. It's easier than you think.
And you can easily jump into things like echo and gin once you feel comfortable with net/http.
Actually i learned a bit of net/http but the first real api framework that i found was fiber so i started with that
But thanks it's really nice of you to take the time for me !
You're welcome 🙂