Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

借阅双链相关代码重构 #1183

Open
DigitalPlatform opened this issue Jan 31, 2024 · 7 comments
Open

借阅双链相关代码重构 #1183

DigitalPlatform opened this issue Jan 31, 2024 · 7 comments

Comments

@DigitalPlatform
Copy link
Owner

一直以来 dp2library 中的借阅双链都是使用的读者证条码号和册条码号。由于允许存在没有册条码号的册记录,为了允许这部分册进行借还,双链中也允许用 @refID:xxx 形态使用册记录的参考 ID。但不允许没有证条码号的读者记录。

这样的缺点是,当读者记录修改了证条码号字段内容以后,或者册记录修改了册条码号字段内容以后,双链的关系就被破坏。若修改的同时要自动去修改双链中的连接字段内容,则寻找双链的连接字段的过程会比较复杂,难以实现。

现计划对双链进行改造,全面允许使用读者记录和册记录的参考 ID。并兼容以前的证条码号和册条码号用法。这样等系统运行一段时间以后,读者以前借阅的图书都被还回了,新产生的借阅信息链可以确保都是新的参考 ID 形态,这样等读者记录和册记录修改条码号字段以后,双链依然可以保持正确。

本 issue 将记载代码重构中涉及到的数据格式变动,给出测试建议。

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Jan 31, 2024

读者记录

改进点:

  1. borrows/borrow 元素中,增加了一个 refID 属性,值为册记录的参考 ID。原有的 barcode 属性依然有效,是册条码号
  2. reservations/request 元素的 arrivedItemBarcode 属性,内容可能是册条码号,现在也可能是 @refID:xxx 形态
  3. reservations/request 元素的 items 属性,内容可能是册条码号列表,现在也可能是 @refID:xxx 形态的列表
  4. outofReservations/request 元素的 itemBarcode 属性,内容原来是册条码号,现在还可能是 @refID:xxx 形态
  5. overdues/overdue 元素中,增加了一个 refID 属性,值为册记录的参考 ID。原有的 barcode 属性依然有效,是册条码号

册记录

改进点:

  1. borrower 元素的内容,目前改为写入 @refID:xxxx 形态。以前的 证条码号形态 依然有效,注意使用的时候对两种可能性加以判断
  2. Reservation() API 中,预约时对册记录的 reservations/request/@reader 属性中写入的可能是证条码号或 @refID:xxx 形态

预约队列记录

改进点:

  1. 增加了一个 patronRefID 元素,内容为读者记录的参考 ID。原有 readerBarcode 元素依然有效
    (注: 其实 2016 年开始预约队列库的 keys 配置文件里面就为 patronRefID 元素添加了一个检索点,只是当时的程序代码里面还没有给预约队列记录主动写入这个元素)

违约金记录

改进点:

  1. 增加 itemRefID 元素,内容为超期册的参考 ID。
  2. 增加 readerRefID 元素,内容为读者参考 ID。
  3. 违约金库 keys 模板里面为上述两个元素增加了检索点,名为“册参考ID”和“读者参考ID”。

出纳日志记录(mongodb)

改进点:

  1. ItemBarcode 字段原来是存储册条码号。现在改为 @refID:xxx 形态。升级版本的时候,有个模块会自动把以前记录的全部此字段内容替换为新的形态。
  2. PatronBarcode 字段原来是存储读者证条码号。现在改为 @refid:xxx 形态。升级版本的时候,有个模块会自动把以前记录的全部此字段内容替换为新的形态。

2024/5/22 发现写入mongodb的borrow的BorrowDate是一个默认值,说明如下:
这个 BorrowDate 字段的语义是“还书的时候,回顾当时借书的时间”,也就是说这个字段对借书动作不管用(属于多余的字段),对还书动作才管用。借书动作要看借书时间,要看 OperTime 字段。(类似道理,还书动作要看还书时间,看 OperTime 字段。也就是说,并没有一个 ReturnDate 字段)
出现多余的字段,这是由数据行要整齐地放入同一个数据记录类引起的。假设如果不同动作的行放入不同的数据记录类,就不会有这个问题,比如负责定义借书动作的类就根本不提供这个 BorrowDate 字段就可以了。不过,这面这种假设的做法,成本太高一般不会考虑使用。

{
  "_id": {
    "$oid": "664d5385562b1ade073690cd"
  },
  "LibraryCode": "",
  "Operation": "borrow",
  "Action": "borrow",
  "ItemBarcode": "@refID:94623e97-65e2-470e-b55e-160f0ce178a4",
  "PatronBarcode": "@refID:9131f365-772d-4ce1-b6ae-334380d41a21",
  "BiblioRecPath": null,
  "Period": "31day",
  "No": "0",
  "Volume": null,
  "ClientAddress": "localhost",
  "Operator": "supervisor",
  "OperTime": {
    "$date": "2024-05-22T02:08:05.000Z"
  },
  "BorrowDate": {
    "$date": {
      "$numberLong": "-62135596800000"
    }
  }
}

Borrow() API 操作日志记录

Return() API 操作日志记录

改进点:

  1. 增加一个 readerRefID 元素,内容为读者记录的参考 ID。
  2. 增加了一个 itemRefID 元素,内容为册记录的参考 ID。

Reservation() API 操作日志记录

改进点:

  1. 增加了一个 itemRefIdList 元素。原有 itemBarcodeList 元素依然有效
  2. 增加了一个 readerRefID 元素。原有 readerBarcode 元素依然有效

Amerce() API 操作日志记录

改进点:

  1. 增加了一个 readerRefID 元素。原有 readerBarcode 元素依然有效

WriteRes() API 操作日志记录

改进点:

  1. 增加了一个 record 元素和一个 oldRecord 元素(和其它类型的日志记录中的 record 和 oldRecord 元素用法相同)。分别表示新旧文本 XML 记录。适用于文本记录。如果使用了这两个元素,日志记录就不会有附件了。

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Jan 31, 2024

Borrow() API

改进点:

  1. 返回的 BorrowInfo 结构中,strItemBarcode 字段的内容可能是册条码号,现在也可能是 @refID:xxx 形态
    注意验证内务等前端的适应性

Return() API

改进点:

  1. 返回的 ReturnInfo 结构中,ItemBarcode 字段的内容可能是册条码号,现在也可能是 @refID:xxx 形态
    注意验证内务等前端的适应性

VerifyBarcode() API

改进点:

  1. strBarcode 参数现在允许 @refID:xxx 形态的内容请求校验。会对所有读者库的参考 ID 检索途径进行试探检索,判断出参考 ID 到底是读者参考 ID 还是册参考 ID

2024/5/22 用接口测试符合预期。

SearchCharging() API

改进点:

  1. patronBarcode 参数允许的内容形态,增加了 @readerRefID:xxx(或者别名 @refID:xxx) 形态,表示读者参考 ID。
    注:总共可以使用以下几种类型的值:
    a) 如果没有前缀,表示读者证条码号;
    b) 如果 以 "@itemBarcode:" 前缀引导,表示这是册条码号;
    c) 如果 以 "@itemRefID:" 前缀引导,表示这是册参考 ID;
    d) 如果 以 "@readerRefID:" 或 "@refID:" 前缀引导,表示这是读者参考 ID。
  2. patronBarcode 参数内容如果是读者证条码号或者册条码号,实际上在执行检索之前,程序会自动替换为读者参考 ID 或者册参考 ID,以便适应 mongodb 借阅历史库的升级变化。

2024/5/22 在接口用partronBarcode参数用4种形状测试均符合预期。但如果action参数为空时,会报异常(todo)

@DigitalPlatform
Copy link
Owner Author

根据操作日志记录重建 mongodb 出纳动作库

这个批处理任务的算法有改进。

原先是处理操作日志记录 borrow 和 return 动作。现在还要处理 setReaderInfo 和 setEntity 动作。

处理 borrow 和 return 动作

新算法要从日志记录中的读者和册记录中尽量提取参考 ID(以@refID:xxx形态),用于创建 mongodb 出纳动作记录。找不到参考 ID 的情况下再用条码号创建。

处理 setReaderInfo 和 setEntity 动作

除了原来算法应该具备的功能,修改和删除 mongodb 动作记录中匹配的两类条码号以外,新算法还要

  1. 关注参考 ID 字段发生的改变。对 mongodb 动作记录相关字段进行查找替换。
  2. 关注 mongodb 动作记录中可能存在的条码号形态的相关字段内容,用从日志记录中抽取出的“条码号 -- 参考 ID”对照关系去进行查找替换,以便 mongodb 动作记录符合新版本要求。

查找替换批处理

曾设想过在新旧版本日志动作切换的时刻,执行一次批处理查找替换 mongodb 中的两类条码号。现在看来没有必要了,因为 处理 setReaderInfo 和 setEntity 动作的时候已经分散解决了这个问题。

@DigitalPlatform
Copy link
Owner Author

SetReaderInfo() API 的一些改进

change 动作

权限检查: 当前账户是否具备修改 barcode 元素的权限。比如,账户权限中包含 setreaderinfo,或者包含 setreaderinfo:barcode,就表示可以修改证条码号字段。

如果读者记录中具有在借信息(borrow 元素),change 动作依然可以自动处理好相关册记录的 borrower 元素联动修改。(旧版本在这种情况下会直接报错拒绝,并返回出错信息建议前端改用 changereaderbarcode 动作)

字段限制: 如果数据库中已经存在的读者记录中 refID 元素为空,则允许修改 refID 元素内容为任意值。但如果已经存在的读者记录中 refID 元素不为空,则不允许修改 refID 元素内容。如果试图修改,SetReaderInfo() API 会返回 result.Value 值 1,表示部分元素的修改被拒绝。(而改用 changereaderrefid 动作可以修改 refID 元素值,包括已经存在的记录中 refID 元素值不为空的情形。changereaderrefid 动作是最新版新增的动作)

此动作不允许修改 foregift 字段。

此动作不允许修改 hire 元素的 expireDate 属性值。也就是说,hire 元素的文本可以修改,但无法改变已经存在的 expreDate 属性值。

changereaderbarcode 动作

权限检查: 当前账户具备修改 barcode 元素的权限,或者具备 changereaderbarcode 权限。(可以理解为 changereaderbarcode 权限提升了当前账户的修改读者记录字段的能力)

如果读者记录中具有在借信息(borrow 元素),change 动作依然可以自动处理好相关册记录的 borrower 元素联动修改。这一点旧版本已经做到了。

字段限制: 此动作的旧版本似乎可以修改 barcode 以外的一些字段。最新版改变了这一行为,改为,只允许修改 barcode 和 comment 字段。

changestate 动作

权限检查: 当前账户具备修改 state 元素的权限,或者具备 changereaderstate 权限。(可以理解为 changereaderstate 权限提升了当前账户的修改读者记录字段的能力)

字段限制: 只允许修改 state 和 comment 字段。

changeforegift 动作

权限检查: 当前账户具备修改 foregift 元素的权限,或者具备 changereaderforegift 权限。(可以理解为 changereaderforegift 权限提升了当前账户的修改读者记录字段的能力)

字段限制: 只允许修改 foregift 和 comment 字段。

changereaderrefid 动作

权限检查: 当前账户具备修改 refID 元素的权限,或者具备 changereaderrefid 权限。(可以理解为 changereaderrefid 权限提升了当前账户的修改读者记录字段的能力)

如果读者记录中具有在借信息(borrow 元素),changereaderrefid 动作依然可以自动处理好相关册记录的 borrower 元素联动修改。(注: 最新版的册记录中 borrower 元素值为 @refID:xxx 形态。但旧版本的册记录中 borrower 元素值为证条码号,此时如果相关读者记录的证条码号或参考 ID 字段发生修改,就有必要自动修改册记录中的 borrower 元素值)

字段限制: 只允许修改 refID 和 comment 字段。

自动修改册记录中 borrower 元素过程出错处理

在自动修改册记录中 borrower 元素的过程中如果出错,最新版会返回 result.Value 值 1,表示成功但部分修改没有兑现。同时会把错误情况写入错误日志中年。(旧版本这种情况 API 会返回报错,并且读者记录已经被修改了,但没有写入操作日志,处在一种尴尬的状态)

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Apr 12, 2024

RepairBorrowInfo() API

从读者一侧修复

API 参数说明:
strReaderKey 参数指明了要修复的读者记录。
strItemKey 参数指明了读者记录中,哪一个 borrow 元素需要被修复。因为读者记录中的 borrow 元素可能不止一个,如果不用 strItemKey 参数指明,函数就无法完成功能。(这里有个值得未来改进的点,就是可以尝试允许 strItemKey 参数为空,此时默认指明读者记录中唯一的 borrow 元素参与修复)

建议的测试场景如下:

  1. 读者记录中 borrow 元素指向册记录,册记录中的 borrower 元素指向读者记录,双链完整。期待的返回值是 result.Value 为 -1,result.ErrorCode 为 ErrorCode.NoError,result.ErrorInfo 中提示这是完整的链条、没有必要修复。

  2. 读者记录中的 borrow 元素指向册记录,但册记录中的 borrower 元素指向另一读者记录。期待的返回值是 result.Value 为 0。读者记录中的 borrow 元素被清除,册记录中的 borrower 元素和相关元素被清除。

  3. 读者记录中的 borrow 元素指向册记录,但册记录中的 borrower 元素为空。期待的返回值是 result.Value 为 0。读者记录中的 borrow 元素被清除。

  4. 读者记录中的 borrow 元素指向一条不存在的册记录。但 strItemKey 参数代表的册记录存在,册记录中的 borrower 元素指向读者记录,或者指向另外一条读者记录。

期待的返回值是 result.Value 为 -1,result.ErrorInfo 中提示请求参数不正确“读者记录中并不存在有关册记录的 xxx 的借阅信息”。

从册一侧修复

API 参数说明:
strReaderKey 参数指明了册记录相关的读者记录。
(注1:目前 API 要求 strReaderKey 参数值不为空,好像是“考验”一下前端,看看前端是否能正确给出相关读者 Key。实际上,在前端请求之前,往往只知道册记录,并且从册记录中的 borrower 元素中获得了读者 key,用于请求的 strReaderKey 参数。这种情况下,确实除了考验一下前端以外,并无其它意义)
(注2: 和读者一侧相比,读者记录中有多个 borrow 元素的情况,而册一侧的册记录中,只有一个 borrower 元素,所以也不存在需要用 strReaderKey 来从多个 borrower 元素中定位一个元素的理由)
strItemKey 参数指明了册记录。
(这里有个值得未来改进的点,就是可以尝试允许 strReaderKey 参数为空,此时可以通过册记录中的 borrower 元素得知相关的读者记录的 key)

建议的测试场景如下:

  1. 册记录中 borrower 元素指向读者记录,读者记录中 borrow 元素指向册记录,双链完整。期待的返回值是 result.Value 为 -1,result.ErrorCode 为 ErrorCode.NoError,result.ErrorInfo 中提示这是完整的链条、没有必要修复。

  2. 册记录中 borrower 元素指向读者记录,但读者记录中的 borrow 元素指向另一册记录。期待的返回值是 result.Value 为 0。读者记录中的 borrow 元素因为不相干不应被清除,册记录中的 borrower 元素和相关元素被清除。

  3. 册记录中的 borrower 元素指向读者记录,但读者记录中并没有和此册相关的 borrow 元素。期待的返回值是 result.Value 为 0。读者记录中的 borrow 元素因为不相干不应被清除,册记录中的 borrower 元素和相关元素被清除。

  4. 册记录中的 borrower 元素指向一条不存在的读者记录。但 strReaderKey 参数代表的读者记录存在,读者记录中的 borrow 元素指向册记录,或者指向另外一条册记录。

期待的返回值是 result.Value 为 -1,result.ErrorInfo 中提示请求参数不正确“册记录中的 borrower 并未指向指定的读者 xxx”。

读者记录中 borrow 元素中 barcode 和 refID 属性值不一致的情况

当出现 borrow 元素中 barcode 和 refID 属性值指向的不是同一条册记录的情况,优先依据 refID 属性。

如果 borrow 元素缺乏 refID 属性,只有 barcode 属性,那就不会出现不一致的情况,这时候依据 barcode 属性。

对于 RepairBorrowInfo() API 和 Borrow() Return() API 里面的判断都是采用这种策略。

操作日志

readerRecord 和 itemRecord 元素特点

从读者一侧修复的时候:

recordRecord 元素必然会有文本内容(代表读者记录 XML),也会有 recPath 属性值。也就是说读者记录一定是存在的。

itemRecord 元素一定会存在,也会有 recPath 属性值。元素文本值可能会表示没有修改以前的册记录 XML,也可能会表示修改后的册记录 XML,这要看 changed 属性,如果 changed 属性值为 'false',则表示册记录在操作中没有被修改过(缺省为修改过)。也就是说册记录一定是存在的。如果册记录不存在,API 会报错,那样就不会创建操作日志记录了。

从册一侧修复的时候:

recordRecord 元素一定会存在,但文本内容(代表读者记录 XML)可能为空。recPath 属性值也可能为空。changed 属性值恒为 'false'。existing 属性值可能为 'false',这时候元素文本内容也会为空。也就是说读者记录可能存在,也可能不存在。

itemRecord 元素一定会存在,也会有 recPath 属性值。元素文本值表示修改后的册记录 XML。changed 属性不存在,代表册记录在操作中一定会被修改。也就是说册记录一定是存在的。如果册记录不存在,API 会报错,那样就不会创建操作日志记录了。

@renyh
Copy link
Collaborator

renyh commented May 20, 2024

记录中的operation算法更新

用途

读者/书目/册(及订购/期/评注)记录中的operations/operation元素,用于记录这条记录是谁创建的,该修改过,还可用于统计工作量,参于编辑的每个人做的都要留下痕迹。

以前版本效果

1)之前版本读者没有operation元素。书目 和 册(订购/期刊/评注)有。
2)首次创建会有一个create类型的operation,位于第一个且只有一个
3)书目以后每次修改会产生一个新的change,不区分人,但不是无限多,当超过10个会把前面的顶出去,导致分布不均匀,一个人可能修改多次。
4)册以后每次修改是只有一个lastModified元素,也不区分人。

新版本算法

1)为读者增加了operation,包括create和change两种。
2)create原理不变,还是针对初始创建产生,位于第一个且只有一个。
3)针对change改为:对于某一个人无论多少次修改,对这个人只产生一个change/lastModified(册/订购/期/评注对这个名称因为已经建了检索点,还继续用lastModified。书目和读者都叫change),这个人多次修改,只会更新他自己这一个operation=change的时间time。
4)这些operation元素是按时间排序的,如果之前修改过的人,又进行了修改,会将该用户的operation移动最后。因为检索点是按xpath配的,xpath有局限,取最后一个元素方便。
5)operation数量超过10个,会顶出排前面的change,但不会顶出第一个create。
(注:由这一点想到在实际应用中,要看看参与编辑的会有多少人,如果超过10个,要能特殊配置。)

测试要点

1)创建人与时间
2)一个人多次修改,应只有一条change(或lastModified)
3)不同的人修改,更新对应人的change(或lastModified),且这个operation会移到最后。
4)用超过10个帐户测试,第11个operation,会顶出排在最前面的change(或lastModified),注不会顶出create。
5)针对上面的4点,分别针对 读者、书、册、订购/期/评注 分别进行测试。

测试结果
2024/5/20-1102 针对 读者 测试1-4要点,符合预期。
2024/5/20-1114 针对 书目 测试1-4要点,符合预期。
2024/5/20-1119 针对 册 测试1-4要点,符合预期。
2024/5/20-1130 针对 订购/期 测试1-4要点,符合预期。

2024/5/20-1143 针对 评注 测试1-4要点,符合预期。注:创建者可以修改自己创建的记录,其它人需要具有managecomment权限才能修改他人的记录。

SetItemInfo()
Value:-1
ErrorCode:AccessDenied
ErrorInfo:不允许当前用户 'a1' 修改由其他用户 'supervisor' 创建的评注记录

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented May 25, 2024

修改数据记录相关 API 改进

这次也顺便对几个负责修改数据记录的 API 进行了改进。SetBiblioInfo() SetReaderInfo() SetEntities() SetOrders() SetIssues() SetComments()。

new 和 change 两种动作之间的异同

早期为修改记录类的 API 都提供了一个 strAction 参数和一个 strRecPath 参数,分别指定要进行的操作,和要修改的记录的路径。

最早的设想场景如下:当 strAction 值为 "new" 时,strRecPath 值为类似“中文图书/?” 这样的表示追加的记录路径;当 strAction 值为 "change" 时,strRecPath 值为类似 "中文图书/100" 这样的表示确定位置的记录路径。

后来随着不断应用实践,逐渐扩展了应用场景,当 strAction 值为 "new" 时,也可能在 strRecPath 值中表达确定位置的记录路径,表示“这是向一个确定位置创建新记录的操作,前端能确保这个位置现在并不存在记录”;和当 strAction 值为 "change" 时,也可能在 strRecPath 值中表达追加的记录路径(不确定位置),表示“这是向一个不确定位置追加新记录的操作,前端能确保这个位置现在并不存在记录,实际上这个位置是服务器临时来决定”。

后面这种用法主要是因为前端利用 API 编程的时候,不想专门去请求检测一下某个位置是否已经存在记录、然后决定用 strAction 的 "new" 还是 "change",而是希望服务器在执行修改 API 的时候灵活处理。这样可以减少一次查询请求。那么从语义上来说,有一种强烈倾向,就是不再区分 "new" 和 "change" 动作,或者说中立一点统一叫"set" 更好。

但这次重构代码,经过深入测试和研讨以后,发现原教旨主义的 "new" 和 "change" 还是有重要区别的,不能简单混为一谈。首先,记录被创建或者修改以后,operations 元素下要添加或者覆盖适当类型的 operation 元素。到底是当作创建还是修改?另外,操作日志中记载的动作,到底是当作创建还是修改?

经过思考,最后决定,operations 元素下添加或者覆盖 operation 元素的操作类型问题,要看修改的记录这个位置,修改以前是否存在原来的记录。如果存在,表明发生了某种覆盖,那就是 change(modify) 动作;如果不存在,表明属于新创建,那就是 create 动作。也就是说,和请求中 strAction 参数值无关。

操作日志中记载的动作,则可以沿用请求中 strAction 参数值。但需要全面检查一下,看看操作日志记录是否到达一种要求:和动作无关,操作日志记录准确记载了被修改位置,修改前的记录内容,和修改后的记录内容,就可以了。

有一个例外情况,就是当请求的 strStyle 参数中含有 "force" 子参数的时候,无论 strAction 参数值为 "new" 还是 "change",都不会使用记录所在位置原来的记录中的 operations/operation 元素,而是要用请求传来的新记录内容。也就是说,可以把这种情况理解为一个超级用户,具备覆盖记录中所有字段的权力,为了从备份数据中恢复记录到数据库中,是把数据记录完全覆盖到指定的位置,等于把原来存在的记录内容彻底冲走了,或者理解为先彻底删除了原记录,然后写入新记录内容。

那 "force" 情况下写入的记录中是否要在 operations 元素下记载这次写入操作的时间呢?一种做法是不做任何记载,理由是,这是“恢复”操作,要还原到备份时候的样子;另外一种做法是给 operations 下追加或者覆盖一个动作为 "restore" 的 operation 元素。

记录中除了 operations 元素,一些当前账户不允许修改的字段如何处理?如果是非 "force" 情况,则要保留原来记录中的这些字段,如果原记录不存在,则这些字段就不存在,或者如果此时 strAction 为 "new" 要按照新创建记录时候的原则给这些字段赋必要的初始值。

一个例子是读者记录中的 password 元素。如果原记录中有 password 元素,则修改发生后,原来的 password 元素依然不变;如果原记录不存在,并且 strAction 为 "new",那么需要按照新创建读者记录时候的规则,利用记录中的 birthDate 构造出初始密码建立一个 password 元素。

如果是 "force" 情况,此时可以理解为具有 supervisor 权限,可以改写任何字段,那么不必考虑原记录中的任何字段,用新记录内容全部覆盖上去即可。

这里涉及到一个关联的话题,就是这些用于恢复的数据记录是如何得到的?原则上应该用相当于 supervisor 的读权限,准确来说就是 backup 权限来从数据库中读取获得。然后用这样的记录去进行恢复操作,把数据恢复到数据库中,这样才能保证比如读者记录中的 password 这样的元素不会丢失。

试想一下,如果当初备份的时候用的是一个普通账户,那么读取读者记录的时候势必得不到 password 元素(被服务器返回前自动过滤了),而用这样的记录再去进行恢复操作,按照上面介绍的算法,最后保存进去的记录就是缺乏 password 元素的,等于恢复以后,password 元素丢了。

注意上面介绍的是普通导出+恢复操作。而如果是普通导出+普通导入,因为普通导入的时候,覆盖的时候本来就没法覆盖数据库中原记录的 password 元素,那么最终导入完成后的结果就是皆大欢喜,数据库记录中的 password 元素最终没有丢失。不过,这是说覆盖操作,数据库中原记录还在。如果换成,导入以前把数据库内的原有记录都删除了(注意删除本身需要超级用户权限,因为一般账户可能会有一些字段不具备写权限导致无法删除记录),再进行导入,那么原记录已经没有了,导入进去最终数据库记录里面就没有 password 元素。

测试要点

  1. 注意观察 action 为 "new" 时操作日志记录中也可能会存在 oldRecord 元素,当原记录存在时。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants