Перейти к основному содержанию

Кэширование запросов

Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Вы можете кэшировать результаты, полученные через методы QueryBuilder: getMany, getOne, getRawMany, getRawOne и getCount.

Кэширование также доступно для результатов методов find* и count* в Repository и EntityManager.

Для активации кэширования необходимо явно включить его в настройках источника данных:

{
type: "mysql",
host: "localhost",
username: "test",
...
cache: true
}

При первом включении кэша
вам потребуется синхронизировать схему базы данных (через CLI, миграции или опцию synchronize источника данных).

Затем в QueryBuilder можно активировать кэш для любого запроса:

const users = await dataSource
.createQueryBuilder(User, "user")
.where("user.isAdmin = :isAdmin", { isAdmin: true })
.cache(true)
.getMany()

Эквивалентный запрос через Repository:

const users = await dataSource.getRepository(User).find({
where: { isAdmin: true },
cache: true,
})

Это выполнит запрос для получения всех администраторов и закэширует результаты.
При следующем запуске этого же кода данные будут взяты из кэша.
Стандартное время жизни кэша — 1000 ms (1 секунда).
Это означает, что кэш станет недействительным через 1 секунду после вызова кода QueryBuilder.
На практике: если пользователи откроют страницу 150 раз за 3 секунды, будет выполнено всего 3 запроса.
Пользователи, добавленные в течение 1-секундного окна кэширования, не будут отображены.

Время кэширования можно изменить вручную через QueryBuilder:

const users = await dataSource
.createQueryBuilder(User, "user")
.where("user.isAdmin = :isAdmin", { isAdmin: true })
.cache(60000) // 1 minute
.getMany()

Через Repository:

const users = await dataSource.getRepository(User).find({
where: { isAdmin: true },
cache: 60000,
})

Или глобально в настройках источника данных:

{
type: "mysql",
host: "localhost",
username: "test",
...
cache: {
duration: 30000 // 30 seconds
}
}

Также можно задать "идентификатор кэша" через QueryBuilder:

const users = await dataSource
.createQueryBuilder(User, "user")
.where("user.isAdmin = :isAdmin", { isAdmin: true })
.cache("users_admins", 25000)
.getMany()

Или через Repository:

const users = await dataSource.getRepository(User).find({
where: { isAdmin: true },
cache: {
id: "users_admins",
milliseconds: 25000,
},
})

Это обеспечивает детальный контроль над кэшем,
например, очистку кэша при добавлении нового пользователя:

await dataSource.queryResultCache.remove(["users_admins"])

По умолчанию TypeORM использует отдельную таблицу query-result-cache для хранения запросов и результатов.
Имя таблицы настраивается через свойство tableName:

{
type: "mysql",
host: "localhost",
username: "test",
...
cache: {
type: "database",
tableName: "configurable-table-query-result-cache"
}
}

Если хранение кэша в таблице БД неэффективно,
можно переключиться на "redis" или "ioredis" для хранения записей в Redis:

{
type: "mysql",
host: "localhost",
username: "test",
...
cache: {
type: "redis",
options: {
socket: {
host: "localhost",
port: 6379
}
}
}
}

Параметр "options" может содержать специфичные настройки node_redis или настройки ioredis в зависимости от типа.

Для подключения к redis-cluster через кластерную функциональность IORedis:

{
type: "mysql",
host: "localhost",
username: "test",
cache: {
type: "ioredis/cluster",
options: {
startupNodes: [
{
host: 'localhost',
port: 7000,
},
{
host: 'localhost',
port: 7001,
},
{
host: 'localhost',
port: 7002,
}
],
options: {
scaleReads: 'all',
clusterRetryStrategy: function (times) { return null },
redisOptions: {
maxRetriesPerRequest: 1
}
}
}
}
}

Примечание: вы можете передавать параметры первым аргументом в конструктор кластера IORedis.

{
...
cache: {
type: "ioredis/cluster",
options: [
{
host: 'localhost',
port: 7000,
},
{
host: 'localhost',
port: 7001,
},
{
host: 'localhost',
port: 7002,
}
]
},
...
}

Если стандартные провайдеры кэша не подходят,
можно создать кастомный провайдер через фабричную функцию provider,
возвращающую объект с интерфейсом QueryResultCache:

class CustomQueryResultCache implements QueryResultCache {
constructor(private dataSource: DataSource) {}
...
}
{
...
cache: {
provider(dataSource) {
return new CustomQueryResultCache(dataSource);
}
}
}

Для игнорирования ошибок кэша и передачи запросов напрямую в БД используйте опцию ignoreErrors:

{
type: "mysql",
host: "localhost",
username: "test",
...
cache: {
type: "redis",
options: {
socket: {
host: "localhost",
port: 6379
}
},
ignoreErrors: true
}
}

Для полной очистки кэша выполните: typeorm cache:clear.