zoukankan      html  css  js  c++  java
  • xorm相关操作小结

    前言

    最近写业务用到xorm操作postgreSQL,抽空写了一些平时会用到的常用的操作,好脑筋不如好笔记。

    xorm

    参考文档

    中文文档-方便滤清xorm所有的知识体系

    英文文档-有各种各样的实际操作

    项目地址

    相关技术博客

    Go每日一库之xorm

    上面那个作者的每日一库系列跟Go的相关文章挺不错:Go每日一库Go系列文章

    操作总结

    “初始化引擎操作”

    下面使用的 model.DB.Walk 实际上是在项目启动时就已经启动的引擎,自己做本地测试的话可以在本地做初始化的工作:

    // init string
    const OnlineConn = "postgres://bytepower_rw:xxxxxx@zzzxxx.com.cn:5432/xxx_db_namexxx?sslmode=disable;"
    
    // init db
    model.DB.Walk, err = xorm.NewEngine("postgres", OnlineConn)
    if err != nil {
    	panic("初始化数据库错误:" + err.Error())
    }
    defer model.DB.Walk.Close()
    

    定义结构体

    type StudentTest struct {
    	// TODO 注意xorm的注释暂时只支持MySQL引擎,postgreSQL即使设置了也不生效
    	// 主键 字段名设置为 sid
    	Id string `json:"id" xorm:"varchar(255) pk 'sid' comment('学生ID')"`
    	// TODO 注意如果设置为 "非空且唯一" 的话会自动创建一个索引!但是 Sync2方法会报错,尽量不要设置非空且唯一字段!
    	Name string `json:"name" xorm:"varchar(25) notnull 'name' comment('学生姓名')"`
    	Age  int    `json:"age" xorm:"notnull 'age' comment('学生年龄')"`
    	// 索引字段 TODO 使用orm内置的方法创建索引会失败!需要手动执行SQL语句
    	Score   float64 `json:"score" xorm:"notnull 'score' comment('学生成绩')"`
    	ClassId string  `json:"class_id" xorm:"notnull 'class_id' comment('学生所在班级')"`
    	// 创建时间与修改时间
    	CreatedTime time.Time `json:"created_time" xorm:"created notnull"`
    	UpdatedTime time.Time `json:"updated_time" xorm:"updated notnull"`
    }
    
    func (s *StudentTest) TableName() string {
    	return "student_test"
    }
    
    // 新建一个班级表,用于连表查询的测试
    type SClassTestModel struct {
    	Id   string `json:"id" xorm:"varchar(255) pk 'cid' comment('班级id')"`
    	Name string `json:"name" xorm:"varchar(255) notnull 'name' comment('班级名称')"`
    }
    
    func (sc *SClassTestModel) TableName() string {
    	return "sclass_test"
    }
    

    创建表

    // 创建班级表
    func TestCreateClassTable(t *testing.T) {
    	err := test.Session.Sync2(aaa_module.SClassTestModel{})
    	require.Equal(t, nil, err)
    }
    
    // 创建学生表
    func TestCreateTable(t *testing.T) {
    	// 创建学生表
    	// TODO 使用 Sync2 方法可以在修改model结构体后直接修改表字段,建议使用这个方法
    	err := test.Session.Sync2(aaa_module.StudentTest{})
    	require.Equal(t, nil, err)
    }
    

    “批量插入数据”

    // 批量插入数据
    func InsertStudentSlice(studentSlice []*StudentTest) (int64, error) {
    	affected, err := model.DB.Walk.Table("student_test").Insert(studentSlice)
    	if err != nil {
    		return affected, errors.New("insert student slice raise error!" + err.Error())
    	}
    	return affected, nil
    }
    
    // 具体实现
    // 批量插入多条数据
    func TestInsertStudentSlice(t *testing.T) {
    	stu1 := aaa_module.StudentTest{Id: "1", Name: "whw1", Age: 12, Score: 99, ClassId: "223"}
    	stu2 := aaa_module.StudentTest{Id: "2", Name: "whw2", Age: 13, Score: 98, ClassId: "222"}
    	stu3 := aaa_module.StudentTest{Id: "3", Name: "whw3", Age: 14, Score: 97, ClassId: "221"}
    	stu4 := aaa_module.StudentTest{Id: "4", Name: "whw4", Age: 15, Score: 96, ClassId: "222"}
    	stu5 := aaa_module.StudentTest{Id: "5", Name: "whw5", Age: 16, Score: 95, ClassId: "221"}
    
    	stuSlice := []*aaa_module.StudentTest{&stu1, &stu2, &stu3, &stu4, &stu5}
    
    	// 创建
    	if affected, err := aaa_module.InsertStudentSlice(stuSlice); err != nil {
    		fmt.Println("affected: ", affected)
    		fmt.Println("err: ", err)
    	} else {
    		fmt.Println("写入成功!affected: ", affected)
    	}
    }
    

    “插入单条数据”

    // 插入单条数据
    func InsertStudentObj(stuObj *StudentTest) (int64, error) {
    	if ok, err := model.DB.Walk.Table("student_test").Insert(stuObj); err != nil {
    		return ok, err
    	} else {
    		return ok, nil
    	}
    }
    
    // 具体实现
    func TestInsertStuObj(t *testing.T) {
    	stuObj := aaa_module.StudentTest{Id: "6", Name: "naruto", Age: 22, Score: 99, ClassId: "231"}
    	if ok, err := aaa_module.InsertStudentObj(&stuObj); err != nil {
    		fmt.Println("insert stuObj raise error! ", err.Error())
    	} else {
    		fmt.Println("insert stuObj successfully! ok: ", ok)
    	}
    }
    

    查询符合条件的记录的数量

    func GetCount(session *xorm.Session, query interface{}, args ...interface{}) (count int64, err error) {
    	return session.Where(query, args...).Count(&WithdrawRecordModel{})
    }
    
    // 具体使用
    cashId := "123"
    userId := "2"
    query := "cash_id = ? and user_id = ?"
    cashCount, err := GetCount(session, query, cashId, userId)
    

    判读记录是否存在

    // 判断记录是否存在
    func ExistStu(stu *StudentTest) (bool, error) {
    	has, err := model.DB.Walk.Table("student_test").Exist(stu)
    	return has, err
    }
    
    // 具体实现
    // 判断记录是否存在 —— 效率更高
    func TestExistStuObj(t *testing.T) {
    	stuObj := aaa_module.StudentTest{Name: "naruto"}
    	has, err := aaa_module.ExistStu(&stuObj)
    	if err != nil {
    		fmt.Println("err: ", err.Error())
    	} else if !has {
    		fmt.Println("不存在这条记录!")
    	} else {
    		fmt.Println("存在这条记录!")
    	}
    }
    

    用主键ID最效率的查询

    // 通过id查找学生对象 高效的查询方式!
    func GetStudentById(sid string) (*StudentTest, bool, error) {
    	stuObj := StudentTest{}
    	// 使用这种查询效率高
    	// TODO 注意这里需要将地址传进去
    	has, err := model.DB.Walk.Table("student_test").Id(sid).Get(&stuObj)
    
    	// TODO 也可以指定返回的字段
    	// has, err := model.DB.Walk.Table("student_test").Id(sid).Cols("sid", "name", "score")
    
    	return &stuObj, has, err
    }
    
    // 具体实现
    // 根据主键id查询单条数据 TODO 效率高的方式
    func TestGetStudentById(t *testing.T) {
    	sid := "2"
    	stuObj, has, err := aaa_module.GetStudentById(sid)
    	if err != nil {
    		fmt.Println("get student by i·d raise error! ", err.Error())
    	} else {
    		if !has {
    			fmt.Println("can't get stuObj by that sid!")
    		} else {
    			fmt.Println(fmt.Sprintf("get the stuObj: sid: %s, Name: %s, Age: %d, Score: %.3f, ClassId %s ", stuObj.Id, stuObj.Name, stuObj.Age, stuObj.Score, stuObj.ClassId))
    		}
    	}
    }
    

    根据条件查询单条数据

    // 根据条件查询单条数据, 接收一个StudentTest结构体指针作为条件
    func GetStuObj(stu *StudentTest) (*StudentTest, bool, error) {
    	has, err := model.DB.Walk.Table("student_test").Get(stu)
    	return stu, has, err
    }
    
    // 具体实现
    // 根据不同的条件查询单条数据
    // TODO: 这种方式很强大,不需要构建繁杂的查询,有的话直接将结果存入 "条件结构体即可"
    func TestGetStudent(t *testing.T) {
    	stu := &aaa_module.StudentTest{Name: "naruto"}
    
    	stu, has, err := aaa_module.GetStuObj(stu)
    	// 判断有没有出错
    	if err != nil {
    		fmt.Println("get student raises error! ", err.Error())
    		// 判断有没有查到数据
    	} else if !has {
    		fmt.Println("can't get stuObj!")
    		// 拿到结果的话直接将结果放在定义好的结构体中
    	} else {
    		fmt.Println("stuObj: ", stu.Id, stu.Name, stu.Score)
    	}
    }
    

    返回所有符合条件的记录

    // 返回所有符合条件的记录 ———— 条件是固定死的
    func FindSlice() ([]StudentTest, error) {
    	stuObjSlice := make([]StudentTest, 1)
    	err := model.DB.Walk.Table("student_test").Where("age > ? and score < ?", 10, 100).Find(&stuObjSlice)
    	return stuObjSlice, err
    }
    
    // 具体实现
    // 返回所有符合条件的记录 ———— 条件是固定死的
    func TestFind(t *testing.T) {
    	stuObjSlice, err := aaa_module.FindSlice()
    	if err != nil {
    		fmt.Println("err>>> ", err)
    	} else {
    		fmt.Println("stuObjSlice: ", stuObjSlice)
    	}
    }
    

    * 自定义条件查询所有记录

    // 返回所有符合条件的记录 —— 自定义条件查询
    // 接收一个 map[string]interface{}  key是查询的字段,value是查询的值
    func FindSliceBySelfCondition(queryMap map[string]interface{}) ([]*StudentTest, error) {
    	var retSlice []*StudentTest
    	// ****** 其实本质上就是一个map[string]interface{} ******
    	err := model.DB.Walk.Table("student_test").Where(queryMap).Find(&retSlice)
    	return retSlice, err
    }
    
    // 具体实现
    // 返回所有符合条件的记录 —— 自定义条件查询
    func TestFindSliceBySelfCondition(t *testing.T){
    
    	// ****** 构建查询条件查询的条件 ******
    	queryMap := map[string]interface{}{
    		"name": "naruto",
    		"age": 22,
    	}
    
    	retSlice, err := aaa_module.FindSliceBySelfCondition(queryMap)
    	if err != nil{
    		fmt.Println("err: ", err)
    	}else{
    		fmt.Println("retSlice: ", retSlice)
    		// 遍历结果
    		for _, obj := range retSlice{
    			fmt.Println("obj: ", obj)
    		}
    	}
    }
    

    连表查询+执行原生SQL

    func JoinQuery() error {
    	// 连表查询语句
    	sqlStr := "select t1.sid as stu_id, t1.name as stu_name,t1.age as stu_age, t1.score as stu_score, t2.name as class_name, t2.cid as class_id " +
    		"from student_test as t1 " +
    		"left join s_class_test_model as t2 " +
    		"on t1.class_id = t2.cid"
    
    	// 1、QueryInterface TODO: 左表中有但右表中没有的会显示nil ———— 推荐这种方式
    	rets, err := model.DB.Walk.Table("student_test").QueryInterface(sqlStr)
    	fmt.Println("QueryInterface: ret: ", rets)
    	for _, mp := range rets {
    		fmt.Println("mp: ", mp["class_id"], mp["class_name"], mp["stu_name"])
    	}
    
    	// 2、QueryString TODO 左表中有但右表中没有的不会显示
    	results, err := model.DB.Walk.Table("student_test").QueryString(sqlStr)
    	fmt.Println("QueryString ret: ", results)
    	for _, mp := range results {
    		fmt.Println("mp: ", mp["class_id"], mp["class_name"], mp["stu_name"])
    	}
    
    	return err
    }
    
    // 具体实现
    // 连表查询 TODO 执行原生SQL的方式!
    func TestJoinQuery(t *testing.T){
    	err := aaa_module.JoinQuery()
    	if err != nil{
    		fmt.Println("err: ", err)
    	}else{
    		fmt.Println("join Query successfully")
    	}
    }
    

    更新记录

    // 更新记录
    /*
    	更新通过engine.Update()实现,可以传入结构指针或map[string]interface{}。对于传入结构体指针的情况,xorm只会更新非空的字段。
    	如果一定要更新空字段,需要使用Cols()方法显示指定更新的列。使用Cols()方法指定列后,即使字段为空也会更新
    */
    func UpdateData() (int64, error){
    
    	affected, err := model.DB.Walk.Table("student_test").Where("name=?", "naruto").Update(&StudentTest{Score: 123})
    
    	// 或者
    	// affected, err := model.DB.Walk.Table("student_test").ID("2").Update(&StudentTest{Score: 666})
    
    	return affected, err
    }
    
    // 具体实现
    func TestUpdate(t *testing.T){
    
    	affected, err := aaa_module.UpdateData()
    	if err != nil{
    		fmt.Println("err: ", err)
    	}else{
    		fmt.Println("修改成功!affected: ", affected)
    	}
    }
    

    删除记录

    // 删除记录
    func DeleteData() (int64, error){
    	affected, err := model.DB.Walk.Table("student_test").Where("name=?", "sasuke").Delete(&StudentTest{})
    	return affected, err
    }
    
  • 相关阅读:
    Linux中查找当前目录下占用空间最大的前10个文件
    Redis的优势和特点
    java中final,finally,finalize三个关键字的区别
    消息队列介绍
    Redis的应用场景
    Spring中@Autowired注解与@Resource注解的区别
    多版本并发控制(MVCC)
    Linux查看CPU和内存使用情况
    进程调度算法
    一致性Hash算法
  • 原文地址:https://www.cnblogs.com/paulwhw/p/14471286.html
Copyright © 2011-2022 走看看