何时以及为何在 MikroOrm 中使用 em.clear()

When to and why use em.clear() in MikroOrm

我对 em.clear() 在 MikroOrm 或任何类似实体管理器中的作用有点困惑。 https://mikro-orm.io/docs/entity-manager link 用于 clear() 方法。

我似乎有一些关于一般 EntityManager 的 Whosebug 答案说我需要在每个 persist/remove and flush 之后调用 clear() 以避免任何内存问题。

为了让这个问题更具体地针对我的情况,我假设我在我的应用程序中构建了一个 Graphql 端点。 有一些通用的CRUD函数供用户调用,每个函数会利用MikroOrm的一些函数如findOne()等创建一个MikroOrm entity对数据库做一些通用的CRUD操作。

是不是每次persist/remove and flush之后(如果有一些CUD操作)都需要调用clear(),甚至只读数据?如果我不调用这个方法会发生什么?

我们应该首先描述 2 种方法来理解持久化在 MikroORM 中的工作原理:em.persist()em.flush()

em.persist(entity, flush?: boolean) 用于标记未来持久化的新实体。它将使实体由给定的 EntityManager 管理,一旦调用 flush,它将被写入数据库。第二个布尔参数可用于立即调用刷新。它的默认值可通过 autoFlush 选项配置。

为了理解 flush,让我们首先定义什么是托管实体:如果实体是从数据库中获取的(通过 em.find()em.findOne() 或通过另一个托管实体),则该实体是托管的或通过 em.persist().

注册为新的

em.flush() 将遍历所有托管实体,计算适当的变更集并执行相应的数据库查询。由于从数据库加载的实体会自动管理,因此您不必对它们调用 persistflush 足以更新它们。

const book = await orm.em.findOne(Book, 1);
book.title = 'How to persist things...';

// no need to persist `book` as its already managed by the EM
await orm.em.flush();

em.clear() 用于测试目的,因此您可以使用单个 EM 实例模拟多个独立请求:

const book1 = await em.findOne(Book, 1); // now book 1 will be loaded
const book2 = await em.findOne(Book, 1); // as book 1 is already loaded, this won't query the db
expect(book1).toBe(book2); // and we will get identity here
em.clear(); // but when we clear the identity map
const book3 = await em.findOne(Book, 1); // this will query the db as the state is now gone
expect(book1).not.toBe(book3); // and identity is gone

您可以通过使用 em.fork() 实现相同的效果,使用多个 EM 而不是使用一个。

内存应该在垃圾收集期间自动释放,在常规(应用程序)代码中不需要 em.clear() 方法。您的应用程序代码应该使用 RequestContext 帮助程序或手动分叉(请参阅 https://mikro-orm.io/docs/identity-map)。请求完成后,不应该引用这个旧上下文,它应该被垃圾收集(但请记住,这种情况不确定地发生,例如,当 JS 引擎感觉像它时:])。