PostgreSQL 是一种特性非常齐全的自由软件的对象-关系型数据库管理系统(ORDBMS),是以加州大学计算机系开发的 POSTGRES,4.2 版本为基础的对象关系型数据库管理系统。POSTGRES 的许多领先概念只是在比较迟的时候才出现在商业网站数据库中。PostgreSQL 支持大部分的 SQL 标准并且提供了很多其他现代特性,如复杂查询、外键、触发器、视图、事务完整性、多版本并发控制等。同样, PostgreSQL 也可以用许多方法扩展,例如通过增加新的数据类型、函数、操作符、聚集函数、索引方法、过程语言等。另外,因为许可证的灵活,任何人都可以以任何目的免费使用、修改和分发 PostgreSQL。
PostgreSQL 数据库在我们近几年的项目系统中,使用的频率极高。原因很简单:免费、高效、强大!而在 .NET
项目中使用 PostgreSQL 数据库,最常见的大概就是使用 Npgsql
作为驱动。
Npgsql 在 2021 年 11 月9日,发布了全新的 6.0.0 版。从该版本开始 Npgsql 原生支持了多主机负载均衡和故障转移、支持通过 OpenTelemetry
报告跟踪数据、支持新 .NET 的 DateOnly 和 TimeOnly 类型等等。还有一项被很多开发者忽视的改变:出于性能优化的原因,参数名称默认开始区分大小写, 开发人员可以通过代码
AppContext.SetSwitch("Npgsql.EnableLegacyCaseInsensitiveDbParameters", true);
控制 Npgsql 像旧版本一样忽视参数大小写。
其实呢,一些不严谨按大小写区分的方式写的 .NET 程序,在升级后由于默认区分大小写让程序爆出一些异常来,也是程序员们可以接受的。但是如果程序逻辑完全发生变化,甚至是毁灭性影响的话,你可能会欲哭无泪的。
所以 Npgsql 紧急发布了 6.0.2 版本,还原为默认不区分大小写了!
为什么呢?源起有人在 Github 的 Npgsql 官方库中,发布一条 Issue,来说明默认区分大小写带来的一种毁灭性打击。
意思就是,如果一条简单的 SQL 语句如下:
delete from persons where "id"=@id
本意是根据传递的id参数值,删除对应的一行记录。而如果在执行这个语句的时候传的参数名不是小写的 id
,而是写成了Id
。带来的结果却是把 persons 表内的数据全部删除了!!!
roji 在随后的回复中,说明了造成这个问题的是由于如下问题交织在一起后引发的:
- PostgreSQL 数据库本身不支持命名参数,而是使用参数位置代替的,也就是 $1、$2...
- Npgsql 通过重写 SQL 来支持的命名参数,将 @id 转变为 $1
- 如果 Npgsql 在你的参数匹配时找不到对应名字的 NpgsqlParameter , 则它不会翻译这个参数,而是原样输出,也就是 @id
- PostgreSQL 中,标识符可以使用@作为前缀,即数据库会认为这是一个叫 id 的字段,所以 @id 与 id 会等同
上述问题叠合在一起后,原来的 SQL 语句实际变成了:
delete from persons where "id"=id
等同于
delete from persons where 1=1
这问题在业务系统中绝对是毁灭性的。
所以,Npgsql 团队在 6.0.2 版本中修改了默认开关值,使得默认不再区分大小写。
如果你正在使用 Npgsql 6.0.0 或者 6.0.1 版,为了你的职业甚至生命安全,赶紧升级到 6.0.2 吧