added translation to chapter 5, thanks to @carlochess for corrections
This commit is contained in:
125
es/05.2.md
Normal file
125
es/05.2.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# 5.2 MySQL
|
||||
|
||||
La pila LAMP ha sido muy popular en internet los últimos años. La M en LAMP significa MySQL. MySQL es famoso porque es de código abierto y fácil de usar. También porque viene como base de datos por defecto en el backend de muchos sitios web.
|
||||
|
||||
## Manejadores MySQL
|
||||
|
||||
Existen varios manejadores que soportan MySQL en Go. Algunos de ellos implementan la interfaz `database/sql`, y otros usan sus propias interfaces estándares.
|
||||
|
||||
- [https://github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) soporta `database/sql`, está escrita en Go puro.
|
||||
- [https://github.com/ziutek/mymysql](https://github.com/ziutek/mymysql) soporta `database/sql` e interfaces definidas por el usuario, está escrita en Go puro.
|
||||
|
||||
Usaré el primer manejador en los siguientes ejemplos (uso este en mis proyectos personales también) y también lo recomiendo por las siguientes razones:
|
||||
|
||||
- Es un manejador de bases de datos nuevo y suporta muchas características
|
||||
- Soporta completamente la interfaz `database/sql`
|
||||
- Soporta el keep-alive, conexiones largas con seguridad entre hilos
|
||||
|
||||
## Ejemplos
|
||||
|
||||
En las siguientes secciones usaré las misma estructura de tablas para diferentes bases de datos, luego crear la base de datos de la siguiente manera:
|
||||
```
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INT(10) NOT NULL AUTO_INCREMENT,
|
||||
`username` VARCHAR(64) NULL DEFAULT NULL,
|
||||
`departname` VARCHAR(64) NULL DEFAULT NULL,
|
||||
`created` DATE NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`uid`)
|
||||
);
|
||||
```
|
||||
El siguiente ejemplo muestra como operar en bases de datos con los estándares de `database/sql`.
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("mysql", "astaxie:astaxie@/test?charset=utf8")
|
||||
checkErr(err)
|
||||
|
||||
// insertar
|
||||
stmt, err := db.Prepare("INSERT userinfo SET username=?,departname=?,created=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
|
||||
checkErr(err)
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(id)
|
||||
// actualizar
|
||||
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
// consultar
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created string
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println(uid)
|
||||
fmt.Println(username)
|
||||
fmt.Println(department)
|
||||
fmt.Println(created)
|
||||
}
|
||||
|
||||
// eliminar
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
db.Close()
|
||||
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
Permítanme explicar algunas de las funciones importantes aquí:
|
||||
|
||||
- `sql.Open()` abre un manejador de bases de datos registrado. Go-MySQL-Driver registra el manejador de MySQL aquí. El segundo argumento es el DSN (Data Source Name) que define la información para realizar la conexión con la base de datos. Soporta los siguientes formatos:
|
||||
```
|
||||
user@unix(/path/to/socket)/dbname?charset=utf8
|
||||
user:password@tcp(localhost:5555)/dbname?charset=utf8
|
||||
user:password@/dbname
|
||||
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname
|
||||
```
|
||||
- `db.Prepare()` retorna la operación que va a ser ejecutada. También reetorna el estado de ejecución después de ejecutar el SQL.
|
||||
- `db.Query()` ejecuta el SQL y retorna el resultado en Rows
|
||||
- `stmt.Exec()` ejecuta el SQL que ha sido preparado y almacenado en un Stmt
|
||||
|
||||
Note que usamos el formato `=?` para pasar argumentos. Esto es necesario para prevenir ataques de inyección SQL.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección previa: [Interfaz database/sql](05.1.md)
|
||||
- Siguiente sección: [SQLite](05.3.md)
|
||||
149
es/05.3.md
Normal file
149
es/05.3.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 5.3 SQLite
|
||||
|
||||
SQLite es una base de datos embebida de código abierto. Es una base de datos contenida en si misma, tiene 0 configuracieon y soporta transacciones. Es altamente portable, fácil de usar, compacta, eficiente y confiable. En la mayoría de los casos solamente se necesita crear una archivo de base de datos para crear conectarse y operar en una base de datos. Si estás buscando una solución embebida, SQLite es una opción para considerar. Se puede decir que SQLite es una versión de código abierto de Access.
|
||||
|
||||
## Manejadores SQLite
|
||||
|
||||
Existen muchos manejadores de bases de datos para SQLite en Go, pero muchos de ellos no soportan los estándares de la interfaz `database/sql`.
|
||||
|
||||
- [https://github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) soporta `database/sql`, basado en cgo
|
||||
- [https://github.com/feyeleanor/gosqlite3](https://github.com/feyeleanor/gosqlite3) no soporta `database/sql`, basado en cgo.
|
||||
- [https://github.com/phf/go-sqlite3](https://github.com/phf/go-sqlite3) no soporta `database/sql`, basado en cgo.
|
||||
|
||||
El primer manejador es el único que soporta los estándares de la interfaz `database/sql`, por esto lo uso en mis proyectos, ya que será mas fácil migrar el código en el futuro si lo necesito.
|
||||
|
||||
## Ejemplos
|
||||
|
||||
Crearemos el siguiente SQL:
|
||||
```
|
||||
CREATE TABLE `userinfo` (
|
||||
`uid` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`username` VARCHAR(64) NULL,
|
||||
`departname` VARCHAR(64) NULL,
|
||||
`created` DATE NULL
|
||||
);
|
||||
```
|
||||
Un ejemplo:
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("sqlite3", "./foo.db")
|
||||
checkErr(err)
|
||||
|
||||
// insertar
|
||||
stmt, err := db.Prepare("INSERT INTO userinfo(username, departname, created) values(?,?,?)")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
|
||||
checkErr(err)
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(id)
|
||||
// actualizar
|
||||
stmt, err = db.Prepare("update userinfo set username=? where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec("astaxieupdate", id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
// consultar
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created time.Time
|
||||
|
||||
for rows.Next() {
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println(uid)
|
||||
fmt.Println(username)
|
||||
fmt.Println(department)
|
||||
fmt.Println(created)
|
||||
}
|
||||
|
||||
rows.Close() // Buen hábito cerrar
|
||||
|
||||
// eliminar
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=?")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(id)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect)
|
||||
|
||||
db.Close()
|
||||
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
Puedes notar que el código es casi el mismo que en la sección pasada, y es porque solamente cambiamos el nombre del manejador de bases de datos registrado llamando a `sql.Open` para conectarnos a SQLite de una manera diferente.
|
||||
|
||||
Nota que algunas veces no puedes usar la sentencia `for` porque no tienes mas de una fila, entonces puedes usar la sentencia `if`:
|
||||
```
|
||||
if rows.Next() {
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println(uid)
|
||||
fmt.Println(username)
|
||||
fmt.Println(department)
|
||||
fmt.Println(created)
|
||||
}
|
||||
```
|
||||
También tienes que ahcer un `rows.Next()` sin usar eso que no puedes obtener en la función `Scan`.
|
||||
|
||||
Transacciones
|
||||
=============
|
||||
|
||||
El ejemplo de arriba muestra como puedes obtener datos de una base de datos, pero cuando quieres escribir aplicaciones web, no solo vas a consultar información de la base de datos sino que también quieres escribir en ella. Para este propósito tu puedes usar transacciones, porque puedes tener múltiples rutinas que accesan a la base de datos, y la base de datos se podría bloquear. Esto no es deseable en una aplicación web y el uso de transacciones es efectivo asegurando que las operaciones sean exitosas en total o fallen completamente, dependiendo de las circunstancias. Es claro que el uso de transacciones puede prevenir un montón de problemas que pueden ocurrir en una aplicación web.
|
||||
```
|
||||
trashSQL, err := database.Prepare("update task set is_deleted='Y',last_modified_at=datetime() where id=?")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
tx, err := database.Begin()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
_, err = tx.Stmt(trashSQL).Exec(id)
|
||||
if err != nil {
|
||||
fmt.Println("doing rollback")
|
||||
tx.Rollback()
|
||||
} else {
|
||||
tx.Commit()
|
||||
}
|
||||
```
|
||||
Como es claro en el código de arribam primero debes prepara un Statement, después debes ejecutarlo, dependiendo de la salida de esa ejecución, puedes volver atrás o mantenerlo.
|
||||
|
||||
Como última nota de esta sección, aquí está una herramienta de mantenimiento para SQLite: [http://sqlitebrowser.org](http://sqlitebrowser.org)
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección anterior: [MySQL](05.2.md)
|
||||
- Siguiente sección: [PostgreSQL](05.4.md)
|
||||
123
es/05.4.md
Normal file
123
es/05.4.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# 5.4 PostgreSQL
|
||||
|
||||
PostgreSQL es una base de datos relacional y de objetos disponible en muchas plataformas incluyendo Linux, FreeBSD, Solaris, Microsoft Windows y Mac OS X. Fue liberada bajo la licencia MIT y por eso es gratuita y de código abierto. Es más grande que MySQL porque está diseñada para uso empresarial y es una alternativa a Oracle. PostgreSQL es una buena elección para proyectos empresariales.
|
||||
|
||||
## Manejadores PostgreSQL
|
||||
|
||||
Existen muchos manejadores de bases de datos para PostgreSQL. Aquí hay algunos ejemplos de ellos:
|
||||
|
||||
- [https://github.com/bmizerany/pq](https://github.com/lib/pq) soporta `database/sql`, escrita en Go puro.
|
||||
- [https://github.com/jbarham/gopgsqldriver](https://github.com/jbarham/gopgsqldriver) soporta `database/sql`, escrita en Go puro
|
||||
- [https://github.com/lxn/go-pgsql](https://github.com/lxn/go-pgsql) soporta `database/sql`, escrita en Go puro
|
||||
|
||||
Usaré el primer ejemplo para explicar lo que sigue.
|
||||
|
||||
## Ejemplos
|
||||
|
||||
Crearemos el siguiente SQL:
|
||||
```
|
||||
CREATE TABLE userinfo
|
||||
(
|
||||
uid serial NOT NULL,
|
||||
username character varying(100) NOT NULL,
|
||||
departname character varying(500) NOT NULL,
|
||||
Created date,
|
||||
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
|
||||
)
|
||||
WITH (OIDS=FALSE);
|
||||
```
|
||||
Un ejemplo:
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/lib/pq"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DB_USER = "postgres"
|
||||
DB_PASSWORD = "postgres"
|
||||
DB_NAME = "test"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
|
||||
DB_USER, DB_PASSWORD, DB_NAME)
|
||||
db, err := sql.Open("postgres", dbinfo)
|
||||
checkErr(err)
|
||||
defer db.Close()
|
||||
|
||||
fmt.Println("# Inserting values")
|
||||
|
||||
var lastInsertId int
|
||||
err = db.QueryRow("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;", "astaxie", "研发部门", "2012-12-09").Scan(&lastInsertId)
|
||||
checkErr(err)
|
||||
fmt.Println("last inserted id =", lastInsertId)
|
||||
|
||||
fmt.Println("# Updating")
|
||||
stmt, err := db.Prepare("update userinfo set username=$1 where uid=$2")
|
||||
checkErr(err)
|
||||
|
||||
res, err := stmt.Exec("astaxieupdate", lastInsertId)
|
||||
checkErr(err)
|
||||
|
||||
affect, err := res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "rows changed")
|
||||
|
||||
fmt.Println("# Querying")
|
||||
rows, err := db.Query("SELECT * FROM userinfo")
|
||||
checkErr(err)
|
||||
|
||||
for rows.Next() {
|
||||
var uid int
|
||||
var username string
|
||||
var department string
|
||||
var created time.Time
|
||||
err = rows.Scan(&uid, &username, &department, &created)
|
||||
checkErr(err)
|
||||
fmt.Println("uid | username | department | created ")
|
||||
fmt.Printf("%3v | %8v | %6v | %6v\n", uid, username, department, created)
|
||||
}
|
||||
|
||||
fmt.Println("# Deleting")
|
||||
stmt, err = db.Prepare("delete from userinfo where uid=$1")
|
||||
checkErr(err)
|
||||
|
||||
res, err = stmt.Exec(lastInsertId)
|
||||
checkErr(err)
|
||||
|
||||
affect, err = res.RowsAffected()
|
||||
checkErr(err)
|
||||
|
||||
fmt.Println(affect, "rows changed")
|
||||
}
|
||||
|
||||
func checkErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
Nota que PostgreSQL usa el formato `$1, $2` en vez del `?` de MySQL, y tiene un formato distinto de DSN en el `sql.Open`
|
||||
Otra cosa es que el manejador de PostgreSQL no soporta el `sql.Result.LastInsertId()`.
|
||||
Entonces en lugar de
|
||||
```
|
||||
stmt, err := db.Prepare("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3);")
|
||||
res, err := stmt.Exec("astaxie", "研发部门", "2012-12-09")
|
||||
fmt.Println(res.LastInsertId())
|
||||
```
|
||||
usa `db.QueryRow()` y `.Scan()` para obtener el último valor insertado.
|
||||
```
|
||||
err = db.QueryRow("INSERT INTO TABLE_NAME values($1) returning uid;", VALUE1").Scan(&lastInsertId)
|
||||
fmt.Println(lastInsertId)
|
||||
```
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección anterior : [SQLite](05.3.md)
|
||||
- Siguiente sección: [Desarrollo de un ORM basado en beedb](05.5.md)
|
||||
256
es/05.5.md
Normal file
256
es/05.5.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# 5.5 Desarrollo de un ORM basado en beedb
|
||||
( ***El proyecto beedb no está mantenido actualmente, pero el código sigue ahí*** )
|
||||
( ***Project beedb is no longer maintained, but the code s still there*** )
|
||||
|
||||
beedb es un ORM ( object relational mapper ) desarrollado en Go, por mi.
|
||||
Usa el lenguaje ideomático de Go para operar con las bases de datos, implementando un mapeo de estructura a base de datos que actua como un Framework ORM liviano de Go. El propósito de desarrollar este ORM no es solamente ayudar a la gente a aprender como implementar un ORM, sino también encontrar un buen balance entre funcionalidad y desempeño en lo que respecta a persistencia de datos.
|
||||
|
||||
beedb es un proyecto de código abierto que soporta la funcionalidad básica de un ORM, pero no soporta las consultas asociativas.
|
||||
|
||||
Como beedb soporta los estándares de la interfaz `database/sql` cualquier manejador que implemente esta interfaz podrá ser usado con beedb. Yo lo he probado con los siguientes manejadores:
|
||||
|
||||
Mysql: [github.com/ziutek/mymysql/godrv](github.com/ziutek/mymysql/godrv)
|
||||
|
||||
Mysql: [code.google.com/p/go-mysql-driver](code.google.com/p/go-mysql-driver)
|
||||
|
||||
PostgreSQL: [github.com/bmizerany/pq](github.com/bmizerany/pq)
|
||||
|
||||
SQLite: [github.com/mattn/go-sqlite3](github.com/mattn/go-sqlite3)
|
||||
|
||||
MS ADODB: [github.com/mattn/go-adodb](github.com/mattn/go-adodb)
|
||||
|
||||
ODBC: [bitbucket.org/miquella/mgodbc](bitbucket.org/miquella/mgodbc)
|
||||
|
||||
## Instalación
|
||||
|
||||
Puedes usar el comando `go get` para instalar beedb localmente.
|
||||
```
|
||||
go get github.com/astaxie/beedb
|
||||
```
|
||||
## Inicialización
|
||||
|
||||
Primero debes importar los paquetes necesarios:
|
||||
```
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/astaxie/beedb"
|
||||
_ "github.com/ziutek/mymysql/godrv"
|
||||
)
|
||||
```
|
||||
Luego necesitas abrir la conexión a la base de datos y crear un objeto beedb (MySQL en este ejemplo):
|
||||
```
|
||||
db, err := sql.Open("mymysql", "test/xiemengjun/123456")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
orm := beedb.New(db)
|
||||
```
|
||||
`beedb.New()` actualmente toma dos argumentos. El primero es el objeto de la base de datos y el segundo es para indicar que motor de base de datos estás usando. Si estás usando MySQL o SQLite puedes omitir el segundo argumento.
|
||||
|
||||
De otra manera, este argumento debe ser incluido, por ejemplo en el caso de SQLServer:
|
||||
```
|
||||
orm = beedb.New(db, "mssql")
|
||||
```
|
||||
PostgreSQL:
|
||||
```
|
||||
orm = beedb.New(db, "pg")
|
||||
```
|
||||
beedb soporta depuración. Usa el siguiente código para habilitarla:
|
||||
```
|
||||
beedb.OnDebug=true
|
||||
```
|
||||
Después debemos tener una estructura para la tabla `Userinfo` que hemos usado en las secciones anteriores.
|
||||
```
|
||||
type Userinfo struct {
|
||||
Uid int `PK` // Si la llave primaria no es id, necesitas añadir la etiqueta `PK` para una llave primaria personalizada.
|
||||
Username string
|
||||
Departname string
|
||||
Created time.Time
|
||||
}
|
||||
```
|
||||
Se conciente que beedb autoconvierte la notación de camello a notación de guiones bajos. Por ejemplo, si tenemos `UserInfo` como el nombre de la estructura, beedb lo convertirá a `user_info` en la base de datos. La misma regla se aplica para los nombres de campos de la estructura.
|
||||
|
||||
## Insertar datos
|
||||
|
||||
El siguiente ejemplo muestra como usar beedb a guardar una estructura en vez de usar comandos planos de SQL. Usamos el método `Save` de beedb para aplicar el cambio.
|
||||
```
|
||||
var saveone Userinfo
|
||||
saveone.Username = "Test Add User"
|
||||
saveone.Departname = "Test Add Departname"
|
||||
saveone.Created = time.Now()
|
||||
orm.Save(&saveone)
|
||||
```
|
||||
Puedes verificar el campo `saveone.Uid` después de que este registro es insertado; su valor es un identificador autoincrementado por el que el método `Save` se ocupa por ti.
|
||||
|
||||
beedb provee otra manera de insertar datos, usando el estilo de mapas de Go.
|
||||
```
|
||||
add := make(map[string]interface{})
|
||||
add["username"] = "astaxie"
|
||||
add["departname"] = "cloud develop"
|
||||
add["created"] = "2012-12-02"
|
||||
orm.SetTable("userinfo").Insert(add)
|
||||
```
|
||||
Insertando varios datos:
|
||||
```
|
||||
addslice := make([]map[string]interface{}, 10)
|
||||
add:=make(map[string]interface{})
|
||||
add2:=make(map[string]interface{})
|
||||
add["username"] = "astaxie"
|
||||
add["departname"] = "cloud develop"
|
||||
add["created"] = "2012-12-02"
|
||||
add2["username"] = "astaxie2"
|
||||
add2["departname"] = "cloud develop2"
|
||||
add2["created"] = "2012-12-02"
|
||||
addslice = append(addslice, add, add2)
|
||||
orm.SetTable("userinfo").InsertBatch(addslice)
|
||||
```
|
||||
El método mostrado arriba es similar a una consulta encadenada, la cual te podría ser familiar si has usado jQuery. Retorna el objeto del ORM después de la llamada, entonces continua haciendo otros trabajos.
|
||||
|
||||
El método `SetTable` le dice al ORM que queremos insertar nuestra data en la tabla `userinfo`.
|
||||
|
||||
## Actualizar datos
|
||||
|
||||
Continuemos trabajando con el ejemplo de arriba, para ver como actualizar los datos. Ahora que tenemos la llave primeria de `saveone(Uid)`, beedb ejecuta una operación de actualizacieon en lugar de insertar un nuevo registro.
|
||||
```
|
||||
saveone.Username = "Update Username"
|
||||
saveone.Departname = "Update Departname"
|
||||
saveone.Created = time.Now()
|
||||
orm.Save(&saveone) // update
|
||||
```
|
||||
Como antes, también puedes usar un mapa para actualizar los datos:
|
||||
```
|
||||
t := make(map[string]interface{})
|
||||
t["username"] = "astaxie"
|
||||
orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)
|
||||
```
|
||||
Permíteme explicar algunos de los métodos usados arriba:
|
||||
|
||||
- `.SetPK()` le dice al ORM que `uid` es la llave primaria del registro en la tabla `userinfo`
|
||||
- `.Where()` define condiciones y suporta múltiples argumentos. Si el primer arguento es un entero, es una manera de acortar `Where("<llave primaria>=?", <valor>)`.
|
||||
- `.Update()` acepta un mapa y actualiza la base de datos.
|
||||
|
||||
## Consultado datos
|
||||
|
||||
Las consultas con la interface beedb son muy fleibles. Veamos algunos ejemplos:
|
||||
|
||||
Ejemplo 1: Consultando por llaves primarias:
|
||||
```
|
||||
var user Userinfo
|
||||
// Where acepta dos argumentos, el segundo entero
|
||||
orm.Where("uid=?", 27).Find(&user)
|
||||
```
|
||||
Ejemplo 2:
|
||||
```
|
||||
var user2 Userinfo
|
||||
orm.Where(3).Find(&user2) // Forma corta que omite el nombre de la llave primaria
|
||||
```
|
||||
Ejemplo 3, otras condiciones de consulta
|
||||
```
|
||||
var user3 Userinfo
|
||||
// Where acepta dos argumentos, el segundo cadena
|
||||
orm.Where("name = ?", "john").Find(&user3)
|
||||
```
|
||||
Ejemplo 4, condiciones mas complicadas:
|
||||
```
|
||||
var user4 Userinfo
|
||||
// Where con tres argumentos aceptados
|
||||
orm.Where("name = ? and age < ?", "john", 88).Find(&user4)
|
||||
```
|
||||
Ejemplos para obtener múltiples registros
|
||||
|
||||
Ejemplo 1, Obtiene 10 registros donde `id>3` Que comienzan en la posición 20
|
||||
```
|
||||
var allusers []Userinfo
|
||||
err := orm.Where("id > ?", "3").Limit(10,20).FindAll(&allusers)
|
||||
```
|
||||
Ejemplo 2, omite el segundo argumento de límite, entonces comienza en 0 y obtiene 10 registros:
|
||||
```
|
||||
var tenusers []Userinfo
|
||||
err := orm.Where("id > ?", "3").Limit(10).FindAll(&tenusers)
|
||||
```
|
||||
Ejemplo 3, obtener todos los recursos:
|
||||
```
|
||||
var everyone []Userinfo
|
||||
err := orm.OrderBy("uid desc,username asc").FindAll(&everyone)
|
||||
```
|
||||
Como puedes ver, el método límite es para limitar el número de resultados.
|
||||
|
||||
- `.Limit()` suporta dos argumentos: el número de resultados comenzando en la posición. 0 es el valor por defecto de posición inicial.
|
||||
- `.OrderBy()` es para ordenar resultados. El argumento es la condición de orden.
|
||||
|
||||
Todos los ejemplos aquí simplemente mapean registros a estructuras. También puedes colocar data en un mapa como sigue:
|
||||
```
|
||||
a, _ := orm.SetTable("userinfo").SetPK("uid").Where(2).Select("uid,username").FindMap()
|
||||
```
|
||||
- `.Select()` le dice a beedb cuantos campos quieres obtener desde la tabla de la base de datos. Si no es especifica, todos los registros son retornados por defecto.
|
||||
- `.FindMap()` retorna el tipo `[]map[String][]byte`, entonces puedes convertir a otros tipos tu mismo.
|
||||
|
||||
## Eliminar datos
|
||||
|
||||
beedb provee métodos amplios para eliminar datos.
|
||||
|
||||
Ejemplo 1, eliminar un único registro
|
||||
```
|
||||
// saveone es el mismo del ejemplo anterior.
|
||||
orm.Delete(&saveone)
|
||||
```
|
||||
Ejemplo 2, elimintar todos los usuarios
|
||||
```
|
||||
// alluser es un segmento que tiene múltiples usuarios
|
||||
orm.DeleteAll(&alluser)
|
||||
```
|
||||
Ejemplo 3, Eliminar registros con SQL
|
||||
```
|
||||
orm.SetTable("userinfo").Where("uid>?", 3).DeleteRow()
|
||||
```
|
||||
## Consultas de asociación
|
||||
|
||||
beedb no soportar uniones entre asociaciones.
|
||||
Sin embargo, desde que algunas aplicaciones necesitan esta caractarísticas, aquí está una implementación:
|
||||
```
|
||||
a, _ := orm.SetTable("userinfo").Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid")
|
||||
.Where("userinfo.uid=?", 1).Select("userinfo.uid,userinfo.username,userdetail.profile").FindMap()
|
||||
```
|
||||
Nosotros vemos un método llamado `.Join()` que toma tres argumentos
|
||||
- El primer argumento: Tipo del Join; INNER, LEFT, OUTER, CROSS, etc.
|
||||
- El segundo argumento: la tabla con la que quieres hacer la unión
|
||||
- El tercer argumento: la condición de Join
|
||||
|
||||
## Group By y Having
|
||||
|
||||
beedb también tiene una implementación de `group by` y `having`.
|
||||
```
|
||||
a, _ := orm.SetTable("userinfo").GroupBy("username").Having("username='astaxie'").FindMap()
|
||||
```
|
||||
- `.GroupBy()` indica el campo con el que se va a agrupar.
|
||||
- `.Having()` indica la condición del `having`.
|
||||
|
||||
## Futuro
|
||||
|
||||
He recibido un montón de retroalimentación de beedb de muchas personas al rededor del mundo y estoy pensando en reconfigurar los siguientes aspectos:
|
||||
|
||||
- Implementar una interfaz similar a `database/sql/driver` en orden de facilitar las operaciones CRUD
|
||||
- Implementar asociaciones de bases de datos relacionales como uno a uno, muchos a uno y muchos a muchos.
|
||||
|
||||
Aquí hay un ejemplo:
|
||||
```
|
||||
type Profile struct {
|
||||
Nickname string
|
||||
Mobile string
|
||||
}
|
||||
type Userinfo struct {
|
||||
Uid int
|
||||
PK_Username string
|
||||
Departname string
|
||||
Created time.Time
|
||||
Profile HasOne
|
||||
}
|
||||
```
|
||||
- Auto crear tablas e indices.
|
||||
- Implementar una piscina de conexiones usando rutinas.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección previa: [PostgreSQL](05.4.md)
|
||||
- Siguiente sección section: [Bases de Datos NoSQL](05.6.md)
|
||||
113
es/05.6.md
Normal file
113
es/05.6.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# 5.6 Bases de Datos NoSQL
|
||||
|
||||
Una base de datos NoSQL provee un mecanismo para el almacenamiento y el retorno de información que usa modelos de consistencia menores que bases de datos relacionales en orden de alcanzar escalabilidad horizontal y mayor disponibilidad. Alguns autores se refieren a ellas como "No solamente SQL" para enfatizar que algunos sistemas NoSQL permiten consultas similares a SQL.
|
||||
|
||||
Al ser el lenguaje C del siglo XXI, Go tiene soporte para bases de datos NoSQL, incluyendo populares como redis, mongoDB, Cassandra y Membase.
|
||||
|
||||
## redis
|
||||
|
||||
redis es un sistema de almacenamiento llave valor como Memcached, que soporta los tipos de cadenas, listas conjuntos y conjuntos ordenados.
|
||||
|
||||
Aquí están algunos de los manejadores de bases de datos para redis:
|
||||
|
||||
- [https://github.com/alphazero/Go-Redis](https://github.com/alphazero/Go-Redis)
|
||||
- [http://code.google.com/p/tideland-rdc/](http://code.google.com/p/tideland-rdc/)
|
||||
- [https://github.com/simonz05/godis](https://github.com/simonz05/godis)
|
||||
- [https://github.com/hoisie/redis.go](https://github.com/hoisie/redis.go)
|
||||
|
||||
Realicé una bifurcación de el último de estos paquetes, arreglé algunos servicios y lo usé en mi sistema de acortado de urls (2 millones de peticiones por día).
|
||||
|
||||
- [https://github.com/astaxie/goredis](https://github.com/astaxie/goredis)
|
||||
|
||||
Veamos como usar el manejador que bifurqué para operar con la base de datos:
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/astaxie/goredis"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var client goredis.Client
|
||||
|
||||
// Definir el puerto por defecto de redis
|
||||
client.Addr = "127.0.0.1:6379"
|
||||
|
||||
// Manipulación de cadenas
|
||||
client.Set("a", []byte("hello"))
|
||||
val, _ := client.Get("a")
|
||||
fmt.Println(string(val))
|
||||
client.Del("a")
|
||||
|
||||
// Operaciones con listas
|
||||
vals := []string{"a", "b", "c", "d", "e"}
|
||||
for _, v := range vals {
|
||||
client.Rpush("l", []byte(v))
|
||||
}
|
||||
dbvals,_ := client.Lrange("l", 0, 4)
|
||||
for i, v := range dbvals {
|
||||
println(i,":",string(v))
|
||||
}
|
||||
client.Del("l")
|
||||
}
|
||||
```
|
||||
Como podemos ver es muy sencillo operar redis en Go, y como tiene un alto rendimiento. Los comandos de este cliente son casi lo mismo que los comandos que vienen con redis.
|
||||
|
||||
## mongoDB
|
||||
|
||||
mongoDB (de "humongous" (enorme)) es una bases de datos orientada a documentos de código abierto desarrollado y mantenida por 10gen. Hace parte de la familia de bases de datos NoSQL. En lugar de almacenar la información en tablas como es hecho en bases de datos relacionales 'clasicas', MongoDB guarda la información en estructurada en documentos al estilo JSON con esquemas dinámicos (MongoDB llama el formato BSON) haciendo que la integración de los datos en cierto tipo de aplicaciones sea mas fácil y rápido.
|
||||
|
||||

|
||||
|
||||
Figura 5.1 MongoDB comparada con Mysql
|
||||
|
||||
El mejor manejador para mongoDB es llamado `mgo`, y es posible que se incluya en la librería estándar en el futuro.
|
||||
|
||||
Aquí está un ejemplo
|
||||
```
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"labix.org/v2/mgo"
|
||||
"labix.org/v2/mgo/bson"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Phone string
|
||||
}
|
||||
|
||||
func main() {
|
||||
session, err := mgo.Dial("server1.example.com,server2.example.com")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
session.SetMode(mgo.Monotonic, true)
|
||||
|
||||
c := session.DB("test").C("people")
|
||||
err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
|
||||
&Person{"Cla", "+55 53 8402 8510"})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
result := Person{}
|
||||
err = c.Find(bson.M{"name": "Ale"}).One(&result)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Phone:", result.Phone)
|
||||
}
|
||||
```
|
||||
Como podemos ver no hay muchas diferencias en lo que respecta a operar con mgo o bases de datos beedb; ambas son basadas en estructuras. Esta es la manera en que Go hace las cosas.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección previa: [Desarrollo de un ORM basado en beedb](05.5.md)
|
||||
- Siguiente sección: [Resumen](05.7.md)
|
||||
11
es/05.7.md
Normal file
11
es/05.7.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# 5.7 Resumen
|
||||
|
||||
En este capítulo, primero aprendiste sobre el diseño de la interfaz `database/sql` y varios manejadores de bases de datos para varios tipos de bases de datos. Luego introducimos beedb, un ORM para bases de datos relacionales. También mostramos algunos ejemplos de operaciones con bases de datos. Al final, hablamos sobre algunas bases de datos NoSQL. Vimos como Go provee soporte para estas bases de datos NoSQL.
|
||||
|
||||
Después de leer este capítulo, espero que hayas entendido un poco mas como funcionan las bases de datos en Go. Esta es la parte mas importante del desarrollo web, por eso es importante que entiendas bien los conceptos de la interfaz `database/sql`.
|
||||
|
||||
## Enlaces
|
||||
|
||||
- [Índice](preface.md)
|
||||
- Sección anterior: [Bases de Datos NoSQL ](05.6.md)
|
||||
- Siguiente capítulo: [Almacenamiento de datos y sesiones](06.0.md)
|
||||
Reference in New Issue
Block a user