天天看點

Rafy 架構 - 大批量導入實體

某些場景下,開發者希望能夠大批量地把實體的資料導入到資料庫中。雖然使用實體倉庫儲存實體清單非常友善,但是其内部實作機制是一條一條的儲存到資料庫,當實體的個數較多時,效率就會很低。是以 rafy 設計了批量導入插件程式,其内部使用 ado.net 及 odp.net 中的批量導入機制來把大量資料一次性導入到資料庫中。

使用方法

由于批量導入功能是一個額外的程式集,是以在使用該功能時,需要先使用 nuget 引用最新版本的 rafy.domain.orm.batchsubmit 程式集。

如果準備導入 oracle 資料庫,則也需要引用 oracle.manageddataaccess(12.1.022 以上版本) 程式集。

修改需要儲存大量實體的代碼,例如,原代碼如下:

需要把最後一行使用倉庫儲存實體清單,修改為建立導入器來儲存實體清單:

注意

從上面的代碼可以看出,批量導入程式是面向整個聚合的。也就是說,批量導入父實體時,同時也會批量導入父實體下的所有子實體。

批量導入不但支援添加新實體,同時也支援批量更新、批量删除。使用方法與使用倉庫保持一緻。

對于大批量的資料,使用批量導入,比直接使用倉庫來儲存實體,速度要快兩個資料級左右。

目前批量導入實體的功能,隻支援 oracle 和 sqlserver 兩個資料庫。

在使用 oracle 資料庫時,還需要在資料庫生成完成後,特别地調用以下代碼以啟用某個聚合實體的批量導入功能,否則導入過程中會抛出異常(原因請見後面的實作原理章節)。代碼如下:

實作原理

下面簡要介紹批量導入的原理。

sql server

對于 sql server 資料庫的批量儲存:

批量新增資料,是使用 system.data.sqlclient.sqlbulkcopy 來實作的。

批量更新資料,是使用 system.data.sqlclient.sqldataadapter 來實作的。

批量删除資料,則是直接拼接 sql 語句,把需要删除的實體的 id 放到 in 語句中進行删除。例如:

oracle

對于 oracle 資料庫的批量儲存:

新增資料、更新資料都是使用 odp.net 中原生的批量導入功能。

參見:oracle.manageddataaccess.client.oraclecommand.arraybindcount 屬性。

而删除資料的實作則和 sqlserver 的實作一緻,均是拼接 delete 語句。

新增大量實體時,實體的 id 生成

一般情況下,使用倉庫儲存一個新增的實體時,倉庫會使用資料庫本身的機制來為實體生成 id,在 sqlserver 中是使用 identity 列,在 oracle 中則是使用每個表對應的 sequence 來生成。但是,批量導入大量新實體時,為了性能上的考慮,則需要一次性為需要儲存的所有新實體統一生成 id。

在 sqlserver 中,可以友善地使用 sql 語句調整表中 identity 下一次的值,是以實作比較簡單。隻需要設定 identity 下一次的值 + 100000,并使用中間跳過的這些值來作為實體的 id 即可。

但是在 oracle 中,如果去調整 sequence 的值,則屬于 ddl 語句,會隐式自動送出事務,會造成資料的錯誤。是以我們最終決定:如果在 oracle 中要使用批量導入功能,資料表對應的 sequence 必須以較大的數字為步距(如 alter sequence "seq_table_id" increment by 100000 nocache)。這樣,在批量導入時,就不再需要增修改 sequence 的步距,而直接使用中間跳過的這些值作為實體的 id。這樣做也比較友善,但是負面效果則是使用倉庫儲存單一實體時,兩次儲存不同實體生成的 id 會相差 100000,不再是連續的。