【Go语言】Beego框架ORM的CRUD操作实现

今天介绍一下Beego 的ORM 操作

Beego 很赞。
Beego中数据库的处理很简答,用beego/orm这个工具就可以了。对于数据库操作主要就是增删查改CURD操作。ORM可以自己建表,我们只需要定义好相关的结构体就好了,然后用相关的函数去注册好就OK。

//定义结构体,名字为表名大写,字段大写,为表的字段
type Book struct {
Name   string
Num    int64 `orm:"pk;auto"` //主键,自动增长
Author string
Price  float32
}

//注册模型
func init() {
//orm.RegisterModelWithPrefix("book_", new(Book))  //带前缀的表
orm.RegisterModel(new(Book)) //不带前缀的表
}

当然最重要是是要引入这个包

"github.com/astaxie/beego/orm"

现在我们来链接数据库。要提供相应的配置参数。

var dbhost string = "localhost:3306" //主机,米有用到( ⊙ o ⊙ )!
var dbuser string = "root"           //数据库用户名
var dbpassword string = ""           //数据库密码
var db string = "ormtest"            //数据库名字

要引入的包是

"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"

初始化数据库

//初始化函数
func init() {
	//注册mysql Driver
	orm.RegisterDriver("mysql", orm.DR_MySQL)
	//构造conn连接
	conn := dbuser + ":" + dbpassword + "@/" + db + "?charset=utf8"
	//注册数据库连接
	orm.RegisterDataBase("default", "mysql", conn)
}

开启自动建表

//自动建表
func createTable() {
	name := "default"                          //数据库别名
	force := false                             //不强制建数据库
	verbose := true                            //打印建表过程
	err := orm.RunSyncdb(name, force, verbose) //建表
	if err != nil {
		beego.Error(err)
	}
}

准备工作做好了现在就来测试,在main()函数中先要初始化一个orm对象,指定使用的数据库,并且执行自动建表

o := orm.NewOrm()  //注册新的orm
	o.Using("dafault") //使用数据库,默认default
	createTable()      //开启自动建表

现在就可以CRUD操作了。
首先是insert

//插入
	//直接构造对象
	var book1 *Book = &Book{Name: "蓝色fasfsaf天空", Price: 30.0, Author: "刘凯宁"}
	//间接构造对象
	var book2 *Book = new(Book)
	book2.Author = "mq"
	book2.Name = "mq111fasf"
	book2.Price = 100.0
	//执行插入,o.Insert()返回的是受影响的id
	fmt.Println(o.Insert(book1))
	fmt.Println(o.Insert(book2))

可以批量插入数据

//批量插入数据
	books := []Book{
		{Name: "lkn1", Price: 10},
		{Name: "lkn5", Price: 122},
		{Name: "lkn3", Price: 3},
		{Name: "lkn22", Price: 12},
		{Name: "lkn2121", Price: 133},
	}
	//插入,第一个参数为要插入的条数
	o.InsertMulti(5, books)
	fmt.Println(books)

然后是read

//读取记录
	book := new(Book)
	//必须要指定主键
	book.Num = 1
	o.Read(book)
	fmt.Println(book)

	//读取记录,如果没有就新建一个,不用指定主键
	book.Author = "qqq"
	o.ReadOrCreate(book, "Author")
	fmt.Println(book)

接下来update

//修改记录,指定主键
	book4 := new(Book)
	book4.Num = 8
	book4.Author = "刘凯宁"
	o.Update(book4, "Author")
	fmt.Println(book4)

最后delete

//删除记录,指定主键
	book3 := new(Book)
	book3.Num = 6
	o.Read(book3)
	fmt.Println(book3)
	o.Delete(book3)

这样就会使用ORM来进行CRUD操作了。
做MVC模式的应用是,数据库这块,就是model这块,主要就是各种数据库的操作,beego中用beego/orm 这个工具很好的完成了各种数据库的操作,简化了SQL语句,并且效率得到了提高。当然可以直接写SQL语句然后去执行,那个以后有机会去介绍吧。关于ORM的使用还有其他的高级应用,敬请期待后面的博客!

刘凯宁@C2P
20140815

Share

【数据结构golang版】第三篇:链表实现

今天完成了单链表的golang版实现

链表很重要。实现了重要的几个方法。直接上代码。


package main

//链表实现
import (
 "fmt"
)

//定义错误常量
const (
 ERROR = -1000000001
)

//定义元素类型
type Element int64

//定义节点
type LinkNode struct {
 Data Element //数据域
 Nest *LinkNode //指针域,指向下一个节点
}

//函数接口
type LinkNoder interface {
 Add(head *LinkNode, new *LinkNode) //后面添加
 Delete(head *LinkNode, index int) //删除指定index位置元素
 Insert(head *LinkNode, index int, data Element) //在指定index位置插入元素
 GetLength(head *LinkNode) int //获取长度
 Search(head *LinkNode, data Element) //查询元素的位置
 GetData(head *LinkNode, index int) Element //获取指定index位置的元素
}

//添加 头结点,数据
func Add(head *LinkNode, data Element) {
 point := head //临时指针
 for point.Nest != nil {
 point = point.Nest //移位
 }
 var node LinkNode //新节点
 point.Nest = &node //赋值
 node.Data = data
 head.Data = Element(GetLength(head)) //打印全部的数据
 if GetLength(head) > 1 {
 Traverse(head)
 }

}

//删除 头结点 index 位置
func Delete(head *LinkNode, index int) Element {
 //判断index合法性
 if index < 0 || index > GetLength(head) {
 fmt.Println("please check index")
 return ERROR
 } else {
 point := head
 for i := 0; i < index-1; i++ {
 point = point.Nest //移位
 }
 point.Nest = point.Nest.Nest //赋值
 data := point.Nest.Data
 return data
 }
}

//插入 头结点 index位置 data元素
func Insert(head *LinkNode, index int, data Element) {
 //检验index合法性
 if index < 0 || index > GetLength(head) {
 fmt.Println("please check index")
 } else {
 point := head
 for i := 0; i < index-1; i++ {
 point = point.Nest //移位
 }
 var node LinkNode //新节点,赋值
 node.Data = data
 node.Nest = point.Nest
 point.Nest = &node
 }
}

//获取长度 头结点
func GetLength(head *LinkNode) int {
 point := head
 var length int
 for point.Nest != nil {
 length++
 point = point.Nest
 }
 return length
}

//搜索 头结点 data元素
func Search(head *LinkNode, data Element) {
 point := head
 index := 0
 for point.Nest != nil {
 if point.Data == data {
 fmt.Println(data, "exist at", index, "th")
 break
 } else {
 index++
 point = point.Nest
 if index > GetLength(head)-1 {
 fmt.Println(data, "not exist at")
 break
 }
 continue
 }
 }
}

//获取data 头结点 index位置
func GetData(head *LinkNode, index int) Element {
 point := head
 if index < 0 || index > GetLength(head) {
 fmt.Println("please check index")
 return ERROR
 } else {
 for i := 0; i < index; i++ {
 point = point.Nest
 }
 return point.Data
 }
}

//遍历 头结点
func Traverse(head *LinkNode) {
 point := head.Nest
 for point.Nest != nil {
 fmt.Println(point.Data)
 point = point.Nest
 }
 fmt.Println("Traverse OK!")
}

//主函数测试
func main() {
 var head LinkNode = LinkNode{Data: 0, Nest: nil}
 head.Data = 0
 var nodeArray []Element
 for i := 0; i < 10; i++ {
 nodeArray = append(nodeArray, Element(i+1+i*100))
 Add(&head, nodeArray[i])
 }
 Delete(&head, 3)
 Search(&head, 2032)
 Insert(&head, 23, 10010)
 Traverse(&head)
 fmt.Println("data is", GetData(&head, 6))
 fmt.Println("length:", GetLength(&head))
}

慢慢发现用golang重新一遍数据结构是一件多么有意义的事情。我会坚持写完的。
自己给自己加油!

刘凯宁@C2P
20140813

Share

【数据结构golang版】第二篇:线性表实现

今天用golang实现了线性表的基本操作。
注释还是很多,读的书是那一本《数据结构C语言版 严蔚敏》,上课的时候我就用的是这个。逻辑什么的都差不多,但是golang的代码全部自己写成的。下面上代码

package main

//线性表的相关算法实现
import (
	"fmt"
)

//定义List数据结构
type Element int64

const (
	MAX_SIZE = 10 //最大Size
	ERROR    = -1 //出错值
	NULL     = 0  //空值
)

type Sqlist struct {
	data   []Element //数据数组
	length int       //当前长度
	size   int       //最大size
}

//定义List的Interface,这里写出所有用到的方法
type Lister interface {
	//初始化构造一个线性表
	InitList(sl *Sqlist) bool
	//清空一个线性表
	ClearList(sl *Sqlist) bool
	//判断线性表是否为空
	IsListEmpty(sl *Sqlist) bool
	//判断线性表是否为满
	IsListFull(sl *Sqlist) bool
	//获取线性表长度
	Listlength(sl Sqlist) int
	//根据index获取数据
	GetData(sl Sqlist, index int) Element
	//根据数据返回index
	GetIndex(sl Sqlist, data Element) int
	//在index位置插入元素
	InsertList(sl *Sqlist, index int, data Element) bool
	//删除index的元素
	DeleteList(sl *Sqlist, index int) Element
	//遍历List
	TraverseList(sl *Sqlist) bool
}

//新建一个线性表
func InitList() Sqlist {
	var sl Sqlist
	sl.data = make([]Element, MAX_SIZE)
	sl.length = 0
	sl.size = MAX_SIZE
	return sl
}

//清空一个线性表
func ClearList(sl *Sqlist) bool {
	for i := 0; i < sl.size; i++ {
		sl.data[i] = NULL //全部都置空
	}
	return true
}

//判断线性表是否为空
func IsListEmpty(sl *Sqlist) bool {
	return sl.length == 0
}

//判断线性表是否为满
func IsListFull(sl *Sqlist) bool {
	return sl.length == MAX_SIZE
}

//获取线性表长度
func Listlength(sl Sqlist) int {
	return sl.length
}

//根据index获取数据
func GetData(sl *Sqlist, index int) Element {
	if index < 0 && index > MAX_SIZE {
		fmt.Println("please check index")
		return ERROR
	} else {
		return sl.data[index]
	}

}

//根据数据返回index
func GetIndex(sl *Sqlist, data Element) int {
	var index int = 0
	for i := 0; i < sl.length; i++ {
		if data == sl.data[i] {
			index = i
			break
		}
	}
	return index

}

//在index位置插入元素
/**
第一要判断index是否合法,然后判断index的位置,注意移动过程,最后要把length加1
**/
func InsertList(sl *Sqlist, index int, data Element) bool {
	if index < 0 && index > sl.length {
		fmt.Println("please check index")
		return false
	}
	if !IsListFull(sl) {
		if index == 0 && sl.length != 0 {
			for i := sl.length; i < 1; i-- {
				sl.data[i] = sl.data[i-1] //千万注意
			}
		} else if index > 0 && index < sl.length {
			for i := sl.length; i < index; i-- {
				sl.data[i] = sl.data[i-1] //注意这一块儿
			}
		} else if index > sl.length {
			fmt.Println("beyoug length")
			return false
		}
		sl.data[index] = data
		sl.length++
		return true
	} else {
		fmt.Println("list is full")
		return false
	}
}

//删除index的元素
/**
第一要判断index是否合法,然后判断index的位置,注意移位的时候要想清楚怎么移动,最后要把length减一
**/
func DeleteList(sl *Sqlist, index int) Element {
	if index < 0 && index > sl.length {
		fmt.Println("please check index")
		return ERROR
	}
	if !IsListEmpty(sl) {
		var data Element = sl.data[index]
		if index == 0 {
			for i := 0; i < sl.length; i++ {
				sl.data[i] = sl.data[i+1] //注意这个
			}
		}
		if index > 0 && index < sl.length {
			for i := index; i < sl.length-1; i++ {
				sl.data[i] = sl.data[i+1] //要注意
			}
		}
		sl.data[sl.length-1] = NULL
		sl.length--
		return data

	} else {
		fmt.Println("list is empty!")
		return ERROR
	}
}

//遍历List
func TraverseList(sl *Sqlist) bool {
	for i := 0; i < sl.length; i++ {
		fmt.Println(sl.data[i])
	}
	return true
}
func main() {
	list := InitList()
	fmt.Println(list.length)
	for i := 0; i < MAX_SIZE; i++ {
		InsertList(&list, i, Element(i*100))
	}
	TraverseList(&list)
	DeleteList(&list, 4)
	fmt.Println(list.data)
	fmt.Println(GetData(&list, 0))
	fmt.Println(GetIndex(&list, 600))
	ClearList(&list)
}

我尽量每天写一点儿数据结构的东西吧,虽然简单,但写起来还是不那么简单的。归根到底还是不熟悉。
自己给自己加油!

刘凯宁@C2P
20140812

Share

【数据结构golang版】第一篇:栈的实现

想复习一下数据结构的知识,最好的方式就是敲一遍代码啊,上学期是用C语言学的,在这里想用goalng把基本的数据结构重写一遍。今天先写简单的栈。

可能和C语言学过的有点儿不一样,第一个是我用了一个StackType的结构体,有两个成员:一个是Array,用来存储数据,一个是Top,用来指示栈顶的元素。定义的初始长度是MAX_SIZE = 10,元素的类型为Element ,本质是int64类型。没有入栈是默认值为零,出栈以后值也会变成0:这个地方我承认处理的不好。其实可以用golang中的slice每次只要append进去就好了,不过我觉得那种的话就太方便了,完全没有意义去判断栈满,于是就还是像上面那种处理了。OK ,现在上代码:

package main

//栈的实现
import (
"fmt"
)

const (
MAX_SIZE = 10 //最大元素量
EMPTY    = -1 //空值
)

//元素类型
type Element int64

//stack 结构体
type StackType struct {
Array []Element //数组
Top   int       //栈顶指示器
}

//创建Stack
func CreateStack() StackType {
var stack StackType
stack.Array = make([]Element, MAX_SIZE)
stack.Top = -1
fmt.Println("Create successful!")
return stack
}

//入栈
func Push(stack *StackType, data Element) {
if !IsFull(stack) {
stack.Top++
stack.Array[stack.Top] = data
fmt.Println("Push OK!")
fmt.Println(stack.Array)
} else {
fmt.Println("stack is FULL!")
fmt.Println(data, "can't Push")
fmt.Println(stack.Array)
}
}

//出栈
func Pop(stack *StackType) Element {
if !IsEmpty(stack) {
data := stack.Array[stack.Top]
stack.Array[stack.Top] = 0
stack.Top--
fmt.Println("Pop OK!")
fmt.Println("data is", data)
fmt.Println(stack.Array)
return data
} else {
fmt.Println("stack is EMPTY!")
return EMPTY
}
}

//取栈顶元素
func GetTopData(stack *StackType) Element {
return stack.Array[stack.Top]
}

//判断栈满
func IsFull(stack *StackType) bool {
return stack.Top >= MAX_SIZE-1
}

//判断栈空
func IsEmpty(stack *StackType) bool {
return stack.Top == -1
}

//主函数
func main() {
stack := CreateStack()  //新建
Push(&stack, 80000)     //进栈
data := GetTopData(&stack)   //取栈顶元素
fmt.Println(data)
Push(&stack, 1951569)
Pop(&stack)      //出栈
}

这就是基本的栈的实现了。做了一些小的处理,基本能实现静态栈的功能。

尽量写下去吧,用golang实现一遍基本的数据结构:栈,队列,链表,二叉树,哈弗曼树,查找和排序的几种不同算法。自己给自己加油!

刘凯宁@C2P
20140811

Share

【Go语言】golang简易TCP服务器和客户机实现

今天介绍golang版本的通信基础:基于TCP的客户端和服务器实现,参考书籍:The Way To Go

那时学习java的时候也是做过通信的,当时是socket编程,服务器监听某一个端口,然后客户机去连接,简单的聊天室就实现了。后来有变成多线程的聊天室,可以进行群聊什么的了,后期可以传图片传音乐,加上UI那一块儿,山寨QQ就OK了。现在我来用golang实现一下简易的聊天室,实现了客户机连接服务器,给服务器发消息,服务器接受消息,客户机退出,服务器可以收到退出信息,以及多个客户机同时连入一个服务器。主要的思路和java一样的,服务器监听某一个端口,客户机去连接,然后发送消息就OK了。上代码了。

package main
//服务器端
import (
"fmt"
"log"
"net"  //支持的通信的包,一定要引进
)

//开始服务器
func startServer() {
//连接主机、端口,采用tcp方式通信,监听7777端口
listener, err := net.Listen("tcp", "localhost:7777")
checkError(err)
fmt.Println("建立成功!")
for {
//等待客户端接入
conn, err := listener.Accept()
checkError(err)
//开一个goroutines处理客户端消息,这是golang的特色,实现并发就只go一下就好
go doServerStuff(conn)
}
}

//处理客户端消息
func doServerStuff(conn net.Conn) {
nameInfo := make([]byte, 512)//生成一个缓存数组
_, err := conn.Read(nameInfo)
checkError(err)

for {
buf := make([]byte, 512)
_, err := conn.Read(buf)//读取客户机发的消息
flag := checkError(err)
if flag == 0 {
break
}
fmt.Println(string(buf))//打印出来
}
}

//检查错误
func checkError(err error) int {
if err != nil {
if err.Error() == "EOF" {
//fmt.Println("用户退出了")
return 0
}
log.Fatal("an error!", err.Error())
return -1
}
return 1
}
func main() {
//开启服务
startServer()
}

以上是服务器的实现,具体看代码注释

package main
//客户机
import (
	"bufio"  //便于读写的包bufferio
	"fmt"
	"log"
	"net"
	"os"
	"strings"
)

//连接服务器
func connectServer() {
	//接通
	conn, err := net.Dial("tcp", "localhost:7777")
	checkError(err)
	fmt.Println("连接成功!\n")
	//输入
	inputReader := bufio.NewReader(os.Stdin)
	fmt.Println("你是谁?")
	name, _ := inputReader.ReadString('\n')
	//
	trimName := strings.Trim(name, "\r\n")
	conn.Write([]byte(trimName + " 接入了\n "))
	for {
		fmt.Println("我们来聊天吧!按quit退出")
		//读一行
		input, _ := inputReader.ReadString('\n')
		trimInput := strings.Trim(input, "\r\n")
		//如果quit就退出
		if trimInput == "quit" {
			fmt.Println("再见")
			conn.Write([]byte(trimName + " 退出了 "))
			return
		}
		//写出来
		_, err = conn.Write([]byte(trimName + " says " + trimInput))
	}
}

//检查错误
func checkError(err error) {
	if err != nil {
		log.Fatal("an error!", err.Error())
	}
}

//主函数
func main() {
	//连接servser
	connectServer()
}

以上是客户机代码,具体看注释

运行的时候,分别go run server和client,你变可以看到这样就可以连接成功了。
服务器只用开一个,客户机可以开任意个,并且相互之间没有干扰。

OK,一个简单的多线程聊天室就实现了。后期可以加上更多的功能,但无非就是去处理输入输出,重点都已经有了。

刘凯宁@C2P
20140807

Share