Skip to content

Commit 436d376

Browse files
author
ma0
committed
translated first two sections of chapter five
1 parent cc95a03 commit 436d376

File tree

2 files changed

+216
-0
lines changed

2 files changed

+216
-0
lines changed

es/05.0.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# 5 Bases de Datos
2+
3+
Para los desarrolladores web, la base de datos está en el núclo del desarrollo web. Puedes guardar casi todo en una base de datos y consultar o actualizar dentro de ella, como información, productos noticias o artículos.
4+
5+
Go no provee ningún manejador para base de datos, pero si provee una interfaz definida en el paquete `database/sql`. Las personas pueden desarrollar manejadores de bases de datos basado en esa interfaz. En la sección 5.1, vamos a hablar sobre el diseño de un manejador de base de datos en Go. En las secciones 5.2 a 5.4 voy a introducir algunos manejadores de bases de datos. En la sección 5.5 voy a presentar un ORM que he diseñado que está basado en el estandar `database/sql`. Es compatible con la mayoría de manejadores que implementan la interfaz `database/sql` y hace fácil acceder a las bases de datos ideomáticamente en Go.
6+
7+
NoSQL ha sido un tópico importante en los últimos años. Muchos sitios web están decidiendo usar bases de datos NoSQL como su base de datos principal, o solo con el propósito de caché. Introduciré dos bases de datos: MongoDB y Redis, en la sección 5.6.
8+
9+
## Enlaces
10+
11+
- [Índice](preface.md)
12+
- Capítulo anterior: [Capítulo 4 Resumen](04.6.md)
13+
- Siguiente sección: [Interfaz database/sql](05.1.md)

es/05.1.md

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# 5.1 Interfaz database/sql
2+
3+
Go no provee ningún manejador de base de datos oficial, a diferencia de otros lenguajes como PHP que si lo hacen. Sin embargo, si provee una estándar de interfaz para que los desarrolladores desarrollen manejadores basados en ella. La ventaja es que si tu código es desarrollado de acuerdo a esa interfaz estándar, no vas a tener que cambiar ningún código si tu base de datos cambia. Veamos cuales son los estándares de esta interface.
4+
5+
## sql.Register
6+
7+
Esta función está en el paquete `database/sql` para registrar una base de datos cuando usas un manejador de base de datos de terceros. Todos deberían llamar a la función `Register(name String, driver driver.Driver)` en la función `init()` en orden de registrarse a si mismas.
8+
9+
Vamos a mirar los corespondientes llamados en el código de mymysql y sqlite3:
10+
```
11+
//manejador https://github.com/mattn/go-sqlite3
12+
func init() {
13+
sql.Register("sqlite3", &SQLiteDriver{})
14+
}
15+
16+
//manejador https://github.com/mikespook/mymysql
17+
// Driver automatically registered in database/sql
18+
var d = Driver{proto: "tcp", raddr: "127.0.0.1:3306"}
19+
func init() {
20+
Register("SET NAMES utf8")
21+
sql.Register("mymysql", &d)
22+
}
23+
```
24+
Vemos que los manejadores de terceros implementan esta función para registrarse a si mismos y Go utiliza un mapa para guardar los manejadores dentro de `database/sql`.
25+
```
26+
var drivers = make(map[string]driver.Driver)
27+
28+
drivers[name] = driver
29+
```
30+
Así, la función de registro puede registrar tantos manejadores como requieras, cada uno con un nombre diferente.
31+
32+
Siempre veremos el siguiente código cuando usemos manejadores de terceros:
33+
```
34+
import (
35+
"database/sql"
36+
_ "github.com/mattn/go-sqlite3"
37+
)
38+
```
39+
Aquí, el guión bajo, (también llamado 'blank') `_` puede ser un poco confuso para muchos principiantes, pero es una gran característica de Go. Sabemos que el identificador de guión bajo es usado para no guardar valores que una función retorna, y también que debes usar todos los paquetes que importes en tu código Go. Entonces, cuando el guión bajo es usado con un import, significa que necesitas ejecutar la función init() de ese paquete sin usarlo directamente. lo cual encaja perfectamente en el caso de registrar el manejador de base de datos.
40+
41+
## driver.Driver
42+
43+
`Driver` es una interface que contiene un método `Open(name string)` que retorna una interfaz `Conn`.
44+
```
45+
type Driver interface {
46+
Open(name string) (Conn, error)
47+
}
48+
```
49+
Esta es una conexión de una vez, que significa que solamente puede ser usada una vez por rutina. El siguiente código causará errores:
50+
```
51+
...
52+
go goroutineA (Conn) // query
53+
go goroutineB (Conn) // insert
54+
...
55+
```
56+
Porque no no tiene idea de que rutina va a realizar cada operación, la operación de consulta podría obtener el resultado de la operación de incersión y viceversa.
57+
58+
Todos los manejadores de terceros debería tener esta función para analizar el nombre de una Conn y retornar el resultado correcto.
59+
60+
## driver.Conn
61+
62+
Esta es la interfaz de conexión con algunos métodos, como dije aarriba, la misma conexión solo puede usarse una vez por rutina.
63+
```
64+
type Conn interface {
65+
Prepare(query string) (Stmt, error)
66+
Close() error
67+
Begin() (Tx, error)
68+
}
69+
```
70+
- `Prepare` retorna el estado del comando SQL ejecutado para consultas, eliminaciones, etc.
71+
- `Close` cierra la conexión actual y limpia los recursos. La mayoría de paquetes de terceros implementan algún tipo de piscina de conexiones, así que no necesitas almacenar las conexiones que puedan causar errores.
72+
- `Begin` retorna un Tx que representa una transacción para manejar. Puedes usarlo para consultar, almacenar, o volver hacia atrás algunas transacciones.
73+
74+
## driver.Stmt
75+
76+
Este es un estado de listo que corresponde con una Conn, y solamente puede ser usada una vez por rutina (como en el caso de Conn).
77+
```
78+
type Stmt interface {
79+
Close() error
80+
NumInput() int
81+
Exec(args []Value) (Result, error)
82+
Query(args []Value) (Rows, error)
83+
}
84+
```
85+
- `Close` cierra la conexión actual, pero sigue retornando la información de la ejecución de una operación de consulta.
86+
- `NumInput` retorna el número de argumentos obligados. Los manejadores de bases de datos debería revisar la cantidad de argumentos cuando los resultados son mayor que 0, y retorna -1 cuando el manejador de la base de datos no conoce ningún argumento obligado.
87+
- `Exec` ejecuta un comando `update/insert` preparados en `Prepare`, retorna un `Result`.
88+
- `Query` ejecuta un comando `select` preparado en `Prepare`, retorna información.
89+
90+
## driver.Tx
91+
92+
Generalmente, las transacciones únicamente tienen métodos de envío y de vuelta atrás, y el manejador de las bases de datos solo necesita implementar estos dos métodos.
93+
```
94+
type Tx interface {
95+
Commit() error
96+
Rollback() error
97+
}
98+
```
99+
## driver.Execer
100+
Esta es una interfaz opcional.
101+
```
102+
type Execer interface {
103+
Exec(query string, args []Value) (Result, error)
104+
}
105+
```
106+
El el manejador no implementa esta interfaz, cuando llame `DB.Exec`, automáticamente llamará `Prepare`, retornará un `Stmt`. Después ejecutará el método `Exec` de `Smtt`, y cerrará el `Smtm`.
107+
108+
## driver.Result
109+
110+
Esta es la interface para los operaciones de `update/insert`.
111+
```
112+
type Result interface {
113+
LastInsertId() (int64, error)
114+
RowsAffected() (int64, error)
115+
}
116+
```
117+
- `LastInsertId` retorna el identificador de autoincremento después de una operación de inserción.
118+
- `RowsAffected` retorna la cantidad de filas afectadas por la operación.
119+
120+
## driver.Rows
121+
122+
Esta interfaz es el resultado de una operación de consulta.
123+
```
124+
type Rows interface {
125+
Columns() []string
126+
Close() error
127+
Next(dest []Value) error
128+
}
129+
```
130+
- `Columns` retorna la información de los campos de la base de datos. El segmento tiene correspondencia con los campos SQL únicamente. y no retorna todos los campos de la tabla de la base de datos.
131+
- `Close` cierra el iterador sobre las columnas.
132+
- `Next` retorna la siguiente información y la asigna a dest, convirtiendo todas las cadenas en arreglos de bytes, y retorna un error io.EOF si no existe mas data disponible.
133+
134+
## driver.RowsAffected
135+
136+
Este es un alias para int64, pero implementado por la interfaz Result.
137+
```
138+
type RowsAffected int64
139+
140+
func (RowsAffected) LastInsertId() (int64, error)
141+
142+
func (v RowsAffected) RowsAffected() (int64, error)
143+
```
144+
## driver.Value
145+
146+
Esta es una interfaz vacía que contiene cualquier tipo de información.
147+
```
148+
type Value interface{}
149+
```
150+
El `Value` debe ser algo con lo que los manejadores puedan operar, o nil, así que debería ser alguno de los siguientes tipos:
151+
```
152+
int64
153+
float64
154+
bool
155+
[]byte
156+
string [*] Exceptuando los Rows.Next, que no puede retornar una cadena.
157+
time.Time
158+
```
159+
## driver.ValueConverter
160+
161+
Define una interfaz para convertir valores nativos en valores de driver.Value.
162+
```
163+
type ValueConverter interface {
164+
ConvertValue(v interface{}) (Value, error)
165+
}
166+
```
167+
Esta interfaz es comunmente usada en manejadores de bases de datos y tiene muchas características útiles:
168+
169+
- Convierte un driver.Value al tipo de campo correspondiente, por ejemplo convierte un int64 a un uint16.
170+
- Conviernte una consulta de base de datos a un driver.Value.
171+
- Conviernte un driver.Value a un usuario definido en la función `scan`.
172+
173+
## driver.Valuer
174+
175+
Define una interfaz para devolver un driver.Value.
176+
```
177+
type Valuer interface {
178+
Value() (Value, error)
179+
}
180+
```
181+
Muchos tipos implementan esta interface para la conversión entre driver.Value y ellos mismos.
182+
183+
En este punto, deberías saber un poco mas sobre el desarrollo de manejadores de bases de datos en Go. una vez que hayas implementado interfaces para operaciones como agregar, eliminar, actualizar, etc, existirán algunos problemas relacionados con comunicarse específicamente con algún tipo de bases de datos.
184+
185+
## database/sql
186+
187+
`database/sql` define en un alto nivel métodos existentes en `database/sql/driver` para tener las operaciones en un nivel mas conveniente, y sugiera que implementes una piscina de conexiones.
188+
```
189+
type DB struct {
190+
driver driver.Driver
191+
dsn string
192+
mu sync.Mutex // protects freeConn and closed
193+
freeConn []driver.Conn
194+
closed bool
195+
}
196+
```
197+
Como puedes ver, la función `Open` retorna una base de datos que tiene una `freeConn`, y esta es una piscina de conexiones simple. Su implementación es simple y fea. Usa `defer db.putConn(ci, err)` en la función `Db.Prepare` para colocar una conexión en la piscina de conexiones. Siempre que se vaya a llamar la función `Conn`, verifica la longitud de `freeConn`. Si es mayor a 0, significa que hay una conexión reusable y la retorna directamente a ti. De otra manera, crea una nueva conexión y la retorna.
198+
199+
## Enlaces
200+
201+
- [Índice](preface.md)
202+
- Sección anterior: [Bases de Datos](05.0.md)
203+
- Sección siguiente: [MySQL](05.2.md)

0 commit comments

Comments
 (0)