IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Xorm学习笔记 -> 正文阅读

[大数据]Xorm学习笔记


与你相识


博主介绍:

– 本人是普通大学生一枚,每天钻研计算机技能,CSDN主要分享一些技术内容,因我常常去寻找资料,不经常能找到合适的,精品的,全面的内容,导致我花费了大量的时间,所以会将摸索的内容全面细致记录下来。另外,我更多关于管理,生活的思考会在简书中发布,如果你想了解我对生活有哪些反思,探索,以及对管理或为人处世经验的总结,我也欢迎你来找我。

– 目前的学习专注于Go语言,辅学算法,前端领域。也会分享一些校内课程的学习,例如数据结构,计算机组成原理等等,如果你喜欢我的风格,请关注我,我们一起成长。



XORM学习笔记

我直接看的官方说明文档。

对xorm的说明

我现在所看的xorm库,是基于原版xorm库的定制增强版。

这是因为本定制版有第三方库依赖,而就是为了维持原版xorm对第三方库零依赖性,所以单独开了一个定制增强版本的xorm库

相关核心功能和原版xorm一致并随原版xorm更新。

安装

go get -u github.com/xormplus/xorm

创建orm引擎

xorm可以同时存在多个orm引擎,一个orm引擎称为Engine,一个Engine一般只对应一个数据库。

Engine通过调用xorm.NewEngine生成。

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/xormplus/xorm"
)

var engine *xorm.Engine

func main() {
    var err error
    engine, err = xorm.NewEngine("mysql", "root:123@/test?charset=utf8")
}

engine可以通过engine.Close来手动关闭,但是一般情况下可以不用关闭,在程序退出的时候会自动关闭。

在engine创建完成之后可以设置一些选项:

日志是一个接口,通过设置日志,可以显示SQL,警告以及错误等,默认的显示级别为INFO。

  • engine.ShowSQL(true),则会在控制台打印出生成的SQL语句;
  • engine.Logger().SetLevel(core.LOG_DEBUG),则会在控制台打印调试及以上的信息;

如果希望将信息不仅打印到控制台,而是保存为文件,那么可以通过类似如下的代码实现,NewSimpleLogger(w io.Writer)接收一个io.Writer接口来将数据写入到对应的设施中。

f, err := os.Create("sql.log")
if err != nil {
    println(err.Error())
    return
}
engine.SetLogger(xorm.NewSimpleLogger(f))

定义表的结构体

统一前缀,后缀

可以通过一种方式在表的字段前加上统一的前缀,后缀或缓存映射,但是表字段不会改变。

// 统一前缀
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, "prefix_")
engine.SetTableMapper(tbMapper)
// 统一后缀
ore.NewSufffixMapper(core.SnakeMapper{}, "suffix") 

Column属性

可以在列中对Column的一些属性进行定义

type User struct {
    Id   int64
    Name string  `xorm:"varchar(25) notnull unique 'usr_name'"`
}

还有很多其它的内容,参考官方操作手册。

表结构操作

获取数据库表结构信息

  • DBMetas()
    xorm支持获取表结构信息,通过调用engine.DBMetas()可以获取到数据库中所有的表,字段,索引的信息。

表操作

  • CreateTables()

创建表使用engine.CreateTables(),参数为一个或多个空的对应Struct的指针。同时可用的方法有Charset()和StoreEngine(),如果对应的数据库支持,这两个方法可以在创建表时指定表的字符编码和使用的引擎。Charset()和StoreEngine()当前仅支持Mysql数据库。

  • IsTableEmpty()

判断表是否为空,参数和CreateTables相同

  • IsTableExist()

判断表是否存在

  • DropTables()

删除表使用engine.DropTables(),参数为一个或多个空的对应Struct的指针或者表的名字。如果为string传入,则只删除对应的表,如果传入的为Struct,则删除表的同时还会删除对应的索引。

同步数据库结构

同步能够部分智能的根据结构体的变动检测表结构的变动,并自动同步。目前有两个实现:

Sync


Sync将进行如下的同步操作:

  • 自动检测和创建表,这个检测是根据表的名字
  • 自动检测和新增表中的字段,这个检测是根据字段名
  • 自动检测和创建索引和唯一索引,这个检测是根据索引的一个或多个字段名,而不根据索引名称
err := engine.Sync(new(User), new(Group))

Sync2


对sync进行了改进,目前推荐使用。

下面的警告信息需要将engine.ShowWarn设置为true才会实现

  • 自动检测和创建表,这个检测是根据表的名字
  • 自动检测和新增表中的字段,这个检测是根据字段名,同时对表中多余的字段给出警告信息
  • 自动检测,创建和删除索引和唯一索引,这个检测是根据索引的一个或多个字段名,而不根据索引名称。因此这里需要注意,如果在一个有大量数据的表中引入新的索引,数据库可能需要一定的时间来建立索引。
  • 自动转换varchar字段类型到text字段类型,自动警告其它字段类型在模型和数据库之间不一致的情况。
  • 自动警告字段的默认值,是否为空信息在模型和数据库之间不匹配的情况
err := engine.Sync2(new(User), new(Group))

导入导出sql脚本

导入:

如果你需要将保存在文件或者其它存储设施中的SQL脚本执行,那么可以调用

engine.Import(r io.Reader)

engine.ImportFile(fpath string)

导出:

如果需要在程序中Dump数据库的结构和数据可以调用

engine.DumpAll(w io.Writer)

engine.DumpAllFile(fpath string)

DumpAll方法接收一个io.Writer接口来保存Dump出的数据库结构和数据的SQL语句,这个方法导出的SQL语句并不能通用。只针对当前engine所对应的数据库支持的SQL。

插入数据

使用xorm api来插入数据

使用InsertInsertOne来插入数据

user := new(User)
user.Name = "myname"
affected, err := engine.Insert(user)
// INSERT INTO user (name) values (?)
  • 批量插入会自动生成Insert into table values (),(),()的语句,因此各个数据库对SQL语句有长度限制,因此这样的语句有一个最大的记录数,根据经验测算在150条左右。大于150条后,生成的sql语句将太长可能导致执行失败。因此在插入大量数据时,目前需要自行分割成每150条插入一次。

使用SQL命令来插入数据

第1种方式

sql ="insert into config(key,value) values (?, ?)"
res, err := engine.Exec(sql, "OSCHINA", "OSCHINA") 

第2种方式

sql_2 := "insert into config(key,value) values (?, ?)"
affected, err := engine.Sql(sql_4, "OSCHINA", "OSCHINA").Execute()

第3种方式

//SqlMap中key为 "sql_i_1" 配置的Sql语句为:insert into config(key,value) values (?, ?)
sql_i_1 := "sql_i_1" 
affected, err := engine.SqlMapClient(sql_i_1, "config_1", "1").Execute()

//SqlMap中key为 "sql_i_2" 配置的Sql语句为:insert into config(key,value) values (?key, ?value)
sql_i_2 := "sql_i_2" 
paramMap_i := map[string]interface{}{"key": "config_2", "value": "2"}
affected, err := engine.SqlMapClient(sql_i_2, &paramMap_i).Execute()

第4种方式

sql_i_3 := "insert.example.stpl"
paramMap_i_t := map[string]interface{}{"key": "config_3", "value": "3"}
affected, err := engine.SqlTemplateClient(sql_i_3, &paramMap_i_t).Execute()

创建时间Created

我感觉这个特性很有意思。它可以让你在数据插入到数据库的时候自动将对应的字段设置为当前的时间,需要在xorm标记中使用created标记。 字段可以是time.Timeintint64int32等int类型。

只需要在后面加上xorm的映射即可,当添加记录的时候,created标记的字段就会被自动更新为当前时间。

type User struct {
    Id int64
    Name string
    CreatedAt time.Time `xorm:"created"`
}

查询和统计数据

ORM方式查询和统计数据

ORM所有的查询条件不区分调用顺序,但必须在调用Get,Find,Count,Iterate,Rows之前调用。

查询单条语句用Get,查询多条语句用Find

RowsIterate方法可以把查询的结果逐条的展示出来,Rows更加灵活。

更新数据

update方法

使用如下的方式来更新

user := new(User)
user.Name = "myname"
affected, err := engine.Id(id).Update(user)

乐观锁

可以使用如下方式添加乐观锁,在insert的时候,version标记的字段将会被设置为1。

type User struct { 
    Id int64 Name string 
    Version int xorm:"version" 
}

在update的时候,update结构体中的内容必须包含原version的值

var user User
engine.Id(1).Get(&user)
// SELECT * FROM user WHERE id = ?
engine.Id(1).Update(&user)
// UPDATE user SET ..., version = version + 1 WHERE id = ? AND version = ?

更新时间

可以通过updated标记,当调用Insert(), InsertOne(), Update()方法的时候,会自动的将对应自动设置为当前时间,对应的字段可以为time.Time或者自定义的time.Time或者int,int64等int类型。

type User struct {
    Id int64
    Name string
    UpdatedAt time.Time `xorm:"updated"`
}

通过sql命令更新数据

第1种方式

sql ="update user set age = ? where name = ?"
res, err := engine.Exec(sql, 1, "xorm") 

第2种方式

sql_2 := "update user set age = ? where name = ?"
affected, err := engine.Sql(sql_2, 1, "xorm").Execute()

第3种方式

//SqlMap中key为 "sql_i_1" 配置的Sql语句为:update user set age = ? where name = ?
sql_i_1 := "sql_i_1" 
affected, err := engine.SqlMapClient(sql_i_1, 1, "xorm").Execute()

//SqlMap中key为 "sql_i_2" 配置的Sql语句为:update user set age = ?age where name = ?name
sql_i_2 := "sql_i_2" 
paramMap_i := map[string]interface{}{"age": 1, "name": "xorm"}
affected, err := engine.SqlMapClient(sql_i_2, &paramMap_i).Execute()

第4种方式

sql_i_3 := "insert.example.stpl"
paramMap_i_t := map[string]interface{}{"age": 1, "name": "xorm"}
affected, err := engine.SqlTemplateClient(sql_i_3, &paramMap_i_t).Execute()

删除数据

Delete方法

第一个参数为删除的记录数,第二个为执行错误

user := new(User)
affected, err := engine.Id(id).Delete(user)

注意:当删除时,如果user中包含有bool,float64或者float32类型,有可能会使删除失败。具体请查看 FAQ

软删除 Deleted

在我以前的使用中,软删除都是要自己去做的,但是XORM通过标记给我们做好了。

type User struct {
    Id int64
    Name string
    DeletedAt time.Time `xorm:"deleted"`
    // 通过Cols来指定只更新某列
    affected, err := engine.Id(id).Cols("age").Update(&user)
}

通过sql语句删除数据

第1种方式

sql ="delete from user where id = ?"
res, err := engine.Exec(sql, 1) 

第2种方式

sql_2 := "delete from user where id = ?"
affected, err := engine.Sql(sql_2, 1).Execute()

第3种方式

//SqlMap中key为 "sql_i_1" 配置的Sql语句为:delete from user where id = ?
sql_i_1 := "sql_i_1" 
affected, err := engine.SqlMapClient(sql_i_1, 1).Execute()

//SqlMap中key为 "sql_i_2" 配置的Sql语句为:delete from user where id = ?id
sql_i_2 := "sql_i_2" 
paramMap_i := map[string]interface{}{"id": 1}
affected, err := engine.SqlMapClient(sql_i_2, &paramMap_i).Execute()

第4种方式

sql_i_3 := "insert.example.stpl"
paramMap_i_t := map[string]interface{}{"id": 1}
affected, err := engine.SqlTemplateClient(sql_i_3, &paramMap_i_t).Execute()

事务

简单事务使用

session := engine.NewSession()
defer session.Close()
// add Begin() before any action
err := session.Begin()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = session.Insert(&user1)
if err != nil {
    session.Rollback()
    return
}
user2 := Userinfo{Username: "yyy"}
_, err = session.Where("id = ?", 2).Update(&user2)
if err != nil {
    session.Rollback()
    return
}

_, err = session.Exec("delete from userinfo where username = ?", user2.Username)
if err != nil {
    session.Rollback()
    return
}

// add Commit() after all actions
err = session.Commit()
if err != nil {
    return
}

嵌套事务使用

在通常情况下,简单事务够我们使用了。 它与简单事务的不同在于,简单事务在同一个session下工作,而嵌套事物则会返回Transaction实例,后续操作则在同一个实例下操作。

session := engine.NewSession()
defer session.Close()
// add BeginTrans() before any action
tx, err := session.BeginTrans()
if err != nil {
    return
}

user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
_, err = tx.Session().Insert(&user1)
if err != nil {
    tx.Rollback()
    return
}

user2 := Userinfo{Username: "yyy"}
_, err = tx.Session().Where("id = ?", 2).Update(&user2)
if err != nil {
    tx.RollbackTrans()
    return
}

_, err = tx.Session().Exec("delete from userinfo where username = ?", user2.Username)
if err != nil {
    tx.RollbackTrans()
    return
}

_, err = tx.Session().SqlMapClient("delete.userinfo", user2.Username).Execute()
if err != nil {
    tx.RollbackTrans()
    return
}

// add CommitTrans() after all actions
err = tx.CommitTrans()
if err != nil {
    ...
    return
}

数据导出

查询结果集导出csv、tsv、xml、json、xlsx、yaml、html

xorm查询结果集支持导出csv、tsv、xml、json、xlsx、yaml、html七种文件格式

以导出xlsx文件格式为例,代码如下

err := engine.Sql("select * from category").Query().SaveAsXLSX("1.xlsx", []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"}, 0777)

if err != nil {
    t.Fatal(err)
}
  • SaveAsCSV(filename string, headers []string, perm os.FileMode)

导出CSV文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsTSV(filename string, headers []string, perm os.FileMode)

导出TSV文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsHTML(filename string, headers []string, perm os.FileMode)

导出HTML文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsXML(filename string, headers []string, perm os.FileMode)

导出XML文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsXMLWithTagNamePrefixIndent(tagName string, prifix string, indent string, filename string, headers []string, perm os.FileMode)

导出指定格式化的XML文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsYAML(filename string, headers []string, perm os.FileMode)

导出YAML文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsJSON(filename string, headers []string, perm os.FileMode)

导出JSON文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

  • SaveAsXLSX(filename string, headers []string, perm os.FileMode)

导出XLSX文件,filename为完整路径,headers为每列的列名,需要结果集中有该字段,此处[]string是为了确定列的顺序,perm为文件权限位

多查询集导出到单一文件

样例代码:

_, results, err := engine.Sqls(map[string]string{"category": "select * from category", "category-16-17": "select * from category where id in (16,17)"}).Execute()

if err != nil {
    t.Fatal(err)
}

databook, err := xorm.NewDatabookWithData(
    map[string]string{
        "category":       "category",
        "category-16-17": "category-16-17"},
    results,
    true,
    map[string][]string{
        "category":       []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"},
        "category-16-17": []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"}})

if err != nil {
    t.Fatal(err)
}

err = databook.SaveAsXLSX("c:/2.xlsx", 0777)
if err != nil {
    t.Fatal(err)
}
err = databook.SaveAsHTML("c:/2.html", 0777)
if err != nil {
    t.Fatal(err)
}
err = databook.SaveAsJSON("c:/2.json", 0777)
if err != nil {
    t.Fatal(err)
}
err = databook.SaveAsXML("c:/2.xml", 0777)
if err != nil {
    t.Fatal(err)
}
err = databook.SaveAsYAML("c:/2.yaml", 0777)
if err != nil {
    t.Fatal(err)
}

连接池

engine内部支持连接池接口和对应的函数。

  • 如果需要设置连接池的空闲数大小,可以使用engine.SetMaxIdleConns()来实现。
  • 如果需要设置最大打开连接数,则可以使用engine.SetMaxOpenConns()来实现。

参考资料


欢迎评论区讨论,或指出问题。 如果觉得写的不错,欢迎点赞,转发,收藏。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-09-30 11:59:57  更:2021-09-30 12:01:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:09:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码