背景
搞了近五年的系统开发,总是抱着一种思维模式,用户的一个操作对应一个请求和一个事务,比如:用户选择了N条记录,我就会向服务器发生一个请求,服务器在一个事务中进行处理。前几天在群里一个前辈反问:批量操作难道真的要在一个事务中?这个问题让陷入了反思,谢谢前辈们(魏琼东)。
DDD中有聚合的概念,一个聚合有且只有一个聚合根和一些其他实体,如:订单聚合中,订单是聚合根,订单明细是聚合内的实体。因为DDD中只能操作聚合根,这篇文章就介绍聚合根的批量删除问题。有人问聚合内的实体的删除咋弄?聚合内实体的删除必须伴随着聚合根的修改(这里不做详细介绍)。
另外一点是需要注意的是,引入工作单元之后,批量操作和单个操作服务器端的逻辑是不同的,如:索引验证问题和工号生成问题(这里不做详细介绍)。
批量删除思路
我目前有三种选择,我记录下来,然后一个一个分析:
- 发送一个请求,服务器一个事务。
- 发送一个请求:服务器N个事务。
- 发送N个请求,服务器N个事务。
发送一个请求,服务器一个事务。
这是我之前采用的思路,现在觉得非常不好,为什么非要在一个事务中呢?如果您觉得非要在一个事务中,就告诉我一声。
发送一个请求:服务器N个事务。
这种思路可以接受,不过要在服务器端做额外的处理,如:收集哪些失败或成功的信息,发生给客户端,如果我不用AJAX,我就会选择这个方案。
发送N个请求,服务器N个事务。
考虑到我是AJAX编程,这种思路好,重分利用了客户端。
发送N个请求,服务器N个事务的实现思路
思路有了,实现就不是问题了,搞个队列排队发送请求就行了,当然你可以选择并行发送请求或分批次排队发送请求。
删除的客户端逻辑
1 /** 2 * 删除功能。 3 * 4 * @class Delete 5 * @extends Happy.action.Action 6 * @namespace Happy.table.action 7 */ 8 Ext.define('Happy.table.action.Delete', { 9 extend: 'Happy.action.Action', 10 requires: [ 11 'Happy.server.PessimisticLockProxy', 12 'Happy.Msg', 13 'Happy.Ajax' 14 ], 15 16 DELETE_CONFIRM_TITLE: '删除确认', 17 DELETE_CONFIRM_MSG: '确定执行删除吗?', 18 19 defaultConfig: { 20 itemId: 'delete', 21 iconCls: 'delete-button', 22 text: '删除', 23 disabled: true, 24 autoEnableAndDisable: true 25 }, 26 27 /** 28 * 契约:<br/> 29 * <ul> 30 * <li>button.up('tablepanel')!==null。</li> 31 * </ul> 32 * @protect 33 * @method onClickHandler 34 * @param {Ext.button.Button} button 按钮 35 */ 36 onClickHandler: function (button) { 37 var me = this; 38 39 var table = button.up('tablepanel'); 40 var records = table.getSelection(); 41 42 if (records.length == 0) { 43 return; 44 } 45 46 Ext.Msg.confirm(me.DELETE_CONFIRM_TITLE, me.DELETE_CONFIRM_MSG, function (btn) { 47 if (btn !== 'yes') { 48 return; 49 } 50 51 me.deleteRecords(records); 52 }); 53 }, 54 55 /** 56 * private 57 * @method deleteRecords 58 */ 59 deleteRecords: function (records) { 60 var me = this; 61 62 if (records.length == 0) { 63 Happy.Msg.showDeleteSuccess(); 64 return; 65 } 66 67 Happy.Ajax.destroy(records.shift(), { 68 success: function (record) { 69 me.deleteRecords(records); 70 }, 71 failure: function (record, operation) { 72 Happy.Msg.showDeleteFailure(operation.error); 73 } 74 }); 75 } 76 });
删除的服务器端逻辑
1 /// <summary> 2 /// 删除。 3 /// </summary> 4 public ActionResult Delete(TAggregateRoot item) 5 { 6 this.CurrentCommandService.Execute(new TDeleteCommand 7 { 8 Aggregate = item 9 }); 10 11 return this.NewtonsoftJson(new 12 { 13 success = true 14 }); 15 }
效果图
备注
这里只是演示了批量删除,有很多针对聚合根的批量操作都可以这么处理。