开源高性能 web 缓存服务器 nuster

kehokoduru 发表了文章 • 0 个评论 • 147 次浏览 • 1 天前 • 来自相关话题

nuster, 一个基于 HAProxy 的高性能 web 缓存服务器 。 完全兼容 HAProxy,并且利用 HAProxy 的 ACL 功能来提供非常细致的缓存规则。

项目地址 查看全部

nuster, 一个基于 HAProxy 的高性能 web 缓存服务器 。 完全兼容 HAProxy,并且利用 HAProxy 的 ACL 功能来提供非常细致的缓存规则。


项目地址 https://github.com/jiangwenyuan/nuster


可以根据 url, path, query, header, cookie,请求速率等等来动态生成缓存,并设置有效期。支持 purge,支持前后端 HTTPS。



  • 完全兼容 HAProxy,支持所有 HAProxy 的特性和功能

  • 强大的动态缓存功能

    • 根据 HTTP method, uri, path, query, header, cookie 等等进行缓存

    • 根据 HTTP 请求和响应内容等等进行缓存

    • 根据环境变量服务器状态等等进行缓存

    • 根据 SSL 版本, SNI 等等进行缓存

    • 根据连接数量,请求速率等等进行缓存

    • 等等


  • 非常快

  • 删除缓存

  • 前后端 HTTPS

  • HTTP 压缩

  • HTTP 重写重定向

  • 等等


性能


非常快, 单进程模式下是 nginx 的 3 倍,多进程下 nginx 的 2 倍,varnish 的 3 倍。


详见https://github.com/jiangwenyuan/nuster/wiki/Web-cache-server-performance-benchmark:-nuster-vs-nginx-vs-varnish-vs-squid

用Golang画一个聊天信息

zhqy 发表了文章 • 0 个评论 • 252 次浏览 • 2018-02-14 00:07 • 来自相关话题

前两天看到一篇博文讲用canvas去画一个聊天信息(表情贴纸),然后自己没事用Go... 查看全部

前两天看到一篇博文讲用canvas去画一个聊天信息(表情贴纸),然后自己没事用Golang去实现了一下,可以写入到文件,也可以写到标准输出配合命令行工具在iterm2上display出来
参见:https://github.com/kr1sten0/draw-chat-message


效果:

分享一个用 go 写的 windows 进程守护小工具

回复

smallfish1 发起了问题 • 1 人关注 • 0 个回复 • 264 次浏览 • 2018-01-26 15:37 • 来自相关话题

calibre简易封装包,将html或markdown生成epub、pdf和mobi电子书

皇虫 发表了文章 • 0 个评论 • 201 次浏览 • 2018-01-21 14:23 • 来自相关话题

calibre简易封装包,将html或markdown生成epub、pdf和mobi电子书。

具体使用教程,见GitHub项目: https:/... 查看全部

calibre简易封装包,将html或markdown生成epub、pdf和mobi电子书。


具体使用教程,见GitHub项目:
https://github.com/TruthHun/converter


文档生成效果:
https://github.com/TruthHun/converter/tree/master/example/gogs_zh/output

thrift 的几个需要改进的地方

taowen 发表了文章 • 0 个评论 • 211 次浏览 • 2018-01-19 09:03 • 来自相关话题

两次拷贝

因为 thrift IDL 生成出来的 struct 不是很好用,比如:

  • 用 *int 表示 optional
  • 无法增加不在 IDL 里的业务字段

所以为... 查看全部

两次拷贝


因为 thrift IDL 生成出来的 struct 不是很好用,比如:



  • 用 *int 表示 optional

  • 无法增加不在 IDL 里的业务字段


所以为了避免和 thrift 的 codegen 做搏斗,业务就自己再定义了一个struct。然后解析的过程就变成了


[]byte => thrift struct => 业务的 struct

这就多了一次内存的拷贝,同时增加了GC负担。这个问题最佳的解决办法就是直接对象绑定到业务 struct 上,也就是 Go 的 struct 不用和 IDL 字段一一对应。这种映射关系和常见 JSON 绑定是类似的。


没 IDL 无法编解码


不是所有人都喜欢代码生成的。有的时候为了开发方便,会希望能不能用反射之类的方式直接绑定到对象上。


即便排除掉口味偏好。仍然有一些场景下无法用Codegen来解决。比如,我们需要一个 thrift proxy。这个代理可以在网络传输过程中修改 thrift message 的第0个参数的内容。我们不能提前知道所有可能的 thrift message 的 IDL,当然也无法对这些 IDL 提前代码生成。使用官方的 thrift lib 是很难优雅地解决这个问题地。


官方的库有性能问题


根据第三方 benchmark: https://github.com/smallnest/gosercomp


这个是 protobuf 的结果


BenchmarkMarshalByGogoProtoBuf-4 20000000   109 ns/op   48 B/op 1 allocs/op
BenchmarkUnmarshalByGogoProtoBuf-4 3000000 408 ns/op 144 B/op 8 allocs/op

这个是 thrift 的结果


BenchmarkMarshalByThrift-4 3000000  462 ns/op   64 B/op 1 allocs/op
BenchmarkUnmarshalByThrift-4 1000000 1356 ns/op 656 B/op 11 allocs/op

性能差距还是非常大的。到底有多慢呢?我们看一下 JSON + 反射的速度


BenchmarkMarshalByJsoniter-4 2000000    721 ns/op   800 B/op    5 allocs/op
BenchmarkUnmarshalByJsoniter-4 3000000 473 ns/op 112 B/op 6 allocs/op

也就是说,在 Go 里面使用 thrift 未必比 JSON 要快。再加上前面提到的第一个问题。事实上,如果不改进官方的Go版本的库(其实Java版本也很糟糕),还不如选择JSON。


为什么会慢呢?主要是这么两点



  • 完全无buffer的解析。所有的数据都假设从 io.Reader 里读取出来。

  • 中途大量的 check err 的代码


thrift 改进计划


thrift 这个协议本身没啥问题。主要是库实现得不好。我们给 Go 写一个新的库吧: https://github.com/thrift-iterator/go



  • 通过静态代码生成支持对象绑定,基于纯 Go 实现的代码生成框架 https://github.com/v2pro/wombat ,从 Go struct 直接生成代码。

  • 通过 jsoniter 类似的反射支持对象绑定,实现性能不受太大影响的情况下,不用代码生成也能使用 thrift协议

  • 支持无 IDL 解析,移植 jsoniter 的 api

    • 支持 iterator api,支持不同字段用不同的解析模式

    • 能 skip 字段并返回 []byte

    • 支持把thrift解析成map


  • 重写解析代码,达到和Protobuf一样的性能水平

goweb,基于go语言的API框架

Alber 发表了文章 • 0 个评论 • 401 次浏览 • 2018-01-17 20:34 • 来自相关话题

goweb

一个基于go语言的快速开发WebAPI的工具,这个工具受到了SpringMVC的启发,结合了go语言本身的特性,整体比较简单,接下来,看看如何使用它。

下载安装:

查看全部
					

goweb


一个基于go语言的快速开发WebAPI的工具,这个工具受到了SpringMVC的启发,结合了go语言本身的特性,整体比较简单,接下来,看看如何使用它。


下载安装:


go get github.com/alberliu/goweb

1.核心功能


请求体参数注入


package main

import "github.com/alberliu/goweb"

type User struct {
Id int `json:"id"`
Name string `json:"name"`
}

func handler(user User) User {
return user
}

func main() {
goweb.HandlePost("/test", handler)
goweb.ListenAndServe(":8000")
}

请求体:


{
"id": 1,
"name": "alber"
}

响应体:


{
"id": 1,
"name": "alber"
}

上面的代码是一个最简的例子,HandlePost(string, interface{})会将一个handler注册到一个全局的内置的goweb实例defultGoWeb,ListenAndServe(":8000")会将defultGoWeb赋给Server的handler变量,然后启动这个Server。(是不是和内置的ServerMux有点像)


goweb会自动解析注册到它本身的handler,当请求到来时,会将请求体的json数据反序列化并注入到handler的参数,handler处理完逻辑返回时,会将handler的返回值序列化为json数据返回。goweb默认使用json的序列化和反序列化方式,当然你可以定义自己的序列化方式,这个在后面你可以看到。


例子给出的handler的参数和返回都是结构体类型,当然你也可以使用指针类型。


结构体goweb其实本质上就是一个路由,它实现了Handler接口。上面的例子都是默认的defultGoWeb,你也可以自己实例化一个goweb。


func main() {
goweb:=goweb.NewGoWeb();
goweb.HandlePost("/test", handler)
server := &http.Server{Addr: ":8000", Handler: goweb}
server.ListenAndServe()
}

url参数注入


package main

import "github.com/alberliu/goweb"

type User struct {
Id int64 `json:"id"`
Name string `json:"name"`
}

func handler(id int64, name string) User {
return User{id, name}
}

func main() {
goweb := goweb.NewGoWeb();
goweb.HandleGet("/test/{id}/{name}", handler)
goweb.ListenAndServe(":8000")
}

执行上面的代码,然后访问url:http://localhost:8000/test/123456/alber


就可以返回下面的json数据


{
"id": 123456,
"name": "alber"
}

handler可以获取到url中的参数,并且注入到handler参数中。handler的第一个参数对应url中的第一个参数,第二个参数对应url中的的第二个参数,依次类推。不过暂时还有个限制,在url中使用参数时,handler中的参数必须与url中的参数个数一致,且类型必须为string或者int64。


2.handler


goweb可以注册多种形式的handler,goweb会利用反射自动解析函数,支持多种类型,但是不能超出它可以解析的范围。以下是它所有能解析的类型。



func handler(ctx goweb.Context) {
}

func handler(ctx goweb.Context) User {
return User{}
}

func handler(user User) User {
return User{}
}

func handler(ctx goweb.Context, user User) User {
return User{}
}

func handler(name string, id int64) User {
return User{}
}

func handler(ctx goweb.Context, name string, id int64) User {
return User{}
}

Context是一个请求上下文,他只有ResponseWriter和Request两个字段,它的内部结构如下所示。你可以根据自己的需求修改源码进行扩展,例如,把它作为一个请求的会话使用。


type Context struct {
w http.ResponseWriter
r *http.Request
}

3.用Group组织你的handler


func main() {
group1:=goweb.NewGroup("/group1")
group1.HandleGet("/handler1",handler)
group1.HandleGet("/handler2",handler)
group1.HandleGet("/handler3",handler)

group2:=goweb.NewGroup("/group2")
group2.HandleGet("/handler1",handler)
group2.HandleGet("/handler2",handler)
group2.HandleGet("/handler3",handler)

group3:=goweb.NewGroup("/group3")
group3.HandleGet("/handler1",handler)
group3.HandleGet("/handler2",handler)
group3.HandleGet("/handler3",handler)

goweb.HandleGroup(group1)
goweb.HandleGroup(group2)
goweb.HandleGroup(group3)
goweb.ListenAndServe(":8000")
}

group可以帮助你分层次的组织你的handler,使你的路由结构更清晰。


4.定义自己序列化和反序列化方式


var json = jsoniter.ConfigCompatibleWithStandardLibrary

func jsonUnmarshal(data []byte, v interface{}) error {
return json.Unmarshal(data, v)
}

func jsonMarshal(v interface{}) ([]byte, error){
return json.Marshal(v)
}

func main() {
goweb:=goweb.NewGoWeb();
goweb.Unmarshal=jsonUnmarshal
goweb.Marshal=jsonMarshal

goweb.ListenAndServe(":8000")

}

goweb默认采用json(使用的是开源的jsoniter)序列化和反序列化数据,goweb的Marshal、Unmarshal变量本身是一个函数.如果你想定义自己的序列化方式,只需要覆盖掉它就行,就像上面那样。


5.拦截器



func interceptor1(http.ResponseWriter, *http.Request) bool {
return true
}
func interceptor2(http.ResponseWriter, *http.Request) bool {
return true
}
func interceptor3(http.ResponseWriter, *http.Request) bool {
return true
}

func main() {
goweb := goweb.NewGoWeb();
goweb.AddInterceptor(interceptor1)
goweb.AddInterceptor(interceptor2)
goweb.AddInterceptor(interceptor3)
goweb.ListenAndServe(":8000")
}

goweb在执行handler之前,会执行一个或者多个interceptor,并且会根据AddInterceptor的先后顺序执行,当interceptor返回true时,会接着往下执行,返回false时,会终止执行。


6.过滤器


func filter(w http.ResponseWriter, r *http.Request, f func(http.ResponseWriter, *http.Request)) {
f(w, r)
}

func main() {
goweb := goweb.NewGoWeb();
goweb.Filter = filter
goweb.ListenAndServe(":8000")
}

你可以给goweb添加一个过略器,在过滤器中,如果你想执行完自己的逻辑之后,执行handler,只需要调用f(w, r)。


7.自定义错误处理



func handler400(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(400)
w.Write([]byte("bad request"))
}
func handler404(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
w.Write([]byte("url not found"))
}
func handler405(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(405)
w.Write([]byte("method not found"))
}

func main() {
goWeb := goweb.NewGoWeb()
goWeb.Handler400 = handler400
goWeb.Handler404 = handler404
goWeb.Handler405 = handler405

goweb.ListenAndServe(":8000")
}

当请求执行失败时,goweb中给出了一些默认的错误处理方式,就像上面那样。当然,你也可以定义一些自己错误处理方式。


写在后面


如果你有什么好的建议,可以发我邮箱,一起交流。


alber_liu@qq.com

goweb,基于go语言API框架

回复

Alber 发起了问题 • 0 人关注 • 0 个回复 • 241 次浏览 • 2018-01-17 20:32 • 来自相关话题

一个辅助操作数据库的go lib[from滴滴]

caibirdme 发表了文章 • 0 个评论 • 308 次浏览 • 2018-01-17 18:48 • 来自相关话题

github地址: gendry

gendry是一个非常简单易用的sql builder,比如构建sql语句:

... 查看全部

github地址: gendry


gendry是一个非常简单易用的sql builder,比如构建sql语句:


where := map[string]interface{}{
"city in": []interface{}{"beijing", "shanghai"},
"score": 5,
"age >": 35,
"_orderby": "bonus desc",
"_grouoby": "department",
}
table := "some_table"
selectFields := []string{"name", "age", "sex"}
cond, values, err := builder.BuildSelect(table, where, selectFields)
rows,err := db.Query(cond, vals...) // db: *sql.DB
//cond = SELECT name,age,sex FROM g_xxx WHERE (city IN (?,?) AND score=? AND age>?) GROUP BY department ORDER BY bonus DESC
//values = []interface{}{"beijing", "shanghai", 5, 35}

读取返回:


type Person struct {
Name string `json:"name"`
Age int `json:"m_age"`
}

rows,err := db.Query("SELECT age as m_age,name from g_xxx where xxx")
defer rows.Close()

var students []Person

scanner.Scan(rows, &students)

gendry最开始是我在滴滴的一个对外接口服务中使用,经过一年多的迭代和多个线上系统大流量的验证,已经非常稳定了。gendry的一个显著特点是非侵入性,只要你的项目目前使用的是标准库,那你就可以无痛添加gendry,大多数时候它就是一个helper函数。如果你不想用,一行代码就可以去掉,不会像orm一样牵一发动全身。gendry还提供了一个cli工具可以根据数据库表结构自动生成该表对应的结构体和对该表的增删改查的dao层代码。


gendry是个很简单的lib,期待大家的使用和意见,热烈欢迎各种pr


这里简要地写了一下我们为什么会开发这个lib: https://github.com/didi/gendry/wiki" title="为什么开发gendry">为什么开发gendry

分享个自己的golang项目 - bitproxy代理工具

回复

moliliang 发起了问题 • 1 人关注 • 0 个回复 • 385 次浏览 • 2018-01-12 16:03 • 来自相关话题

分享一个收集 Nginx 日志的 Exporter

smallfish1 发表了文章 • 0 个评论 • 230 次浏览 • 2018-01-04 21:21 • 来自相关话题

目的: 滚动收集 Nginx 日志并生成 Prometheus 采样数据。

功能:

  1. 动态配置 Nginx 日志格式
  2. Metric 支持静态和动态的 LabelSet
  3. 支持同时收集... 查看全部

目的: 滚动收集 Nginx 日志并生成 Prometheus 采样数据。


功能:



  1. 动态配置 Nginx 日志格式

  2. Metric 支持静态和动态的 LabelSet

  3. 支持同时收集多个日志


它能做什么:



  1. 统计任意 API 请求数,以及请求错误数。

  2. 任意 API 请求时长 95 值。

  3. 任意 API 请求包的大小 95值。


地址: https://github.com/songjiayang/nginx-log-exporter


欢迎大家试用和 PR

一个比较完整的 Vim debug workflow

SpaceVim 发表了文章 • 0 个评论 • 316 次浏览 • 2017-12-14 22:40 • 来自相关话题

SpaceVim Layers: debug


原文: http://spacevim.org/layers/debug/


Description


This layer provide a debug workflow for SpaceVim. All of the function is based on vim-vebugger.


Install


To use this configuration layer, add call SpaceVim#layers#load('debug') to your custom configuration file.


Key bindings























































Key Binding Description
SPC d l launching debugger
SPC d c Continue the execution
SPC d b Toggle a breakpoint for the current line
SPC d B Clear all breakpoints
SPC d o step over
SPC d i step into functions
SPC d O step out of current function
SPC d e s Evaluate and print the selected text
SPC d e e Evaluate the <cword> under the cursor
SPC d e S Execute the selected text
SPC d k Terminates the debugger

Debug Transient State


key bindings is too long? use SPC d . to open the debug transient state:


Debug Transient State

go超级时间轮timewheel(一路向前)github.com/anjieych/timewheel

Anjie 发表了文章 • 0 个评论 • 382 次浏览 • 2017-12-12 20:03 • 来自相关话题

go超级时间轮timewheel(一路向前)github.com/anjieych/timewheel

有传统时间轮的影子,但又超出传统时间轮:

  1. 非“盘/环”形结构: 一路向前,永... 查看全部

go超级时间轮timewheel(一路向前)github.com/anjieych/timewheel


有传统时间轮的影子,但又超出传统时间轮:



  1. 非“盘/环”形结构:
    一路向前,永不回头,每tick一次,移除一个slot;每个slot中的entity 触发OnExpired来处理到期(或过期)事件;

  2. 超级时间轮:
    他是一个轮或者轮的集合,因为他可以同时处理不同实现了Entity的业务,每个业务有各自OnExpired定义,只要可以遵循相同的时间刻度Interval就可以放入同一个轮来统一计时触发。
    最后,优点或缺点可以作者交流。


[========]


package main

import (
"fmt"
"github.com/anjieych/timewheel"
"time"
)

func main() {
tw := timewheel.NewTimewheel("tw-example", time.Second)
tw.Start()
tick := time.NewTicker(3 * time.Second)
for {
d := &Data{
eid: time.Now().UnixNano(),
data: <-tick.C,
}
d.SetSlotId(tw.Add(d, 5*time.Second))
}
}
// Data must implements timewheel.Entity
type Data struct {
eid int64
slotId int
data interface{}
}

func (d *Data) SetEId(eId int64) {
d.eid = eId
}
func (d *Data) GetEId() (eId int64) {
return d.eid
}
func (d *Data) SetSlotId(slotId int) {
d.slotId = slotId
}
func (d *Data) GetSlotId() (slotId int) {
return d.slotId
}
func (d *Data) OnExpired() {
fmt.Printf("%s\t OnExpired :{slotId: %d\t,eid: %d\t,data: %s}\n", time.Now(), d.GetSlotId(), d.GetEId(), d.data)
}

fx 已经支持 Go, Node, Python, Ruby, Java, PHP, Julia 这些语言了

回复

metrue 发起了问题 • 1 人关注 • 0 个回复 • 522 次浏览 • 2017-12-08 12:33 • 来自相关话题

分享一个带 TTL 以及失效回调的 LRU 库. https://github.com/Akagi201/kvcache

Akagi201 发表了文章 • 0 个评论 • 281 次浏览 • 2017-12-06 15:04 • 来自相关话题

https://github.com/Akagi201/kvcache

包含一个完整功能版本(每一个 TTL 的 key 用一个 gorou... 查看全部

https://github.com/Akagi201/kvcache


包含一个完整功能版本(每一个 TTL 的 key 用一个 goroutine 进行维护), 以及轻量级版本 (不使用 goroutine, 这样 TTL 时间计算不是很准确, 具体看代码逻辑)


完美达到我的业务需要的效果. 大家有同样的需求可以测试测试.


有问题一定向我反馈. akagi201@gmail.com

tsdump-用于导出数据库表结构的工具(支持导出为text、markdown、csv、json)

voidint 发表了文章 • 0 个评论 • 316 次浏览 • 2017-12-03 20:32 • 来自相关话题

项目地址: https://github.com/voidint/tsdump

特性

  • 支持将数据库(当前仅支持查看全部

项目地址: https://github.com/voidint/tsdump


特性



  • 支持将数据库(当前仅支持MySQL)及其表结构的元数据以textmarkdownjsoncsv形式输出。


安装


$ go get -u github.com/voidint/tsdump

基本使用




  • 全局选项


    GLOBAL OPTIONS:
    -H value, --host value Connect to host. (default: "127.0.0.1")
    -P value, --port value Port number to use for connection. (default: 3306)
    -u value, --user value User for login if not current user. (default: "voidint")
    -p value, --password value Password to use when connecting to server.
    -d value, --db value Database name.
    -V value, --viewer value Output viewer. Optional values: txt|csv|json|md (default: "txt")
    -o value, --output value Write to a file, instead of STDOUT.
    -D, --debug Enable debug mode.
    --help, -h show help
    --version, -v print the version



  • 使用root用户创建一个名为mydb的数据库实例,以及一张student的表。


    CREATE DATABASE IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

    USE `mydb`;

    CREATE TABLE `student` (
    `sno` char(8) NOT NULL COMMENT '学号',
    `sname` varchar(255) NOT NULL COMMENT '姓名',
    `gender` char(2) DEFAULT NULL COMMENT '性别',
    `native` char(20) DEFAULT NULL COMMENT '籍贯',
    `birthday` datetime DEFAULT NULL COMMENT '出生日期',
    `dno` char(6) DEFAULT NULL COMMENT '所在院系',
    `spno` char(8) DEFAULT NULL COMMENT '专业代码',
    `classno` char(4) DEFAULT NULL COMMENT '班级号',
    `entime` date DEFAULT NULL COMMENT '入校时间',
    `home` varchar(40) DEFAULT NULL COMMENT '家庭住址',
    `tell` varchar(40) DEFAULT NULL COMMENT '联系电话',
    PRIMARY KEY (`sno`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生信息表';



  • 将数据库及其表结构数据以表格形式输出到console


    $ tsdump -H 127.0.0.1 -P 3307 -u root -p "mypassword" --db mydb
    |----------|---------------|--------------------|
    | DATABASE | CHARACTER SET | COLLATION |
    |----------|---------------|--------------------|
    | mydb | utf8mb4 | utf8mb4_general_ci |
    |----------|---------------|--------------------|

    TABLE: student 学生信息表
    |----------|----------|--------------|---------------|--------------------|----------|
    | COLUMN | NULLABLE | DATA TYPE | CHARACTER SET | COLLATION | COMMENT |
    |----------|----------|--------------|---------------|--------------------|----------|
    | sno | NO | char(8) | utf8mb4 | utf8mb4_general_ci | 学号 |
    | sname | NO | varchar(255) | utf8mb4 | utf8mb4_general_ci | 姓名 |
    | gender | YES | char(2) | utf8mb4 | utf8mb4_general_ci | 性别 |
    | native | YES | char(20) | utf8mb4 | utf8mb4_general_ci | 籍贯 |
    | birthday | YES | datetime | | | 出生日期 |
    | dno | YES | char(6) | utf8mb4 | utf8mb4_general_ci | 所在院系 |
    | spno | YES | char(8) | utf8mb4 | utf8mb4_general_ci | 专业代码 |
    | classno | YES | char(4) | utf8mb4 | utf8mb4_general_ci | 班级号 |
    | entime | YES | date | | | 入校时间 |
    | home | YES | varchar(40) | utf8mb4 | utf8mb4_general_ci | 家庭住址 |
    | tell | YES | varchar(40) | utf8mb4 | utf8mb4_general_ci | 联系电话 |
    |----------|----------|--------------|---------------|--------------------|----------|



  • 将数据库及其表结构数据输出到markdown文件


    $ tsdump -H 127.0.0.1 -P 3307 -u root -p "mypassword" --db mydb -V md > ./mydb.md

    output:


    student


    学生信息表







































































































    COLUMN NULLABLE DATA TYPE CHARACTER SET COLLATION COMMENT
    sno NO char(8) utf8mb4 utf8mb4_general_ci 学号
    sname NO varchar(255) utf8mb4 utf8mb4_general_ci 姓名
    gender YES char(2) utf8mb4 utf8mb4_general_ci 性别
    native YES char(20) utf8mb4 utf8mb4_general_ci 籍贯
    birthday YES datetime 出生日期
    dno YES char(6) utf8mb4 utf8mb4_general_ci 所在院系
    spno YES char(8) utf8mb4 utf8mb4_general_ci 专业代码
    classno YES char(4) utf8mb4 utf8mb4_general_ci 班级号
    entime YES date 入校时间
    home YES varchar(40) utf8mb4 utf8mb4_general_ci 家庭住址
    tell YES varchar(40) utf8mb4 utf8mb4_general_ci 联系电话



  • 将数据库及其表结构数据输出到csv文件


    $ tsdump -H 127.0.0.1 -P 3307 -u root -p "mypassword" --db mydb -V csv -o ./mydb.csv


  • 将数据库及其表结构数据输出到JSON文件
    $ tsdump -H 127.0.0.1 -P 3307 -u root -p "mypassword" --db mydb -V json -o ./mydb.json