0

尝试为 am Oracle 表中的数据行生成唯一校验和,用于确保在检索它们并尝试同时更新它们的两个用户之间不会更改该行。

 SELECT ora_hash( KY_REFUND_ID CD_STATUS || KY_CHECK_NUM || 
        COMMENT || CREATED_BY || TS_CREATED || TX_UPDATED_BY || TS_UPDATED) as checksum
 INTO p_checksum
 FROM REFUND_CHECKS r
 WHERE ROWID = p_rowid;

奇怪的是,如果在调试时在 sqldeveloper 中调用该过程,而不是通过网站调用它,我们会得到不同的校验和。当内部再次计算校验和以与我的值进行比较时,这成为一个问题 - 我得到 12345,但内部相同的数据导致 78904,因此系统说它们不匹配。

据我所知,两个不同的用户在查看相同数据时获得不同校验和的唯一方法......他们没有查看相同的数据。我怀疑这两个电话之间有一些看不见的“东西”。我能看到的唯一不同的是正在使用的帐户。

在 sqldeveloper 中,调用是使用模式名称进行的,但网站调用的是 dotnet_user。

无论如何,在确定校验和时,帐户名称是否用作数学中的一些额外值?如果不是,可能存在哪些其他看不见的差异可能导致不同的结果,更重要的是,如何将它们标准化,以便双方得到相同的结果?

4

1 回答 1

2

问题是您依赖于隐式转换。您通过将多个值连接在一起来生成一个字符串,这意味着时间戳(可能来自名称)列正在使用会话的 NLS 设置隐式转换为字符串。您在 SQL Developer 中和通过您的 Web 客户端有不同的 NLS 设置。

作为一个简单的演示:

alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS';

select ora_hash(timestamp '2018-01-01 00:00:00') as ts_hash,
       'abc' || timestamp '2018-01-01 00:00:00' as str,
       ora_hash('abc' || timestamp '2018-01-01 00:00:00') as str_hash
from dual;

   TS_HASH STR                      STR_HASH
---------- ---------------------- ----------
1986439397 abc2018-01-01 00:00:00  588765268

alter session set nls_timestamp_format = 'DD-Mon-YYYY HH:MI:SS AM';

select ora_hash(timestamp '2018-01-01 00:00:00') as ts_hash,
       'abc' || timestamp '2018-01-01 00:00:00' as str,
       ora_hash('abc' || timestamp '2018-01-01 00:00:00') as str_hash
from dual;

   TS_HASH STR                          STR_HASH
---------- -------------------------- ----------
1986439397 abc01-Jan-2018 12:00:00 AM 2809284723

相同的时间戳值,以及时间戳本身在其本机数据类型中的相同哈希值;但是对字符串的不同隐式转换,以及这些字符串的不同哈希值。

更改您的代码以将时间戳显式转换为特定的固定格式,它将不再依赖 NLS,因此将变得一致,例如

 SELECT ora_hash( KY_REFUND_ID CD_STATUS || KY_CHECK_NUM || 
          COMMENT || CREATED_BY ||
          to_char(TS_CREATED, 'SYYYYMMDDHH24MISSFF9') || TX_UPDATED_BY ||
          to_char(TS_UPDATED, 'SYYYYMMDDHH24MISSFF9')) as checksum
 INTO p_checksum
 FROM REFUND_CHECKS r
 WHERE ROWID = p_rowid;
于 2018-10-26T13:44:29.407 回答