Go no proporcionar ningún controlador de base de datos oficial que hace PHP, pero tiene algunos estándares de interfaz de controlador de base de datos para desarrolladores que desarrollan drivers de bases de datos. Hay una ventaja que si el código ha sido desarrollado de acuerdo con estos estándares de interfaz, no cambia ningún código cuando su base de datos cambia. Vamos a ver lo que estos estándares de interfaz de base de datos son.
Esta función se encuentra en el paquete de base de database/sql
para registrar los drivers de bases de datos al utilizar controladores de base de datos de terceros. Todos esos drivers, deben llamar a la función de registro (nombre de la cadena, driver driver.Driver) en init () función para registrar sus conductores.
Vamos a echar un vistazo a el código correspondiente en los conductores de mymysql y sqlite3:
//https://github.com/mattn/go-sqlite3 driver
func init() {
sql.Register("sqlite3", &SQLiteDriver{})
}
//https://github.com/mikespook/mymysql driver
// Driver automatically registered in database/sql
var d = Driver{proto: "tcp", raddr: "127.0.0.1:3306"}
func init() {
Register("SET NAMES utf8")
sql.Register("mymysql", &d)
}
Vemos que todos los controladores de bases de datos de terceras partes implementan esta función a fin de registrarse, y Go utiliza un mapa para guardar los conductores de usuario dentro de databse/sql
.
var drivers = make(map[string]driver.Driver)
drivers[name] = driver
Por lo tanto, esta función de registro puede registrar los drivers tantos como desee, con nombre diferente.
Siempre vemos siguiente código cuando utilizamos controladores de terceros:
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
)
Aquí el guion bajo _ es bastante confuso para muchos principiantes, y esto es un gran diseño en Go. Sabemos este identificador es para descartar los valores de retorno de la función, y usted tiene que utilizar todos los paquetes importados en el código en Go. Así que cuando se utiliza la importación se necesita para ejecutar la función init () de ese paquete sin usarla directamente, para el registro de controlador de base de datos.
Driver
es una interfaz que tiene un método Open(name string)
que devuelve una interfaz de Conn
.
type Driver interface {
Open(name string) (Conn, error)
}
Esto se hace una sola vez Conn, lo que significa que se puede utilizar sólo una vez en una goroutine. En el siguiente código se producirá errores:
...
go goroutineA (Conn) // query
go goroutineB (Conn) // insert
...
Debido a que Go no tiene ni idea sobre qué goroutine se hace la operación, por lo que la operación de consulta se puede obtener el resultado de la inserción, viceversa.
Todos los controladores de otros fabricantes deben tener esta función para analizar el nombre de Conn y devolver correctamente los resultados.
Se trata de una interfaz de conexión de base de datos con algunos métodos, y como he dicho anteriormente, solo se puede utilizar Conn en una goroutine.
type Conn interface {
Prepare(query string) (Stmt, error)
Close() error
Begin() (Tx, error)
}
Prepare
prepara el estado de comandos SQL correspondiente para consultar y borrar, etcClose
cierra la conexión actual y recursos limpios. La mayoría de los controladores de terceros utilizan algunos tipos de agrupación de conexiones, por lo que no es necesario para almacenar en caché las conexiones a menos que usted desee tener errores inesperados.Begin
devuelve un Tx que representa un identificador que se puede utilizar para consultar, actualizar o retroceder etc
Este es un estado de listo y se corresponde con Conn, por lo que sólo se puede utilizar en una goroutine como Conn
type Stmt interface {
Close() error
NumInput() int
Exec(args []Value) (Result, error)
Query(args []Value) (Rows, error)
}
Close
cierra la conexión actual, pero sigue devolviendo datos de filas si se está haciendo operación de consulta.NumInput
devuelve el número de argumentos obligados, los controladores de bases de datos deben comprobar los argumentos de llamantes cuando el resultado es mayor que 0, y se devuelve -1 cuando los conductores de bases de datos no conocen ningún argumento obligado.Exec
ejecuta comandos SQL deupdate/insert
que se prepara enPrepare
, devuelveResult
.Query
ejecuta comandos SQL deselect
que se preparan enPrepare
, devuelve datos filas.
Generally, affair handle only have submit or roll back, and database drivers only need to implement these two methods.
type Tx interface {
Commit() error
Rollback() error
}
Esta es una interfaz opcional.
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
Si el conductor no implementa esta interfaz, a continuación, cuando usted llama DB.Exec, llama automáticamente Prepare y devuelve Stmt, luego ejecuta Exec de Stmt, a continuación, cierra Stmt.
Esta es la interfaz para el resultado de la operacion update/insert
.
type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}
LastInsertId
devuelve el número de Identificación de incremento automático después de la operación de inserción de la base de datos.RowsAffected
devuelve filas que afectaron después de operación de consulta.
Esta es la interfaz de conjunto de resultados de la operación de consulta.
type Rows interface {
Columns() []string
Close() error
Next(dest []Value) error
}
Columns
devuelve los campos de información de las tablas de base de datos, el corte es uno-a-uno con campo de consulta SQL, no todos los campos de esa tabla de base de datos.Close
cierra iterator de filas.Next
datos siguientes y asigna a dest, toda cadena deben convertirse en matriz de bytes, y obtiene el error io.EOF si no hay más datos disponibles.
Este es un alias de int64, pero implementa la interfaz de resultados.
type RowsAffected int64
func (RowsAffected) LastInsertId() (int64, error)
func (v RowsAffected) RowsAffected() (int64, error)
Esta es una interfaz de vacío que puede contener cualquier tipo de datos.
type Value interface{}
El valor debe ser algo que los drivers pueden operar o anular, por lo que debe ser uno de los siguientes tipos:
int64
float64
bool
[]byte
string [*] Except Rows.Next which cannot return string
time.Time
Esto define una interfaz para la conversión de los valores normales para driver.Value.
type ValueConverter interface {
ConvertValue(v interface{}) (Value, error)
}
Esto es comúnmente utilizado en los controladores de base de datos y tiene muchas buenas características
- Convertir driver.Value al correspondiente tipo de campo de base de datos, por ejemplo, convertir a int64 Uint16.
- Convertir los resultados de consultas de bases de datos para driver.Value.
- Convert Convertir driver.Value al usuario el valor definido en
scan
función.
Esto define una interfaz para el retorno de driver.Value.
type Valuer interface {
Value() (Value, error)
}
Muchos tipos implementan esta interfaz para la conversión entre driver.Value y ella misma.
En este punto, usted debe tener conceptos acerca de cómo desarrollar un controlador de base de datos. Una vez implementada sobre interfaces para operaciones como añadir, eliminar, actualizar, etc No sólo dejó problemas sobre la comunicación con la base de datos específica.
databse/sql define métodos más alto nivel por encima de database/sql/driver para un manejo más cómodo con las bases de datos, y le sugiere implementar un grupo de conexiones.
type DB struct {
driver driver.Driver
dsn string
mu sync.Mutex // protects freeConn and closed
freeConn []driver.Conn
closed bool
}
Como puede ver, la función Abrir devuelve un DB que tiene un freeConn, y este es el grupo de conexión simple. Su implementación es muy simple , utiliza defer db.putConn(ci, err)
en función Db.prepare poner la conexión en la agrupación de conexiones. Cada vez que se llama a la función Conn, comprueba la longitud de freeCoon, si es mayor que 0 significa que hay una conexión directa reutilizable y vuelve, de lo contrario crea y retorna una nueva.
- Indice
- Sección anterior: Base de datos
- Siguiente sección: MySQL