何时以及为何在 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()
将遍历所有托管实体,计算适当的变更集并执行相应的数据库查询。由于从数据库加载的实体会自动管理,因此您不必对它们调用 persist
,flush
足以更新它们。
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 引擎感觉像它时:])。
我对 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()
将遍历所有托管实体,计算适当的变更集并执行相应的数据库查询。由于从数据库加载的实体会自动管理,因此您不必对它们调用 persist
,flush
足以更新它们。
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 引擎感觉像它时:])。