mirror of
https://github.com/vlang/v.git
synced 2025-08-03 09:47:15 -04:00
db: modify mysql/pg/sqlite interface for pool working (#24780)
This commit is contained in:
parent
f62b5fd7f2
commit
7039081d66
@ -13,5 +13,5 @@ fn main() {
|
|||||||
for row in res.rows() {
|
for row in res.rows() {
|
||||||
println(row.vals.join(', '))
|
println(row.vals.join(', '))
|
||||||
}
|
}
|
||||||
conn.close()
|
conn.close()!
|
||||||
}
|
}
|
||||||
|
159
examples/database/mysql_pool.v
Normal file
159
examples/database/mysql_pool.v
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// vtest build: !(macos || windows)
|
||||||
|
import db.mysql
|
||||||
|
import pool
|
||||||
|
import time
|
||||||
|
|
||||||
|
// Define your connection factory function
|
||||||
|
fn create_conn() !&pool.ConnectionPoolable {
|
||||||
|
config := mysql.Config{
|
||||||
|
host: '127.0.0.1'
|
||||||
|
port: 3306
|
||||||
|
username: 'root'
|
||||||
|
password: '12345678'
|
||||||
|
dbname: 'mysql'
|
||||||
|
}
|
||||||
|
db := mysql.connect(config)!
|
||||||
|
return &db
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Configure pool parameters
|
||||||
|
config := pool.ConnectionPoolConfig{
|
||||||
|
max_conns: 50
|
||||||
|
min_idle_conns: 5
|
||||||
|
max_lifetime: 2 * time.hour
|
||||||
|
idle_timeout: 30 * time.minute
|
||||||
|
get_timeout: 5 * time.second
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create connection pool
|
||||||
|
mut my_pool := pool.new_connection_pool(create_conn, config)!
|
||||||
|
defer {
|
||||||
|
// When application exits
|
||||||
|
my_pool.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire connection
|
||||||
|
mut conn := my_pool.get()!
|
||||||
|
defer {
|
||||||
|
// Return connection to pool
|
||||||
|
my_pool.put(conn) or { println(err) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert `conn` to a `mysql.DB` object
|
||||||
|
mut db := conn as mysql.DB
|
||||||
|
|
||||||
|
assert db.validate()!
|
||||||
|
|
||||||
|
mut response := db.exec('drop table if exists users')!
|
||||||
|
assert response == []mysql.Row{}
|
||||||
|
|
||||||
|
response = db.exec('create table if not exists users (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
username TEXT,
|
||||||
|
last_name TEXT NULL DEFAULT NULL
|
||||||
|
)')!
|
||||||
|
assert response == []mysql.Row{}
|
||||||
|
|
||||||
|
mut result_code := db.exec_none('insert into users (username) values ("jackson")')
|
||||||
|
assert result_code == 0
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("shannon")')
|
||||||
|
assert result_code == 0
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("bailey")')
|
||||||
|
assert result_code == 0
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("blaze")')
|
||||||
|
assert result_code == 0
|
||||||
|
rows := db.exec_param('insert into users (username) values (?)', 'Hi')!
|
||||||
|
assert rows == []mysql.Row{}
|
||||||
|
|
||||||
|
// Regression testing to ensure the query and exec return the same values
|
||||||
|
res := db.query('select * from users')!
|
||||||
|
response = res.rows()
|
||||||
|
assert response[0].vals[1] == 'jackson'
|
||||||
|
response = db.exec('select * from users')!
|
||||||
|
assert response[0].vals[1] == 'jackson'
|
||||||
|
|
||||||
|
response = db.exec('select * from users where id = 400')!
|
||||||
|
assert response.len == 0
|
||||||
|
|
||||||
|
single_row := db.exec_one('select * from users')!
|
||||||
|
assert single_row.vals[1] == 'jackson'
|
||||||
|
|
||||||
|
response = db.exec_param_many('select * from users where username = ?', [
|
||||||
|
'jackson',
|
||||||
|
])!
|
||||||
|
assert response[0] == mysql.Row{
|
||||||
|
vals: ['1', 'jackson', '']
|
||||||
|
}
|
||||||
|
|
||||||
|
response = db.exec_param_many('select * from users where username = ? and id = ?',
|
||||||
|
['bailey', '3'])!
|
||||||
|
assert response[0] == mysql.Row{
|
||||||
|
vals: ['3', 'bailey', '']
|
||||||
|
}
|
||||||
|
|
||||||
|
response = db.exec_param_many('select * from users', [''])!
|
||||||
|
assert response == [
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['1', 'jackson', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['2', 'shannon', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['3', 'bailey', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['4', 'blaze', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['5', 'Hi', '']
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
response = db.exec_param('select * from users where username = ?', 'blaze')!
|
||||||
|
assert response[0] == mysql.Row{
|
||||||
|
vals: ['4', 'blaze', '']
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction test
|
||||||
|
// turn off `autocommit` first
|
||||||
|
db.autocommit(false)!
|
||||||
|
// begin a new transaction
|
||||||
|
db.begin()!
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("tom")')
|
||||||
|
assert result_code == 0
|
||||||
|
// make a savepoint
|
||||||
|
db.savepoint('savepoint1')!
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("kitty")')
|
||||||
|
assert result_code == 0
|
||||||
|
// rollback to `savepoint1`
|
||||||
|
db.rollback_to('savepoint1')!
|
||||||
|
result_code = db.exec_none('insert into users (username) values ("mars")')
|
||||||
|
assert result_code == 0
|
||||||
|
db.commit()!
|
||||||
|
response = db.exec_param_many('select * from users', [''])!
|
||||||
|
assert response == [
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['1', 'jackson', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['2', 'shannon', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['3', 'bailey', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['4', 'blaze', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['5', 'Hi', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['6', 'tom', '']
|
||||||
|
},
|
||||||
|
mysql.Row{
|
||||||
|
vals: ['8', 'mars', '']
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
@ -110,7 +110,7 @@ fn msql_array() ! {
|
|||||||
sql db {
|
sql db {
|
||||||
drop table Parent
|
drop table Parent
|
||||||
} or {}
|
} or {}
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.query('drop table if exists Parent')!
|
db.query('drop table if exists Parent')!
|
||||||
@ -144,7 +144,7 @@ fn psql_array() ! {
|
|||||||
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
|
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
|
||||||
defer {
|
defer {
|
||||||
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
|
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
|
db.exec_one('drop table if exists "Parent", "Child"') or { eprintln(err) }
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ fn msql() ! {
|
|||||||
defer {
|
defer {
|
||||||
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
|
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
|
||||||
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
|
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
|
||||||
conn.close()
|
conn.close() or {}
|
||||||
}
|
}
|
||||||
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
|
conn.query('DROP TABLE IF EXISTS Module') or { eprintln(err) }
|
||||||
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
|
conn.query('DROP TABLE IF EXISTS User') or { eprintln(err) }
|
||||||
@ -253,7 +253,7 @@ fn psql() ! {
|
|||||||
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
|
mut db := pg.connect(host: pg_host, user: pg_user, password: pg_pass, dbname: pg_db)!
|
||||||
defer {
|
defer {
|
||||||
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
|
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
|
db.exec_one('drop table if exists "modules", "User"') or { eprintln(err) }
|
||||||
sql db {
|
sql db {
|
||||||
|
@ -330,12 +330,10 @@ pub fn (mut db DB) refresh(options u32) !bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// reset resets the connection, and clear the session state.
|
// reset resets the connection, and clear the session state.
|
||||||
pub fn (mut db DB) reset() !bool {
|
pub fn (mut db DB) reset() ! {
|
||||||
if C.mysql_reset_connection(db.conn) != 0 {
|
if C.mysql_reset_connection(db.conn) != 0 {
|
||||||
db.throw_mysql_error()!
|
db.throw_mysql_error()!
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ping pings a server connection, or tries to reconnect if the connection
|
// ping pings a server connection, or tries to reconnect if the connection
|
||||||
@ -348,8 +346,14 @@ pub fn (mut db DB) ping() !bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate pings a server connection, or tries to reconnect if the connection
|
||||||
|
// has gone down.
|
||||||
|
pub fn (mut db DB) validate() !bool {
|
||||||
|
return db.ping()!
|
||||||
|
}
|
||||||
|
|
||||||
// close closes the connection.
|
// close closes the connection.
|
||||||
pub fn (mut db DB) close() {
|
pub fn (mut db DB) close() ! {
|
||||||
C.mysql_close(db.conn)
|
C.mysql_close(db.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ fn test_mysql_orm() {
|
|||||||
dbname: 'mysql'
|
dbname: 'mysql'
|
||||||
)!
|
)!
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
table := orm.Table{
|
table := orm.Table{
|
||||||
name: 'Test'
|
name: 'Test'
|
||||||
|
@ -16,6 +16,11 @@ fn test_mysql() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mut db := mysql.connect(config)!
|
mut db := mysql.connect(config)!
|
||||||
|
defer {
|
||||||
|
db.close() or {}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert db.validate()!
|
||||||
|
|
||||||
mut response := db.exec('drop table if exists users')!
|
mut response := db.exec('drop table if exists users')!
|
||||||
assert response == []mysql.Row{}
|
assert response == []mysql.Row{}
|
||||||
|
@ -33,6 +33,6 @@ pub fn (mut pool ConnectionPool) release(conn DB) {
|
|||||||
pub fn (mut pool ConnectionPool) close() {
|
pub fn (mut pool ConnectionPool) close() {
|
||||||
for _ in 0 .. pool.connections.len {
|
for _ in 0 .. pool.connections.len {
|
||||||
mut conn := <-pool.connections or { break }
|
mut conn := <-pool.connections or { break }
|
||||||
conn.close()
|
conn.close() or { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ fn res_to_rows(res voidptr) []Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close frees the underlying resource allocated by the database connection
|
// close frees the underlying resource allocated by the database connection
|
||||||
pub fn (db &DB) close() {
|
pub fn (db &DB) close() ! {
|
||||||
C.PQfinish(db.conn)
|
C.PQfinish(db.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,3 +510,13 @@ pub fn (db &DB) savepoint(savepoint string) ! {
|
|||||||
return error('pg exec error: "${e}"')
|
return error('pg exec error: "${e}"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate checks if the connection is still usable
|
||||||
|
pub fn (db &DB) validate() !bool {
|
||||||
|
db.exec_one('SELECT 1')!
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset returns the connection to initial state for reuse
|
||||||
|
pub fn (db &DB) reset() ! {
|
||||||
|
}
|
||||||
|
@ -19,7 +19,7 @@ fn test_float_field() {
|
|||||||
conn := 'host=localhost user=postgres password=12345678' // insert own connection string
|
conn := 'host=localhost user=postgres password=12345678' // insert own connection string
|
||||||
db := pg.connect_with_conninfo(conn)!
|
db := pg.connect_with_conninfo(conn)!
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
sql db {
|
sql db {
|
||||||
|
@ -57,7 +57,7 @@ fn test_pg_orm() {
|
|||||||
) or { panic(err) }
|
) or { panic(err) }
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
table := orm.Table{
|
table := orm.Table{
|
||||||
name: 'Test'
|
name: 'Test'
|
||||||
|
@ -12,9 +12,11 @@ fn test_large_exec() {
|
|||||||
|
|
||||||
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert db.validate()!
|
||||||
|
|
||||||
rows := db.exec('
|
rows := db.exec('
|
||||||
SELECT ischema.table_schema, c.relname, a.attname, t.typname, t.typalign, t.typlen
|
SELECT ischema.table_schema, c.relname, a.attname, t.typname, t.typalign, t.typlen
|
||||||
FROM pg_class c
|
FROM pg_class c
|
||||||
@ -38,7 +40,7 @@ fn test_prepared() {
|
|||||||
}
|
}
|
||||||
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.prepare('test_prepared', 'SELECT NOW(), $1 AS NAME', 1) or { panic(err) }
|
db.prepare('test_prepared', 'SELECT NOW(), $1 AS NAME', 1) or { panic(err) }
|
||||||
@ -57,7 +59,7 @@ fn test_transaction() {
|
|||||||
|
|
||||||
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
|
||||||
defer {
|
defer {
|
||||||
db.close()
|
db.close() or {}
|
||||||
}
|
}
|
||||||
db.exec('drop table if exists users')!
|
db.exec('drop table if exists users')!
|
||||||
db.exec('create table if not exists users (
|
db.exec('create table if not exists users (
|
||||||
|
@ -33,6 +33,6 @@ pub fn (mut pool ConnectionPool) release(conn DB) {
|
|||||||
pub fn (mut pool ConnectionPool) close() {
|
pub fn (mut pool ConnectionPool) close() {
|
||||||
for _ in 0 .. pool.connections.len {
|
for _ in 0 .. pool.connections.len {
|
||||||
conn := <-pool.connections or { break }
|
conn := <-pool.connections or { break }
|
||||||
conn.close()
|
conn.close() or { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ pub fn connect(path string) !DB {
|
|||||||
// close Closes the DB.
|
// close Closes the DB.
|
||||||
// TODO: For all functions, determine whether the connection is
|
// TODO: For all functions, determine whether the connection is
|
||||||
// closed first, and determine what to do if it is
|
// closed first, and determine what to do if it is
|
||||||
pub fn (mut db DB) close() !bool {
|
pub fn (mut db DB) close() ! {
|
||||||
code := C.sqlite3_close(db.conn)
|
code := C.sqlite3_close(db.conn)
|
||||||
if code == 0 {
|
if code == 0 {
|
||||||
db.is_open = false
|
db.is_open = false
|
||||||
@ -160,7 +160,6 @@ pub fn (mut db DB) close() !bool {
|
|||||||
code: code
|
code: code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true // successfully closed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only for V ORM
|
// Only for V ORM
|
||||||
@ -500,3 +499,12 @@ pub fn (mut db DB) rollback_to(savepoint string) ! {
|
|||||||
}
|
}
|
||||||
db.exec('ROLLBACK TO ${savepoint};')!
|
db.exec('ROLLBACK TO ${savepoint};')!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset returns the connection to initial state for reuse
|
||||||
|
pub fn (mut db DB) reset() ! {
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate checks if the connection is still usable
|
||||||
|
pub fn (mut db DB) validate() !bool {
|
||||||
|
return db.exec_none('SELECT 1') == 100
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@ fn test_sqlite() {
|
|||||||
}
|
}
|
||||||
mut db := sqlite.connect(':memory:') or { panic(err) }
|
mut db := sqlite.connect(':memory:') or { panic(err) }
|
||||||
assert db.is_open
|
assert db.is_open
|
||||||
|
assert db.validate()!
|
||||||
db.exec('drop table if exists users')!
|
db.exec('drop table if exists users')!
|
||||||
db.exec("create table users (id integer primary key, name text default '', last_name text null default null);")!
|
db.exec("create table users (id integer primary key, name text default '', last_name text null default null);")!
|
||||||
db.exec("insert into users (name) values ('Sam')")!
|
db.exec("insert into users (name) values ('Sam')")!
|
||||||
|
@ -53,8 +53,12 @@ mut my_pool := pool.new_connection_pool(create_conn, config)!
|
|||||||
// Acquire connection
|
// Acquire connection
|
||||||
mut conn := my_pool.get()!
|
mut conn := my_pool.get()!
|
||||||
|
|
||||||
// Use connection
|
// Convert `conn` to a `mysql.DB` object
|
||||||
|
mut db := conn as mysql.DB
|
||||||
|
|
||||||
|
// Use connection `db`
|
||||||
// ... your operations ...
|
// ... your operations ...
|
||||||
|
// db.exec()
|
||||||
|
|
||||||
// Return connection to pool
|
// Return connection to pool
|
||||||
my_pool.put(conn)!
|
my_pool.put(conn)!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user