CQRS批量操作的性能问题

13-01-03 thinkjava
假设Book是一个聚合实体,现在要删除某一个Book没有问题,通过仓储Repository加载实体,然后调用其delete方法即可,但现在问题来了,如果DB中有上万个Book需要一次性批量全部删除,那么应该如何设计呢,看下面的代码:

       @[author]CommandHandler[/author]
	public void handle(RemoveAllBookCommand command, UnitOfWork unitOfWork) {
		List<BookEntry> entrys = bookRepository.findAllBooks();
		if (entrys != null || !entrys.isEmpty()) {
			for (BookEntry entry : entrys) {
				Book book = (Book) this.repository.load(new StringAggregateIdentifier(entry
								.getIdentifier()));
				book.delete();//删除Book
			}
		}
	}
<p>

这种设计有两个缺点:

1. 脱了裤子放屁,还不如直接调用bookRepository.deleteAllBooks()

2. 性能降低,获取所有的Data Book,然后调用实体中的delete方法

3. 分页删除,如果有100万Book需要全部清零,那么一定需要分多次调用findBooks获得数据实体,这会严重影响性能

各位版友有何建议?

SpeedVan
2013-01-04 00:49
2013-01-03 17:47 "@cloudstack"的内容
这种设计有两个缺点:

1. 脱了裤子放屁,还不如直接调用bookRepository.deleteAllBooks()

2. 性能降低,获取所有的Data Book,然后调用实体中的delete方法

3. 分页删除,如果有100万Book需 ...

假设 books 是所有书的集合,那么我们只需要books.clear()即可。把Repository看成集合,clear()或deleteAllBooks()明显是合理的,你可以把clear理解为清仓。

还有建议不要用book.delete(),“自杀”是不建议的,所谓的删除是逻辑上的从集合中移除,book自身不存在生死权,他的生死必须交由“自然”本身。

[该贴被SpeedVan于2013-01-04 01:13修改过]

banq
2013-01-04 09:09
2013-01-03 17:47 "@cloudstack"的内容
性能降低,获取所有的Data Book ...

在Jdonframework中是通过获取所有实体的ID后,再根据ID来删除,批量删除是Repository的一个特殊独立功能,不应该是实体自己的功能,创建和删除我一直认为不应该是实体自己的行为,对于创建,一个事物没有被创建之前不可能创建自己,这违反基本逻辑。

删除自己也不是自己来控制的,何为删除自己?对于领域模型,它是不知道有数据库仓储存在的,数据仓库中的实体是扁平的,而领域模型是立体活动的,这好比人活着和死了或休眠的关系一样。有一天如果人类技术发达,可以将人体冷冻后储存起来,千年以后再从仓储中取出复活。

删除这个词语其实隐含着数据库的概念,而不是领域模型自己的概念,所以,直接归纳为Repository仓储操作即可,是属于仓库管理命令。

thinkjava
2013-01-04 11:58
2013-01-04 00:49 "@SpeedVan"的内容
假设 books 是所有书的集合,那么我们只需要books.clear()即可。把Repository看成集合,clear()或deleteAllBooks()明显是合理的,你可以把clear理解为清仓。

还有建议不要用book.delete(),“自杀”是不建议的,所谓的删除是逻辑上的从集合中移除 ...

我这里的Book是一个聚合实体,你说的books是什么?是指Repository<Book>吗,如果是,仓储Repository是没有删除功能的,如果books是指要设计一个Books的聚合实体,里面维护一个List<Book>的集体吗?那Books与Repository是什么关系呢? 因为Repository只有load(aggregateId)和add(Object obj)两个方法,我往Repository里增加一本书是合理的,但增加一个Books的聚合不合理呀?也没法实现呀

我看过Axon的Addressbook sample,他是将Contact作为实体的,是个聚合根,其中就是changeName,delete等方法,如何解释?

thinkjava
2013-01-04 12:06
2013-01-04 09:09 "@banq"的内容
在Jdonframework中是通过获取所有实体的ID后,再根据ID来删除,批量删除是Repository的一个特殊独立功能 ...

删除这个词语其实隐含着数据库的概念,而不是领域模型自己的概念,所以,直接归纳为Repository仓储操作即可,是属于仓库管理命令。

获取所有实体的ID后,再根据ID来删除,这样性能低下,如果有100万个Book,你这样一个一个删除我觉着不是好办法,还不如直接调用DB SQL:DELETE FROM BOOK呢

你说的Repository是指访问DB的DAO吧,领域仓储Repository是没有删除功能的呀,只有load和add两个方法

SpeedVan
2013-01-04 17:55
2013-01-04 11:58 "@cloudstack"的内容
我这里的Book是一个聚合实体,你说的books是什么?是指Repository吗,如果是,仓储Repository是没有删除功能的,如果books是指要设计一个Books的聚合实体,里面维护一个List的集体吗?那 ...

很多技术都是不彻底的,就如函数式,现在有多少真正的纯函数的语言?很多都是挂羊头卖狗肉,又如当时提出REST一样。

books就是Repository<Book>,实体的创建和删除,真的不能自己进行,先撇开哲学角度,实体关系是被上一层维护的话,这种自杀行为相当于绕开关系约束。可能是因为自杀曾经被提倡过,使用自杀认为是简单,但这种做法其实是把每一个关系约束重新放入自杀中,用一下就知放屁了。放到哲学角度,就像抹杀存在一样,一个自然系统中,突然某东西消失了,这个自然系统就会崩溃。

试想:若果不是从books集合中移除1book,那么当这个book自杀时,books如何维护数量呢?

thinkjava
2013-01-04 22:32
2013-01-04 17:55 "@SpeedVan"的内容
books就是Repository,实体的创建和删除,真的不能自己进行,先撇开哲学角度,实体关系是被上一层维护的话,这种自杀行为相当于绕开关系约束。可能是因为自杀曾经被提倡过,使用自杀认为是简单,但这种做法其实是把每一个关系约束 ...

你可能不太了解CQRS的领域仓储Repository设计的目的,Repository是不允许删除的,即使要删除,也同样会产生一个BookRemoveEvent的领域事件,而不是直接从EventStore中删除某个事件数据,这样的理由是来自于Event Sourcing所带来的一种数据分析与跟踪的可能性,它允许将领导对象可以还原到任何一个时间点,通过事件重放(replay)来诊断你的模型数据,所以Repository不允许对EventStore进行任意的删除操作,这是CQRS的设计思路,但是这种思路让我疑惑的是:如果要实现一个图书管理系统,有一个对Book聚合的CURD操作,那么其中的批量Remove Book如何设计,delete和create是否允许放在Book聚合上,比如如下代码:

 Book extends AggregateRoot {
      publlic Book(String name) {
           apply(BookCreatedEvent(name))
      }
      public void handle(BookCreatedEvent event) {
       }
       pubilc void delete() {
            apply(new BookDeletedEvent());
        }
        public void handle(BookDeletedEvent event) {
         }
  }
<p>

所以当你在UI上多选了几本书要批量删除,那么此时如何设计Book的行为

gameboyLV
2013-01-05 20:32
2013-01-04 22:32 "@cloudstack"的内容
所以当你在UI上多选了几本书要批量删除,那么此时如何设计Book的行为 ...

不知道这个思路能不能解决您的疑问:http://www.jdon.com/44844/5

猜你喜欢