Skip to content

Replace方法

Tuuz edited this page Nov 6, 2023 · 10 revisions

本页仅介绍Oracle使用

  • Mysql原本就支持Replace方法并且十分灵活,你只需要按照常规流程操作即可
  • Oracle版本的使用上与Mysql略有出入,为了实现更加灵活的Replace方法,你可以查看下面提供的几个场景的Demo,十分简单易上手

Replace Into (Merge)

原版框架的Replace方法因为Oracle不支持的原因,会导致报错,新版(v1.12.6+)在修复故障的同时,使用Merge方法覆写了Replace,使Oracle数据库也可以和Mysql一样使用ReplaceInto方法

数据库

  • 数据库
    • 名称:aaa
    • 字段:
      • id:NUMBER
      • val:VARCHAR2
      • val2:VARCHAR2

DDL

CREATE TABLE "C##TEST"."aaa" (
	"id" NUMBER NOT NULL ENABLE,
	"val" VARCHAR2 ( 255 ) DEFAULT '',
	"val2" VARCHAR2 ( 255 ),
PRIMARY KEY ( "id" ) USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE ( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT ) TABLESPACE "USERS" ENABLE 
) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE ( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT ) TABLESPACE "USERS"

需求

  • 我希望直接把这个方法当成insert来用,性能差点我不在意:
    • 你要不要看看你自己在说什么?
  • 我希望只检测id,当id=2时,修改val和val2字段的数据,当id=2不存在时插入这一条数据
	tuuz.Db()
	db := tuuz.Db().Table("aaa")
	db.Fields()
	db.Where("id")
	db.Data(map[string]any{
		"id":   "2",
		"val":  "ggg",
		"val2": "sss",
	})
	fmt.Println(db.Replace())
  • 我希望检测id=2是否存在的同时,检测val是否也叫"ggg"如果有就更新val2为"sss"如果没有,就插入这一整条数据
	tuuz.Db()
	db := tuuz.Db().Table("aaa")
	db.Fields()
	db.Where("id")
	db.Where("val")
	db.Data(map[string]any{
		"id":   "2",
		"val":  "ggg",
		"val2": "sss",
	})
	fmt.Println(db.Replace())
  • 我希望全检测,如果三个字段均有重复的就不要插入了,如果没有重复的就插入一条新的数据(当Insert来用)
    • 请注意这个方法不健康,因为没有做主键检测,假设你的主键是id,使用这个方法,id重复了,他就不会成功插入,举个例子:
	tuuz.Db()
	db := tuuz.Db().Table("aaa")
	db.Fields()
	db.Data(map[string]any{
		"id":   "2",
		"val":  "ggg",
		"val2": "sss",
	})
	fmt.Println(db.Replace())
  • 例如id为2的那条数据已经存在了(id是主键),err就会立即报错,你将你会看到Oracle的错误信息:
unique constraint (C##TEST.SYS_C008317) violated
  • 所以在这个情况下,我强烈建议你使用db.Where(你的主键),来避免此类错误的发生,当然如果你需要的就是重复报错并在前端返回,那么也许这么设计刚好可以解决你的问题

设计思考

  • 所以Replace的设计主要就是为了解决你使用中的灵活性问题,让Oracle也可以用着很方便
  • 为什么要用where来承接,为什么不能直接使用db.Where("id",2)这样的方法,不是看起来更方便吗?
    • 因为MySQL也是这么用的,举个例子,默认的Mysql Replace into用法
REPLACE INTO aaa (id, val, val2) VALUES (2, 'ccc', 'fff');
  • 如果我只想根据id来修改其他字段,语句就会变成这样
INSERT INTO aaa (id, val, val2) VALUES (2, 'ccc', 'fff') ON DUPLICATE KEY UPDATE val = 'ccc', val2 = 'fff';
  • 所以在这个基础上,如果不传where,就是上面的用法,传where,就自动变成了下面的模式,当然这只是一个MySQL的Demo用于解释框架是如何更加灵活的解决Oracle中使用Replace的方法

功能评估

  • 环境测试
    • 已经通过测试环境测试
    • 安全性
      • 已使用PrepareStatement来解决注入问题,请不要在Where中输入动态查询参数避免预处理失效(也许来自远程的PostGet参数)
    • 操作使用
      • 因为Oracle的不同,框架已经做了Oracle关键字处理,你无需自己再处理,例如使用NUMBER关键字作为字段时你无需使用db.Where(""NUMBER"")来处理,你可以直接使用db.Where("NUMBER")即可,其他的内容框架已经做过处理了,当然如果吃的很饱也可以自己处理一遍,框架没有反直觉的设计,你觉得这样行,大概率就是行的,不行你可以再ISSUE或直接PR