完成gaes包开发

This commit is contained in:
john
2018-08-09 12:46:13 +08:00
19 changed files with 402 additions and 324 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ gitpush.sh
pkg/
bin/
cbuild
*/.DS_Store

2
TODO
View File

@ -15,7 +15,7 @@ ghttp获取参数支持直接转struct功能
map转struct增加对tag的支持
gcache检查在i386下的int64->int转换问题
gfsnotify增加对于目录的监控
orm增加sqlite对Save方法的支持(去掉触发器语句);
DONE:
1. gconv完善针对不同类型的判断例如尽量减少sprintf("%v", xxx)来执行string类型的转换

View File

@ -9,31 +9,38 @@ package gaes
import (
"bytes"
"errors"
"crypto/aes"
"crypto/cipher"
"errors"
)
const (
ivDefValue = "I Love Go Frame!"
)
func Encrypt(plaintext []byte, key []byte) ([]byte, error) {
// AES加密, 使用CBC模式注意key必须为16/24/32位长度iv初始化向量为非必需参数
func Encrypt(plainText []byte, key []byte, iv...[]byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
plaintext = PKCS5Padding(plaintext, blockSize)
iv := []byte(ivDefValue)
blockMode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
blockMode.CryptBlocks(ciphertext, plaintext)
plainText = PKCS5Padding(plainText, blockSize)
ivValue := ([]byte)(nil)
if len(iv) > 0 {
ivValue = iv[0]
} else {
ivValue = []byte(ivDefValue)
}
blockMode := cipher.NewCBCEncrypter(block, ivValue)
ciphertext := make([]byte, len(plainText))
blockMode.CryptBlocks(ciphertext, plainText)
return ciphertext, nil
}
func Decrypt(cipherText []byte, key []byte) ([]byte, error) {
// AES解密, 使用CBC模式注意key必须为16/24/32位长度iv初始化向量为非必需参数
func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
@ -42,16 +49,21 @@ func Decrypt(cipherText []byte, key []byte) ([]byte, error) {
if len(cipherText) < blockSize {
return nil, errors.New("cipherText too short")
}
iv := []byte(ivDefValue)
ivValue := ([]byte)(nil)
if len(iv) > 0 {
ivValue = iv[0]
} else {
ivValue = []byte(ivDefValue)
}
if len(cipherText)%blockSize != 0 {
return nil, errors.New("cipherText is not a multiple of the block size")
}
blockModel := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(cipherText))
blockModel.CryptBlocks(plaintext, cipherText)
plaintext = PKCS5UnPadding(plaintext)
blockModel := cipher.NewCBCDecrypter(block, ivValue)
plainText := make([]byte, len(cipherText))
blockModel.CryptBlocks(plainText, cipherText)
plainText = PKCS5UnPadding(plainText)
return plaintext, nil
return plainText, nil
}
func PKCS5Padding(src []byte, blockSize int) []byte {
@ -61,7 +73,7 @@ func PKCS5Padding(src []byte, blockSize int) []byte {
}
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
length := len(src)
unpadding := int(src[length - 1])
return src[:(length - unpadding)]
}

View File

@ -5,123 +5,122 @@
// You can obtain one at https://gitee.com/johng/gf.
// 数据库ORM.
// 默认内置支持MySQL, 其他数据库需要手动import对应的数据库引擎第三方包.
package gdb
import (
"fmt"
"fmt"
"time"
"errors"
"database/sql"
"gitee.com/johng/gf/g/util/grand"
_ "github.com/lib/pq"
_ "github.com/go-sql-driver/mysql"
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/container/gring"
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/container/gmap"
"time"
"gitee.com/johng/gf/g/container/gmap"
"gitee.com/johng/gf/g/container/gring"
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/g/os/gcache"
"gitee.com/johng/gf/g/util/grand"
_ "github.com/go-sql-driver/mysql"
)
const (
OPTION_INSERT = 0
OPTION_REPLACE = 1
OPTION_SAVE = 2
OPTION_IGNORE = 3
OPTION_INSERT = 0
OPTION_REPLACE = 1
OPTION_SAVE = 2
OPTION_IGNORE = 3
)
// 数据库操作接口
type Link interface {
// 打开数据库连接,建立数据库操作对象
Open (c *ConfigNode) (*sql.DB, error)
// 打开数据库连接,建立数据库操作对象
Open(c *ConfigNode) (*sql.DB, error)
// SQL操作方法
Query(q string, args ...interface{}) (*sql.Rows, error)
Exec(q string, args ...interface{}) (sql.Result, error)
Prepare(q string) (*sql.Stmt, error)
// SQL操作方法
Query(q string, args ...interface{}) (*sql.Rows, error)
Exec(q string, args ...interface{}) (sql.Result, error)
Prepare(q string) (*sql.Stmt, error)
// 数据库查询
GetAll(q string, args ...interface{}) (Result, error)
GetOne(q string, args ...interface{}) (Record, error)
GetValue(q string, args ...interface{}) (Value, error)
// 数据库查询
GetAll(q string, args ...interface{}) (Result, error)
GetOne(q string, args ...interface{}) (Record, error)
GetValue(q string, args ...interface{}) (Value, error)
// Ping
PingMaster() error
PingSlave() error
// Ping
PingMaster() error
PingSlave() error
// 连接属性设置
SetMaxIdleConns(n int)
SetMaxOpenConns(n int)
SetConnMaxLifetime(d time.Duration)
// 连接属性设置
SetMaxIdleConns(n int)
SetMaxOpenConns(n int)
SetConnMaxLifetime(d time.Duration)
// 开启事务操作
Begin() (*Tx, error)
// 开启事务操作
Begin() (*Tx, error)
// 数据表插入/更新/保存操作
Insert(table string, data Map) (sql.Result, error)
Replace(table string, data Map) (sql.Result, error)
Save(table string, data Map) (sql.Result, error)
// 数据表插入/更新/保存操作
Insert(table string, data Map) (sql.Result, error)
Replace(table string, data Map) (sql.Result, error)
Save(table string, data Map) (sql.Result, error)
// 数据表插入/更新/保存操作(批量)
BatchInsert(table string, list List, batch int) (sql.Result, error)
BatchReplace(table string, list List, batch int) (sql.Result, error)
BatchSave(table string, list List, batch int) (sql.Result, error)
// 数据表插入/更新/保存操作(批量)
BatchInsert(table string, list List, batch int) (sql.Result, error)
BatchReplace(table string, list List, batch int) (sql.Result, error)
BatchSave(table string, list List, batch int) (sql.Result, error)
// 数据修改/删除
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
// 数据修改/删除
Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error)
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error)
// 创建链式操作对象(Table为From的别名)
Table(tables string) (*Model)
From(tables string) (*Model)
// 创建链式操作对象(Table为From的别名)
Table(tables string) *Model
From(tables string) *Model
// 关闭数据库操作对象
Close() error
// 关闭数据库操作对象
Close() error
// 内部方法
insert(table string, data Map, option uint8) (sql.Result, error)
batchInsert(table string, list List, batch int, option uint8) (sql.Result, error)
// 内部方法
insert(table string, data Map, option uint8) (sql.Result, error)
batchInsert(table string, list List, batch int, option uint8) (sql.Result, error)
getQuoteCharLeft () string
getQuoteCharRight () string
handleSqlBeforeExec(q *string) *string
getQuoteCharLeft() string
getQuoteCharRight() string
handleSqlBeforeExec(q *string) *string
}
// 数据库链接对象
type Db struct {
link Link // 底层数据库类型管理对象
master *sql.DB // 实例化数据库链接(master)
slave *sql.DB // 实例化数据库链接(slave可能会与master相同)
charl string // SQL安全符号(左)
charr string // SQL安全符号(右)
debug *gtype.Bool // (默认关闭)是否开启调试模式,当开启时会启用一些调试特性
sqls *gring.Ring // (debug=true时有效)已执行的SQL列表
cache *gcache.Cache // 查询缓存,需要注意的是,事务查询不支持缓存
link Link // 底层数据库类型管理对象
master *sql.DB // 实例化数据库链接(master)
slave *sql.DB // 实例化数据库链接(slave可能会与master相同)
charl string // SQL安全符号(左)
charr string // SQL安全符号(右)
debug *gtype.Bool // (默认关闭)是否开启调试模式,当开启时会启用一些调试特性
sqls *gring.Ring // (debug=true时有效)已执行的SQL列表
cache *gcache.Cache // 查询缓存,需要注意的是,事务查询不支持缓存
}
// 执行的SQL对象
type Sql struct {
Sql string // SQL语句(可能带有预处理占位符)
Args []interface{} // 预处理参数值列表
Error error // 执行结果(nil为成功)
Cost int64 // 执行时间消耗(毫秒)
Func string // 执行方法名称
Sql string // SQL语句(可能带有预处理占位符)
Args []interface{} // 预处理参数值列表
Error error // 执行结果(nil为成功)
Start int64 // 执行开始时间(毫秒)
End int64 // 执行结束时间(毫秒)
Func string // 执行方法名称
}
// 返回数据表记录值
type Value []byte
type Value []byte
// 返回数据表记录Map
type Record map[string]Value
type Record map[string]Value
// 返回数据表记录List
type Result []Record
type Result []Record
// 关联数组,绑定一条数据表记录(使用别名)
type Map = map[string]interface{}
type Map = map[string]interface{}
// 关联数组列表(索引从0开始的数组),绑定多条记录(使用别名)
type List = []Map
type List = []Map
// MySQL接口对象
var linkMysql = &dbmysql{}
@ -129,45 +128,49 @@ var linkMysql = &dbmysql{}
// PostgreSQL接口对象
var linkPgsql = &dbpgsql{}
// Sqlite接口对象
// @author wxkj<wxscz@qq.com>
var linkSqlite = &dbsqlite{}
// 数据库查询缓存对象map使用数据库连接名称作为键名键值为查询缓存对象
var dbCaches = gmap.NewStringInterfaceMap()
var dbCaches = gmap.NewStringInterfaceMap()
// 使用默认/指定分组配置进行连接数据库集群配置项default
func New(groupName...string) (*Db, error) {
name := config.d
if len(groupName) > 0 {
name = groupName[0]
}
config.RLock()
defer config.RUnlock()
func New(groupName ...string) (*Db, error) {
name := config.d
if len(groupName) > 0 {
name = groupName[0]
}
config.RLock()
defer config.RUnlock()
if len(config.c) < 1 {
return nil, errors.New("empty database configuration")
}
if list, ok := config.c[name]; ok {
// 将master, slave集群列表拆分出来
masterList := make(ConfigGroup, 0)
slaveList := make(ConfigGroup, 0)
for i := 0; i < len(list); i++ {
if list[i].Role == "slave" {
slaveList = append(slaveList, list[i])
} else {
// 默认配置项的角色为master
masterList = append(masterList, list[i])
}
}
if len(masterList) < 1 {
return nil, errors.New("at least one master node configuration's need to make sense")
}
masterNode := getConfigNodeByPriority(masterList)
var slaveNode *ConfigNode
if len(slaveList) > 0 {
slaveNode = getConfigNodeByPriority(slaveList)
}
return newDb(masterNode, slaveNode, name)
} else {
return nil, errors.New(fmt.Sprintf("empty database configuration for item name '%s'", name))
}
if len(config.c) < 1 {
return nil, errors.New("empty database configuration")
}
if list, ok := config.c[name]; ok {
// 将master, slave集群列表拆分出来
masterList := make(ConfigGroup, 0)
slaveList := make(ConfigGroup, 0)
for i := 0; i < len(list); i++ {
if list[i].Role == "slave" {
slaveList = append(slaveList, list[i])
} else {
// 默认配置项的角色为master
masterList = append(masterList, list[i])
}
}
if len(masterList) < 1 {
return nil, errors.New("at least one master node configuration's need to make sense")
}
masterNode := getConfigNodeByPriority(masterList)
var slaveNode *ConfigNode
if len(slaveList) > 0 {
slaveNode = getConfigNodeByPriority(slaveList)
}
return newDb(masterNode, slaveNode, name)
} else {
return nil, errors.New(fmt.Sprintf("empty database configuration for item name '%s'", name))
}
}
// 按照负载均衡算法(优先级配置)从数据库集群中选择一个配置节点出来使用
@ -176,84 +179,87 @@ func New(groupName...string) (*Db, error) {
// 2、那么节点1的权重范围为[0, 99]节点2的权重范围为[100, 199]比例为1:1
// 3、假如计算出的随机数为99;
// 4、那么选择的配置为节点1;
func getConfigNodeByPriority (cg ConfigGroup) *ConfigNode {
if len(cg) < 2 {
return &cg[0]
}
var total int
for i := 0; i < len(cg); i++ {
total += cg[i].Priority * 100
}
// 不能取到末尾的边界点
r := grand.Rand(0, total)
if r > 0 {
r -= 1
}
min := 0
max := 0
for i := 0; i < len(cg); i++ {
max = min + cg[i].Priority * 100
//fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max)
if r >= min && r < max {
return &cg[i]
} else {
min = max
}
}
return nil
func getConfigNodeByPriority(cg ConfigGroup) *ConfigNode {
if len(cg) < 2 {
return &cg[0]
}
var total int
for i := 0; i < len(cg); i++ {
total += cg[i].Priority * 100
}
// 不能取到末尾的边界点
r := grand.Rand(0, total)
if r > 0 {
r -= 1
}
min := 0
max := 0
for i := 0; i < len(cg); i++ {
max = min + cg[i].Priority*100
//fmt.Printf("r: %d, min: %d, max: %d\n", r, min, max)
if r >= min && r < max {
return &cg[i]
} else {
min = max
}
}
return nil
}
// 创建数据库链接对象
func newDb (masterNode *ConfigNode, slaveNode *ConfigNode, groupName string) (*Db, error) {
var link Link
switch masterNode.Type {
case "mysql": link = linkMysql
case "pgsql": link = linkPgsql
default:
return nil, errors.New(fmt.Sprintf("unsupported db type '%s'", masterNode.Type))
}
master, err := link.Open(masterNode)
if err != nil {
return nil, err
}
slave := master
if slaveNode != nil {
slave, err = link.Open(slaveNode)
if err != nil {
return nil, err
}
}
db := &Db {
link : link,
master : master,
slave : slave,
charl : link.getQuoteCharLeft(),
charr : link.getQuoteCharRight(),
debug : gtype.NewBool(),
}
// 设置连接属性master和slave必须是一致的所以这里使用的是master的属性设置
if masterNode.MaxIdleConnCount > 0 {
db.SetMaxIdleConns(masterNode.MaxIdleConnCount)
}
if masterNode.MaxOpenConnCount > 0 {
db.SetMaxOpenConns(masterNode.MaxOpenConnCount)
}
if masterNode.MaxConnLifetime > 0 {
db.SetConnMaxLifetime(time.Duration(masterNode.MaxConnLifetime)*time.Second)
}
if v := dbCaches.Get(groupName); v == nil {
dbCaches.LockFunc(func(m map[string]interface{}) {
if v, ok := m[groupName]; !ok {
db.cache = gcache.New()
m[groupName] = db.cache
} else {
db.cache = v.(*gcache.Cache)
}
})
} else {
db.cache = v.(*gcache.Cache)
}
func newDb(masterNode *ConfigNode, slaveNode *ConfigNode, groupName string) (*Db, error) {
var link Link
switch masterNode.Type {
case "mysql":
link = linkMysql
case "pgsql":
link = linkPgsql
case "sqlite":
link = linkSqlite
default:
return nil, errors.New(fmt.Sprintf("unsupported db type '%s'", masterNode.Type))
}
master, err := link.Open(masterNode)
if err != nil {
return nil, err
}
slave := master
if slaveNode != nil {
slave, err = link.Open(slaveNode)
if err != nil {
return nil, err
}
}
db := &Db{
link: link,
master: master,
slave: slave,
charl: link.getQuoteCharLeft(),
charr: link.getQuoteCharRight(),
debug: gtype.NewBool(),
}
// 设置连接属性master和slave必须是一致的所以这里使用的是master的属性设置
if masterNode.MaxIdleConnCount > 0 {
db.SetMaxIdleConns(masterNode.MaxIdleConnCount)
}
if masterNode.MaxOpenConnCount > 0 {
db.SetMaxOpenConns(masterNode.MaxOpenConnCount)
}
if masterNode.MaxConnLifetime > 0 {
db.SetConnMaxLifetime(time.Duration(masterNode.MaxConnLifetime) * time.Second)
}
if v := dbCaches.Get(groupName); v == nil {
dbCaches.LockFunc(func(m map[string]interface{}) {
if v, ok := m[groupName]; !ok {
db.cache = gcache.New()
m[groupName] = db.cache
} else {
db.cache = v.(*gcache.Cache)
}
})
} else {
db.cache = v.(*gcache.Cache)
}
return db, nil
return db, nil
}

View File

@ -32,7 +32,7 @@ func (db *Db) SetDebug(debug bool) {
}
}
// 获取已经执行的SQL列表
// 获取已经执行的SQL列表(仅在debug=true时有效)
func (db *Db) GetQueriedSqls() []*Sql {
if db.sqls == nil {
return nil
@ -49,6 +49,21 @@ func (db *Db) GetQueriedSqls() []*Sql {
return sqls
}
// 打印已经执行的SQL列表(仅在debug=true时有效)
func (db *Db) PrintQueriedSqls() {
sqls := db.GetQueriedSqls()
for k, v := range sqls {
fmt.Println(len(sqls) - k, ":")
fmt.Println(" Sql :", v.Sql)
fmt.Println(" Args :", v.Args)
fmt.Println(" Error:", v.Error)
fmt.Println(" Start:", gtime.NewFromTimeStamp(v.Start).Format("Y-m-d H:i:s.u"))
fmt.Println(" End :", gtime.NewFromTimeStamp(v.End).Format("Y-m-d H:i:s.u"))
fmt.Println(" Cost :", v.End - v.Start, "ms")
fmt.Println(" Func :", v.Func)
}
}
// 关闭链接
func (db *Db) Close() error {
if db.master != nil {
@ -81,7 +96,8 @@ func (db *Db) Query(query string, args ...interface{}) (*sql.Rows, error) {
Sql : *p,
Args : args,
Error : err,
Cost : militime2 - militime1,
Start : militime1,
End : militime2,
Func : "DB:Query",
})
} else {
@ -108,7 +124,8 @@ func (db *Db) Exec(query string, args ...interface{}) (sql.Result, error) {
Sql : *p,
Args : args,
Error : err,
Cost : militime2 - militime1,
Start : militime1,
End : militime2,
Func : "DB:Exec",
})
} else {
@ -291,7 +308,6 @@ func (db *Db) Begin() (*Tx, error) {
func (db *Db) getInsertOperationByOption(option uint8) string {
oper := "INSERT"
switch option {
case OPTION_INSERT:
case OPTION_REPLACE:
oper = "REPLACE"
case OPTION_SAVE:

View File

@ -13,7 +13,9 @@ import (
"database/sql"
)
// postgresql的适配
// PostgreSQL的适配.
// 使用时需要import:
// _ "github.com/lib/pq"
// @todo 需要完善replace和save的操作覆盖
// 数据库链接对象

View File

@ -0,0 +1,52 @@
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// @author wxkj<wxscz@qq.com>
package gdb
import (
"database/sql"
)
// 使用时需要import:
// _ "github.com/mattn/go-sqlite3"
// 数据库链接对象
type dbsqlite struct {
Db
}
func (db *dbsqlite) Open(c *ConfigNode) (*sql.DB, error) {
var source string
if c.Linkinfo != "" {
source = c.Linkinfo
} else {
source = c.Name
}
if db, err := sql.Open("sqlite3", source); err == nil {
return db, nil
} else {
return nil, err
}
}
// 获得关键字操作符 - 左
func (db *dbsqlite) getQuoteCharLeft() string {
return "`"
}
// 获得关键字操作符 - 右
func (db *dbsqlite) getQuoteCharRight() string {
return "`"
}
// 在执行sql之前对sql进行进一步处理
// @todo 需要增加对Save方法的支持可使用正则来实现替换
// @todo 将ON DUPLICATE KEY UPDATE触发器修改为两条SQL语句(INSERT OR IGNORE & UPDATE)
func (db *dbsqlite) handleSqlBeforeExec(q *string) *string {
return q
}

View File

@ -10,12 +10,11 @@ import (
"fmt"
"errors"
"strings"
"database/sql"
_ "github.com/lib/pq"
_ "github.com/go-sql-driver/mysql"
"gitee.com/johng/gf/g/util/gconv"
"reflect"
"database/sql"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/util/gconv"
_ "github.com/go-sql-driver/mysql"
)
// 数据库事务对象
@ -47,7 +46,8 @@ func (tx *Tx) Query(query string, args ...interface{}) (*sql.Rows, error) {
Sql : *p,
Args : args,
Error : err,
Cost : militime2 - militime1,
Start : militime1,
End : militime2,
Func : "TX:Query",
})
} else {
@ -74,7 +74,8 @@ func (tx *Tx) Exec(query string, args ...interface{}) (sql.Result, error) {
Sql : *p,
Args : args,
Error : err,
Cost : militime2 - militime1,
Start : militime1,
End : militime2,
Func : "TX:Exec",
})
} else {

View File

@ -40,6 +40,9 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e
p := key
if strings.EqualFold(p[len(p) - 6:], "/index") {
p = p[0 : len(p) - 6]
if len(p) == 0 {
p = "/"
}
}
m[p] = &handlerItem {
ctype : v.Elem().Type(),
@ -75,6 +78,9 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, methods strin
p := key
if strings.EqualFold(p[len(p) - 6:], "/index") {
p = p[0 : len(p) - 6]
if len(p) == 0 {
p = "/"
}
}
m[p] = &handlerItem {
ctype : t,

View File

@ -36,6 +36,9 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er
p := key
if strings.EqualFold(p[len(p) - 6:], "/index") {
p = p[0 : len(p) - 6]
if len(p) == 0 {
p = "/"
}
}
m[p] = &handlerItem {
ctype : nil,
@ -71,6 +74,9 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, methods string
p := key
if strings.EqualFold(p[len(p) - 6:], "/index") {
p = p[0 : len(p) - 6]
if len(p) == 0 {
p = "/"
}
}
m[p] = &handlerItem {
ctype : nil,

View File

@ -66,10 +66,13 @@ func NewFromStrLayout (str string, layout string) *Time {
return nil
}
// 时间戳转换为时间对象
// 时间戳转换为时间对象,时间戳支持到纳秒的数值
func NewFromTimeStamp (timestamp int64) *Time {
return &Time{
time.Unix(timestamp, 0),
for timestamp < 1e18 {
timestamp *= 10
}
return &Time {
time.Unix(int64(timestamp/1e9), timestamp%1e9),
}
}

View File

@ -1,40 +0,0 @@
package main
import (
"fmt"
"gitee.com/johng/gf/g/database/gdb"
)
func main() {
gdb.AddDefaultConfigNode(gdb.ConfigNode {
Host : "127.0.0.1",
Port : "3306",
User : "root",
Pass : "123456",
Name : "test",
Type : "mysql",
Role : "master",
Charset : "utf8",
})
db, err := gdb.New()
if err != nil {
panic(err)
}
db.SetDebug(true)
// 执行3条SQL查询
for i := 1; i <= 3; i++ {
db.Table("user").Where("uid=?", i).One()
}
// 构造一条错误查询
db.Table("user").Where("no_such_field=?", "just_test").One()
for k, v := range db.GetQueriedSqls() {
fmt.Println(k, ":")
fmt.Println("Sql :", v.Sql)
fmt.Println("Args :", v.Args)
fmt.Println("Error:", v.Error)
fmt.Println("Cost :", v.Cost)
fmt.Println("Func :", v.Func)
}
}

View File

@ -0,0 +1,32 @@
package main
import (
"gitee.com/johng/gf/g/database/gdb"
)
func main() {
gdb.AddDefaultConfigNode(gdb.ConfigNode{
Host: "127.0.0.1",
Port: "3306",
User: "root",
Pass: "123456",
Name: "test",
Type: "mysql",
Role: "master",
Charset: "utf8",
})
db, err := gdb.New()
if err != nil {
panic(err)
}
db.SetDebug(true)
// 执行3条SQL查询
for i := 1; i <= 3; i++ {
db.Table("user").Where("uid=?", i).One()
}
// 构造一条错误查询
db.Table("user").Where("no_such_field=?", "just_test").One()
db.PrintQueriedSqls()
}

View File

@ -0,0 +1,47 @@
package main
//import (
// _ "github.com/mattn/go-sqlite3"
// "gitee.com/johng/gf/g/database/gdb"
// "gitee.com/johng/gf/g"
// "fmt"
//)
//
//func main() {
// gdb.SetConfig(gdb.Config{
// "default": gdb.ConfigGroup{
// gdb.ConfigNode{
// Name: "/tmp/my.db",
// Type: "sqlite",
// },
// },
// })
// db := g.Database()
// if db == nil {
// panic("db create failed")
// }
// defer db.Close()
//
// // 创建表
// sql := `CREATE TABLE user (
// uid INT PRIMARY KEY NOT NULL,
// name VARCHAR(30) NOT NULL
// );`
// if _, err := db.Exec(sql); err != nil {
// fmt.Println(err)
// }
//
// // 写入数据
// result, err := db.Table("user").Data(g.Map{"uid" : 1, "name" : "john"}).Save()
// if err == nil {
// fmt.Println(result.RowsAffected())
// } else {
// fmt.Println(err)
// }
//
// // 删除表
// sql = `DROP TABLE user;`
// if _, err := db.Exec(sql); err != nil {
// fmt.Println(err)
// }
//}

View File

@ -1,75 +1,9 @@
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"errors"
"fmt"
"gitee.com/johng/gf/g/encoding/gbase64"
)
const (
ivDefValue = "I Love Go Frame!"
"fmt"
)
func main() {
v := "1234567890123456789012345678901234567890123456789012345678901234567890"
k := "123456789012345 "
e, err := AesEncrypt([]byte(v), []byte(k))
fmt.Println(err)
fmt.Println(len(e))
fmt.Println(string(gbase64.Encode(string(e))))
d, err := AesDecrypt([]byte(e), []byte(k))
fmt.Println(err)
fmt.Println(string(d))
}
func AesEncrypt(plaintext []byte, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
plaintext = PKCS5Padding(plaintext, blockSize)
iv := []byte(ivDefValue)
blockMode := cipher.NewCBCEncrypter(block, iv)
ciphertext := make([]byte, len(plaintext))
blockMode.CryptBlocks(ciphertext, plaintext)
return ciphertext, nil
}
func AesDecrypt(cipherText []byte, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
if len(cipherText) < blockSize {
return nil, errors.New("cipherText too short")
}
iv := []byte(ivDefValue)
if len(cipherText)%blockSize != 0 {
return nil, errors.New("cipherText is not a multiple of the block size")
}
blockModel := cipher.NewCBCDecrypter(block, iv)
plaintext := make([]byte, len(cipherText))
blockModel.CryptBlocks(plaintext, cipherText)
plaintext = PKCS5UnPadding(plaintext)
return plaintext, nil
}
func PKCS5Padding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(src, padtext...)
}
func PKCS5UnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
fmt.Println(1)
}