各位观众老爷,晚上好!我是今天的主讲人,咱们今天的主题是 WordPress 的 transient API,也就是 get_transient()
和 set_transient()
这对好基友,以及它们背后默默付出的 wp_options
表。准备好,我们要开始扒它们的底裤了!
Transient API 是什么鬼?
想象一下,你有一个非常耗时的操作,比如从外部 API 获取数据,或者进行复杂的数据库查询。每次用户访问页面都要重新执行这些操作,那服务器岂不是要累死了?Transient API 就是来拯救世界的。它可以让你把这些耗时操作的结果缓存起来,下次用户访问的时候直接从缓存里拿,速度嗖嗖的!
Transient API 其实就是一个简单的键值对存储系统,它能让你设置缓存的过期时间,到期后缓存自动失效。
set_transient()
: 种下缓存的种子
我们先来看看 set_transient()
函数的源码,它负责把数据存入缓存。
/**
* Set the value of a transient.
*
* You can set the transient to expire in a number of seconds. If you set the
* expiration to 0, the transient will not expire.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* Must be 191 characters or less in length.
* @param mixed $value Transient value. Must be serializable if non-scalar.
* Expected to not be SQL-escaped.
* @param int $expiration Optional. Time until expiration in seconds. Default 0 (no expiration).
* @return bool False if value was not set and true if value was set.
*/
function set_transient( string $transient, mixed $value, int $expiration = 0 ): bool {
/**
* Fires before a transient is set.
*
* @since 3.0.0
*
* @param string $transient Transient name.
* @param mixed $value Transient value.
* @param int $expiration Time until expiration in seconds.
*/
do_action( 'set_transient', $transient, $value, $expiration );
$transient_timeout = '_transient_timeout_' . $transient;
$transient = '_transient_' . $transient;
if ( false === get_option( $transient_timeout ) ) {
$autoload = 'yes';
if ( $expiration ) {
$autoload = 'no';
add_option( $transient_timeout, time() + $expiration, '', $autoload );
} else {
add_option( $transient_timeout, 0, '', $autoload );
}
} else {
if ( $expiration ) {
update_option( $transient_timeout, time() + $expiration );
} else {
update_option( $transient_timeout, 0 );
}
}
if ( false === get_option( $transient ) ) {
$autoload = 'yes';
add_option( $transient, $value, '', $autoload );
} else {
update_option( $transient, $value );
}
/**
* Fires after a transient is set.
*
* @since 3.0.0
*
* @param string $transient Transient name.
* @param mixed $value Transient value.
* @param int $expiration Time until expiration in seconds.
*/
do_action( 'set_transient', $transient, $value, $expiration );
return true;
}
看起来很长,但其实逻辑很简单:
-
Action Hook: 首先,它会触发一个
set_transient
的 action hook,允许你在这个过程前后做一些事情。比如记录日志,或者修改缓存的值和过期时间。 -
命名空间: 它会给你的 transient name 加上前缀
_transient_timeout_
和_transient_
,这样可以避免和其他 option 冲突。比如,你想缓存名为my_data
的数据,那么实际存储在wp_options
表中的 option name 就是_transient_my_data
和_transient_timeout_my_data
。 -
过期时间: 接下来,它会处理过期时间。如果设置了过期时间,它会将过期时间戳(当前时间 + 过期秒数)存储在
_transient_timeout_{transient_name}
这个 option 中。如果没有设置过期时间,就将_transient_timeout_{transient_name}
设置为0
。 -
存储数据: 最后,它会将你的数据存储在
_transient_{transient_name}
这个 option 中。 -
add_option()
vsupdate_option()
: 函数会先尝试使用get_option()
检查相应的 option 是否已经存在。如果不存在,就使用add_option()
创建新的 option,否则使用update_option()
更新已有的 option。 -
Action Hook: 再次触发
set_transient
action hook。
get_transient()
: 挖出缓存的宝藏
现在,我们来看看 get_transient()
函数的源码,它负责从缓存中获取数据。
/**
* Retrieve the value of a transient.
*
* If the transient does not exist, does not have a value, or has expired,
* then the return value will be false.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return mixed Value of transient.
*/
function get_transient( string $transient ): mixed {
/**
* Fires before a transient is retrieved.
*
* @since 3.0.0
*
* @param string $transient Transient name.
*/
do_action( 'get_transient', $transient );
$transient_timeout = '_transient_timeout_' . $transient;
$transient = '_transient_' . $transient;
$timeout = get_option( $transient_timeout );
if ( false === $timeout ) {
return false;
}
if ( (int) $timeout < time() && (int) $timeout > 0 ) {
delete_transient( $transient );
return false;
}
$value = get_option( $transient );
/**
* Filters an existing transient's value.
*
* The dynamic portion of the hook name, `$transient`, refers to the transient name.
*
* @since 2.8.0
*
* @param mixed $value Value of transient.
*/
return apply_filters( "transient_{$transient}", $value );
}
同样,我们来分解一下:
-
Action Hook: 触发
get_transient
action hook。 -
命名空间: 和
set_transient()
一样,它也会给 transient name 加上前缀_transient_timeout_
和_transient_
。 -
获取过期时间: 它会从
wp_options
表中获取_transient_timeout_{transient_name}
的值,也就是过期时间戳。 -
检查是否过期: 如果过期时间戳小于当前时间,并且大于0(0表示永不过期),说明缓存已经过期。这时,它会调用
delete_transient()
函数删除缓存,并返回false
。 -
获取数据: 如果缓存没有过期,它会从
wp_options
表中获取_transient_{transient_name}
的值,也就是缓存的数据。 -
Filter Hook: 最后,它会触发一个
transient_{$transient}
的 filter hook,允许你修改缓存的值。
delete_transient()
: 清除缓存的痕迹
delete_transient()
函数的作用就是删除 transient,防止脏数据继续被使用。
/**
* Delete a transient.
*
* @since 2.8.0
*
* @param string $transient Transient name. Expected to not be SQL-escaped.
* @return bool True if the transient was successfully deleted, false otherwise.
*/
function delete_transient( string $transient ): bool {
/**
* Fires before a transient is deleted.
*
* @since 3.0.0
*
* @param string $transient Transient name.
*/
do_action( 'delete_transient', $transient );
$transient_timeout = '_transient_timeout_' . $transient;
$transient = '_transient_' . $transient;
$deleted = delete_option( $transient );
$deleted_timeout = delete_option( $transient_timeout );
if ( $deleted || $deleted_timeout ) {
/**
* Fires after a transient is deleted.
*
* @since 3.0.0
*
* @param string $transient Transient name.
*/
do_action( 'deleted_transient', $transient );
return true;
}
return false;
}
这个函数更加简单粗暴:
- Action Hook: 触发
delete_transient
action hook。 - 命名空间: 和之前一样。
- 删除 Option: 使用
delete_option()
函数分别删除_transient_{transient_name}
和_transient_timeout_{transient_name}
这两个 option。 - Action Hook: 触发
deleted_transient
action hook。
wp_options
表: 幕后英雄
Transient API 的所有数据都存储在 wp_options
表中。这个表是 WordPress 用来存储各种配置项的,比如站点标题、主题设置等等。
wp_options
表的结构通常包含以下几个关键字段:
字段名 | 数据类型 | 描述 |
---|---|---|
option_id |
bigint(20) unsigned |
主键,自增长。 |
option_name |
varchar(191) |
Option 的名称。Transient API 使用 _transient_{transient_name} 和 _transient_timeout_{transient_name} 作为 option name。这个字段需要唯一索引。长度限制为 191 个字符,这是因为 WordPress 数据库的键长度限制。 |
option_value |
longtext |
Option 的值。Transient API 将缓存的数据存储在这个字段中。 longtext 可以存储大量数据,但是读取速度相对较慢。 |
autoload |
varchar(20) |
指示这个 option 是否在 WordPress 初始化时自动加载。Transient API 默认将 _transient_timeout_{transient_name} 设置为 no (除非没有设置过期时间,设置为yes ),将 _transient_{transient_name} 设置为 yes 。 这意味着缓存的过期时间不会自动加载,而缓存的数据会。 |
Transient API 的优缺点
优点:
- 简单易用: API 非常简单,只有三个函数,容易上手。
- 自动过期: 可以设置过期时间,避免缓存脏数据。
- 内置支持: 无需安装额外的插件,WordPress 自带。
缺点:
- 性能瓶颈: 所有数据都存储在
wp_options
表中,如果缓存的数据量很大,或者频繁读写缓存,可能会导致性能问题。因为wp_options
表通常存储在数据库中,读写速度相对较慢。 - 数据类型限制: 存储在
wp_options
表中的数据需要能够被序列化。这意味着一些特殊的数据类型可能无法直接存储。 - 全局共享: 所有插件和主题都可以访问和修改 transient 数据,容易产生冲突。
最佳实践
- 谨慎使用: 只缓存真正需要缓存的数据,避免过度缓存。
- 合理设置过期时间: 根据数据的更新频率,设置合适的过期时间。
- 使用对象缓存: 如果缓存的数据量很大,可以考虑使用对象缓存,比如 Memcached 或 Redis。这些缓存系统可以将数据存储在内存中,读写速度更快。
- 避免频繁读写: 尽量减少对 transient 的读写操作,可以使用批量操作或者其他优化手段。
- 注意数据类型: 确保缓存的数据可以被序列化。
代码示例
<?php
// 设置一个 transient,过期时间为 30 分钟
$transient_name = 'my_expensive_data';
$data = get_transient( $transient_name );
if ( false === $data ) {
// 如果缓存不存在,执行耗时操作
$data = do_something_expensive();
// 缓存数据,过期时间为 30 分钟 (1800 秒)
set_transient( $transient_name, $data, 1800 );
}
// 使用缓存的数据
echo $data;
// 删除缓存
//delete_transient( $transient_name );
function do_something_expensive() {
// 模拟一个耗时操作
sleep(2);
return 'Hello from the expensive function!';
}
总结
Transient API 是 WordPress 提供的一个简单易用的缓存机制。它通过 set_transient()
、get_transient()
和 delete_transient()
这三个函数,以及 wp_options
表,实现了键值对缓存,并支持过期时间。 虽然 Transient API 有一些缺点,但在很多情况下,它仍然是一个不错的选择。只要合理使用,就可以有效地提高 WordPress 站点的性能。
好了,今天的讲座就到这里。希望大家对 Transient API 有了更深入的了解。 记住,缓存虽好,可不要贪杯哦! 谢谢大家!