Go语言学习笔记(八)golang 操作 Redis & Mysql & RabbitMQ
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959
Reids
安装导入
go get github.com/garyburd/redigo/redis
import "github.com/garyburd/redigo/redis"
链接
github:https://github.com/antirez/redis
Doc:http://godoc.org/github.com/garyburd/redigo/redis
Redis全套使用:http://www.cnblogs.com/suoning/p/5807247.html
使用
连接
import "github.com/garyburd/redigo/redis" func main() {
c, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("conn redis failed, err:", err)
return
}
defer c.Close()
}
set & get
_, err = c.Do("Set", "name", "nick")
if err != nil {
fmt.Println(err)
return
} r, err := redis.String(c.Do("Get", "name"))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(r)
mset & mget
批量设置
_, err = c.Do("MSet", "name", "nick", "age", "")
if err != nil {
fmt.Println("MSet error: ", err)
return
} r2, err := redis.Strings(c.Do("MGet", "name", "age"))
if err != nil {
fmt.Println("MGet error: ", err)
return
}
fmt.Println(r2)
hset & hget
hash操作
_, err = c.Do("HSet", "names", "nick", "suoning")
if err != nil {
fmt.Println("hset error: ", err)
return
} r, err = redis.String(c.Do("HGet", "names", "nick"))
if err != nil {
fmt.Println("hget error: ", err)
return
}
fmt.Println(r)
expire
设置过期时间
_, err = c.Do("expire", "names", )
if err != nil {
fmt.Println("expire error: ", err)
return
}
lpush & lpop & llen
队列
// 队列
_, err = c.Do("lpush", "Queue", "nick", "dawn", )
if err != nil {
fmt.Println("lpush error: ", err)
return
}
for {
r, err = redis.String(c.Do("lpop", "Queue"))
if err != nil {
fmt.Println("lpop error: ", err)
break
}
fmt.Println(r)
}
r3, err := redis.Int(c.Do("llen", "Queue"))
if err != nil {
fmt.Println("llen error: ", err)
return
}
连接池
各参数的解释如下:
MaxIdle:最大的空闲连接数,表示即使没有redis连接时依然可以保持N个空闲的连接,而不被清除,随时处于待命状态。
MaxActive:最大的激活连接数,表示同时最多有N个连接
IdleTimeout:最大的空闲连接等待时间,超过此时间后,空闲连接将被关闭
pool := &redis.Pool{
MaxIdle: ,
MaxActive: ,
IdleTimeout: ,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "localhost:6379")
},
}
连接池栗子
package main import (
"fmt" "github.com/garyburd/redigo/redis"
) var pool *redis.Pool func init() {
pool = &redis.Pool{
MaxIdle: ,
MaxActive: ,
IdleTimeout: ,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", "localhost:6379")
},
}
} func main() {
c := pool.Get()
defer c.Close() _, err := c.Do("Set", "name", "nick")
if err != nil {
fmt.Println(err)
return
} r, err := redis.String(c.Do("Get", "name"))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(r)
}
管道操作
请求/响应服务可以实现持续处理新请求,客户端可以发送多个命令到服务器而无需等待响应,最后在一次读取多个响应。
使用Send(),Flush(),Receive()方法支持管道化操作
Send向连接的输出缓冲中写入命令。
Flush将连接的输出缓冲清空并写入服务器端。
Recevie按照FIFO顺序依次读取服务器的响应。
func main() {
c, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("conn redis failed, err:", err)
return
}
defer c.Close() c.Send("SET", "name1", "sss1")
c.Send("SET", "name2", "sss2") c.Flush() v, err := c.Receive()
fmt.Printf("v:%v,err:%v\n", v, err)
v, err = c.Receive()
fmt.Printf("v:%v,err:%v\n", v, err) v, err = c.Receive() // 夯住,一直等待
fmt.Printf("v:%v,err:%v\n", v, err)
}
Mysql
安装导入
go get "github.com/go-sql-driver/mysql"
go get "github.com/jmoiron/sqlx" import (
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
链接:
github:
https://github.com/go-sql-driver/mysql
https://github.com/jmoiron/sqlx
Doc:
http://godoc.org/github.com/jmoiron/sqlx
http://jmoiron.github.io/sqlx/
Mysql全套使用:http://www.cnblogs.com/suoning/p/5769141.html
连接
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
} Db = database
}
栗子建表
CREATE TABLE `person` (
`user_id` int() DEFAULT NULL,
`username` varchar() DEFAULT NULL,
`sex` varchar() DEFAULT NULL,
`email` varchar() DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
栗子(insert)
package main import (
"fmt" _ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) type Person struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
} var Db *sqlx.DB func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
}
Db = database
} func main() {
r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "suoning", "man", "suoning@net263.com")
if err != nil {
fmt.Println("exec failed, ", err)
return
}
id, err := r.LastInsertId()
if err != nil {
fmt.Println("exec failed, ", err)
return
} fmt.Println("insert succ:", id)
}
栗子(update)
package main import (
"fmt" _ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) type Person struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
} var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
} Db = database
} func main() { _, err := Db.Exec("update person set user_id=? where username=?", , "suoning")
if err != nil {
fmt.Println("exec failed, ", err)
return
} }
栗子(select)
package main import (
"fmt" _ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) type Person struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
} type Place struct {
Country string `db:"country"`
City string `db:"city"`
TelCode int `db:"telcode"`
} var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
} Db = database
} func main() { var person []Person
err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", )
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("select succ:", person) people := []Person{}
Db.Select(&people, "SELECT * FROM person ORDER BY user_id ASC")
fmt.Println(people)
jason, john := people[], people[]
fmt.Printf("%#v\n%#v", jason, john)
}
栗子(delete)
package main import (
"fmt" _ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) type Person struct {
UserId int `db:"user_id"`
Username string `db:"username"`
Sex string `db:"sex"`
Email string `db:"email"`
} var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
} Db = database
} func main() { _, err := Db.Exec("delete from person where username=? limit 1", "suoning")
if err != nil {
fmt.Println("exec failed, ", err)
return
} fmt.Println("delete succ")
}
事务
package main import (
"github.com/astaxie/beego/logs"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
) var Db *sqlx.DB func init() {
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
if err != nil {
logs.Error("open mysql failed,", err)
return
}
Db = database
} func main() {
conn, err := Db.Begin()
if err != nil {
logs.Warn("DB.Begin failed, err:%v", err)
return
} defer func() {
if err != nil {
conn.Rollback()
return
}
conn.Commit()
}() // do something
}
RabbitMQ
安装
go get "github.com/streadway/amqp"
文档:
https://github.com/rabbitmq/rabbitmq-tutorials/tree/master/go
栗子一(普通模式)
生产者:
package main import (
"fmt"
"log"
"os"
"strings" "github.com/streadway/amqp"
"time"
) /*
默认点对点模式
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func main() {
// 连接
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() // 打开一个并发服务器通道来处理消息
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() // 申明一个队列
q, err := ch.QueueDeclare(
"task_queue", // name
true, // durable 持久性的,如果事前已经声明了该队列,不能重复声明
false, // delete when unused
false, // exclusive 如果是真,连接一断开,队列删除
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") body := bodyFrom(os.Args) // 发布
err = ch.Publish(
"", // exchange 默认模式,exchange为空
q.Name, // routing key 默认模式路由到同名队列,即是task_queue
false, // mandatory
false,
amqp.Publishing{
// 持久性的发布,因为队列被声明为持久的,发布消息必须加上这个(可能不用),但消息还是可能会丢,如消息到缓存但MQ挂了来不及持久化。
DeliveryMode: amqp.Persistent,
ContentType: "text/plain",
Body: []byte(body),
})
failOnError(err, "Failed to publish a message")
log.Printf(" [x] Sent %s", body)
} func bodyFrom(args []string) string {
var s string
if (len(args) < ) || os.Args[] == "" {
s = fmt.Sprintf("%s-%v","hello", time.Now())
} else {
s = strings.Join(args[:], " ")
}
return s
}
消费者:
package main import (
"bytes"
"fmt"
"github.com/streadway/amqp"
"log"
"time"
) /*
默认点对点模式
工作方,多个,拿发布方的消息
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() // 指定队列!
q, err := ch.QueueDeclare(
"task_queue", // name
true, // durable
false, // delete when unused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") // Fair dispatch 预取,每个工作方每次拿一个消息,确认后才拿下一次,缓解压力
err = ch.Qos(
, // prefetch count
, // prefetch size
false, // global
)
failOnError(err, "Failed to set QoS") // 消费根据队列名
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
false, // auto-ack 设置为真自动确认消息
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer") forever := make(chan bool) go func() {
for d := range msgs {
log.Printf("Received a message: %s", d.Body)
dot_count := bytes.Count(d.Body, []byte("."))
t := time.Duration(dot_count)
time.Sleep(t * time.Second)
log.Printf("Done") // 确认消息被收到!!如果为真的,那么同在一个channel,在该消息之前未确认的消息都会确认,适合批量处理
// 真时场景:每十条消息确认一次,类似
d.Ack(false)
}
}() log.Printf(" [*] Waiting for messages. To exit press CTRL+C")
<-forever
}
栗子二(订阅模式)
订阅 生产者:
package main import (
"fmt"
"github.com/streadway/amqp"
"log"
"os"
"strings"
"time"
) /*
广播模式
发布方
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() // 默认模式有默认交换机,广播自己定义一个交换机,交换机可与队列进行绑定
err = ch.ExchangeDeclare(
"logs", // name
"fanout", // type 广播模式
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange") body := bodyFrom(os.Args) // 发布
err = ch.Publish(
"logs", // exchange 消息发送到交换机,这个时候没队列绑定交换机,消息会丢弃
"", // routing key 广播模式不需要这个,它会把所有消息路由到绑定的所有队列
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(body),
})
failOnError(err, "Failed to publish a message") log.Printf(" [x] Sent %s", body)
} func bodyFrom(args []string) string {
var s string
if (len(args) < ) || os.Args[] == "" {
s = fmt.Sprintf("%s-%v","hello", time.Now())
} else {
s = strings.Join(args[:], " ")
}
return s
}
订阅 消费者:
package main import (
"fmt"
"github.com/streadway/amqp"
"log"
) /*
广播模式
订阅方
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() // 同样要申明交换机
err = ch.ExchangeDeclare(
"logs", // name
"fanout", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange") // 新建队列,这个队列没名字,随机生成一个名字
q, err := ch.QueueDeclare(
"", // name
false, // durable
false, // delete when usused
true, // exclusive 表示连接一断开,这个队列自动删除
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") // 队列和交换机绑定,即是队列订阅了发到这个交换机的消息
err = ch.QueueBind(
q.Name, // queue name 队列的名字
"", // routing key 广播模式不需要这个
"logs", // exchange 交换机名字
false,
nil)
failOnError(err, "Failed to bind a queue") // 开始消费消息,可开多个订阅方,因为队列是临时生成的,所有每个订阅方都能收到同样的消息
msgs, err := ch.Consume(
q.Name, // queue 队列名字
"", // consumer
true, // auto-ack 自动确认
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer") forever := make(chan bool) go func() {
for d := range msgs {
log.Printf(" [x] %s", d.Body)
}
}() log.Printf(" [*] Waiting for logs. To exit press CTRL+C")
<-forever
}
栗子三(RPC模式)
RPC 应答方:
package main import (
"fmt"
"log"
"strconv" "github.com/streadway/amqp"
) /*
RPC模式
应答方
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func fib(n int) int {
if n == {
return
} else if n == {
return
} else {
return fib(n-) + fib(n-)
}
} func main() { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() q, err := ch.QueueDeclare(
"rpc_queue", // name
false, // durable
false, // delete when usused
false, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") // 公平分发 没有这个则round-robbin
err = ch.Qos(
, // prefetch count
, // prefetch size
false, // global
)
failOnError(err, "Failed to set QoS") // 消费,等待请求
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
false, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer") forever := make(chan bool) go func() {
//请求来了
for d := range msgs {
n, err := strconv.Atoi(string(d.Body))
failOnError(err, "Failed to convert body to integer") log.Printf(" [.] fib(%d)", n) // 计算
response := fib(n) // 回答
err = ch.Publish(
"", // exchange
d.ReplyTo, // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
CorrelationId: d.CorrelationId, //序列号
Body: []byte(strconv.Itoa(response)),
})
failOnError(err, "Failed to publish a message") // 确认回答完毕
d.Ack(false)
}
}() log.Printf(" [*] Awaiting RPC requests")
<-forever
}
RPC 请求方:
package main import (
"fmt"
"log"
"math/rand"
"os"
"strconv"
"strings"
"time" "github.com/streadway/amqp"
) /*
RPC模式
请求方
*/ func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
} func randomString(l int) string {
bytes := make([]byte, l)
for i := ; i < l; i++ {
bytes[i] = byte(randInt(, ))
}
return string(bytes)
} func randInt(min int, max int) int {
return min + rand.Intn(max-min)
} func fibonacciRPC(n int) (res int, err error) { conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close() ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close() // 队列声明
q, err := ch.QueueDeclare(
"", // name
false, // durable
false, // delete when usused
true, // exclusive 为真即连接断开就删除
false, // noWait
nil, // arguments
)
failOnError(err, "Failed to declare a queue") msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive 这个为真,服务器会认为这是该队列唯一的消费者
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer") corrId := randomString() err = ch.Publish(
"", // exchange
"rpc_queue", // routing key
false, // mandatory
false, // immediate
amqp.Publishing{
ContentType: "text/plain",
CorrelationId: corrId,
ReplyTo: q.Name,
Body: []byte(strconv.Itoa(n)),
})
failOnError(err, "Failed to publish a message") for d := range msgs {
if corrId == d.CorrelationId {
res, err = strconv.Atoi(string(d.Body))
failOnError(err, "Failed to convert body to integer")
break
}
} return
} func main() {
rand.Seed(time.Now().UTC().UnixNano()) n := bodyFrom(os.Args) log.Printf(" [x] Requesting fib(%d)", n)
res, err := fibonacciRPC(n)
failOnError(err, "Failed to handle RPC request") log.Printf(" [.] Got %d", res)
} func bodyFrom(args []string) int {
var s string
if (len(args) < ) || os.Args[] == "" {
s = ""
} else {
s = strings.Join(args[:], " ")
}
n, err := strconv.Atoi(s)
failOnError(err, "Failed to convert arg to integer")
return n
}
Go语言学习笔记(八)golang 操作 Redis & Mysql & RabbitMQ的更多相关文章
- golang 操作 Redis & Mysql & RabbitMQ
golang 操作 Redis & Mysql & RabbitMQ Reids 安装导入 go get github.com/garyburd/redigo/redis import ...
- Go语言学习笔记八: 数组
Go语言学习笔记八: 数组 数组地球人都知道.所以只说说Go语言的特殊(奇葩)写法. 我一直在想一个人参与了两种语言的设计,但是最后两种语言的语法差异这么大.这是自己否定自己么,为什么不与之前统一一下 ...
- python学习笔记:python操作redis
Redis 是一个高性能的key-value数据库.它支持存储的value类型包括string(字符串).list(链表).set(集合).zset(sorted set --有序集合)和hash(哈 ...
- R语言学习笔记:SQL操作
虽然R很强大,但如果对SQL非常熟悉,也不能浪费这项技能了,可以用上sqldf包,从example("sqldf")抄了几条用法放在这里,以后可能会用上. library(&quo ...
- Redis学习笔记八:集群模式
作者:Grey 原文地址:Redis学习笔记八:集群模式 前面提到的Redis学习笔记七:主从复制和哨兵只能解决Redis的单点压力大和单点故障问题,接下来要讲的Redis Cluster模式,主要是 ...
- go语言之行--golang操作redis、mysql大全
一.redis 简介 redis(REmote DIctionary Server)是一个由Salvatore Sanfilippo写key-value存储系统,它由C语言编写.遵守BSD协议.支持网 ...
- golang学习笔记13 Golang 类型转换整理 go语言string、int、int64、float64、complex 互相转换
golang学习笔记13 Golang 类型转换整理 go语言string.int.int64.float64.complex 互相转换 #string到intint,err:=strconv.Ato ...
- Redis学习笔记(1)——Redis简介
一.Redis是什么? Remote Dictionary Server(Redis) 是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value ...
- 2017-04-21周C语言学习笔记
C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...
随机推荐
- ARP欺骗分析
(作者原创,欲转载请说明出处)1.arp介绍 arp:地址解析协议;将IP地址映射为MAC地址.2.为什么要有arp 平时上网我们都知道要有一个IP地址才能上网,那arp用来干嘛的呢?如果 ...
- Docker镜像构建的两种方式
关于Docker里面的几个主要概念 这里用个不太恰当的比方来说明. 大家肯定安装过ghost系统,镜像就像是ghost文件,容器就像是ghost系统.你可以拿别人的ghost文件安装系统(使用镜像运行 ...
- 移动端300ms的点击延迟以及解决方案
[今天做在移动端的一些效果时,我选择使用动画而不是用过渡,这个300ms的点击延迟是我为什么使用动画而不使用过渡最主要的一个原因] 动画和过渡 共同点:都是css控制DOM运动, 不同点: 1.过渡: ...
- Java 数据类型在实际开发中应用二枚举
在实际编程中,往往存在着这样的"数据集",它们的数值在程序中是稳定的,而且"数据集"中的元素是有限的.在JDK1.5之前,人们用接口来描述这一种数据类型. 1. ...
- java 关键字final
一.最终的意思,可以修饰类,方法,变量.特点: A:它修饰的类,不能被继承. B:它修饰的方法,不能被重写. C:它修饰的变量,是一个常量.二.面试相关: 1.局部变量基本类型 值不能发生改变 例如: ...
- 为何你跟着滴滴D8级前端大神撸代码,技术却依旧原地踏步?
引子 听说最近有很多小伙伴,热衷于在慕课网上学习各种前端实战教程,并以完成项目为奋斗目标.比如本文接下来要提到的<Vue2.0高级实战之开发移动端音乐App>,这门课程的传授者是来自滴滴D ...
- php简明学习笔记
1.变量 <?php //变量声明(php变量无需单独创建,变量会在第一次赋值时创建) $a = 1; //弱类型(php变量会根据其值自动转换为相应的数据类型) $a = "a&qu ...
- Vulkan Tutorial 29 Loading models
操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 Introduction 应用程序现在已经可以渲染纹理3D模型,但是 vertice ...
- Jmeter连接DB2/ORACLE/MYSQL数据库
连接DB2 1.将db2数据库驱动db2java.jar.db2jcc.jar放入jmeter的lib/下,同时也要放入本地jdk目录下例如:C:\Program Files\Java\jdk1.7. ...
- jQuery点击缩略图切换大图代码
很多网站上都会有点击缩略图切换成大图的效果,下面来分享一下它的源码 还是先来看效果截图 运行文件 然后点击下一张 下面分享源代码 html文件 <!DOCTYPE html PUBLIC &qu ...