深入理解 WordPress `get_transient()` 和 `set_transient()` 函数的源码:如何在 `wp_options` 表中实现短暂缓存。

各位观众老爷,大家好!我是你们的老朋友,今天咱们来聊聊WordPress里一对儿好基友:get_transient()set_transient()。 它们的作用嘛,简单来说,就是让你的WordPress站点跑得更快,就像打了鸡血一样!

别害怕,今天咱们不搞那些高深的理论,就用最接地气的方式,把它们扒个精光,看看它们到底是怎么在 wp_options 表里捣鼓出短暂缓存的。

开场白:为什么要用 Transient?

在开始之前,先问大家一个问题:你的网站是不是经常需要从数据库里读取一些数据,比如分类目录的数量、最新文章的列表等等? 这些数据可能不会经常变化,但每次请求都去数据库里捞一遍,是不是有点浪费资源?

就像你每天早上都要煮咖啡,但你完全可以一次性多煮一点,放在保温杯里,这样就不用每次都重新煮了。Transient 就是 WordPress 里的“保温杯”,它可以把一些数据暂时存起来,下次需要的时候直接从“保温杯”里拿,不用再去数据库里折腾了。

主角登场:set_transient()

set_transient() 函数的作用,就是把数据存到 Transient 里。它的原型是这样的:

set_transient( string $transient, mixed $value, int $expiration = 0 ) : bool
  • $transient:Transient 的名字,也就是“保温杯”的名字,你要用这个名字才能找到它。
  • $value:要缓存的数据,可以是任何类型,比如字符串、数组、对象等等。
  • $expiration:过期时间,单位是秒。过了这个时间,“保温杯”里的东西就过期了,需要重新煮咖啡(重新从数据库里读取数据)。如果设置为 0,表示永不过期(但不推荐,因为会占用数据库空间)。

set_transient() 源码剖析:

咱们来深入看看 set_transient() 到底做了些什么。它的核心逻辑都在 wp-includes/option.php 文件里。

function set_transient( string $transient, mixed $value, int $expiration = 0 ) : bool {
    $transient_timeout = '_transient_timeout_' . $transient;
    $transient = '_transient_' . $transient;

    if ( false === get_option( $transient ) ) {
        if ( 0 < $expiration ) {
            set_option( $transient_timeout, time() + $expiration, false );
        }

        return add_option( $transient, $value, '', 'no' );
    } else {
        if ( 0 < $expiration ) {
            update_option( $transient_timeout, time() + $expiration, false );
        } else {
            delete_option( $transient_timeout );
        }

        return update_option( $transient, $value, false );
    }
}

别被这一堆代码吓到,咱们一步一步来:

  1. 给 Transient 起名字:

    $transient_timeout = '_transient_timeout_' . $transient;
    $transient = '_transient_' . $transient;

    这里给 Transient 的名字前面加上了 _transient__transient_timeout_ 前缀。 为什么要这样做呢? 主要是为了避免和其他 Option 的名字冲突,就像给“保温杯”贴上标签,防止拿错。

  2. 检查 Transient 是否存在:

    if ( false === get_option( $transient ) ) {
        // Transient 不存在
    } else {
        // Transient 存在
    }

    这里用 get_option() 函数来检查 wp_options 表里有没有这个 Transient。 如果没有,说明是第一次存,需要用 add_option() 函数来添加; 如果有,说明已经存过了,需要用 update_option() 函数来更新。

  3. 设置过期时间:

    if ( 0 < $expiration ) {
        set_option( $transient_timeout, time() + $expiration, false );
    } else {
        delete_option( $transient_timeout );
    }

    如果设置了过期时间,就把过期时间戳(当前时间 + 过期秒数)存到 _transient_timeout_{$transient} 这个 Option 里。 如果没有设置过期时间,就把 _transient_timeout_{$transient} 这个 Option 删除。

  4. 保存 Transient 数据:

    return add_option( $transient, $value, '', 'no' ); // 添加 Transient
    return update_option( $transient, $value, false ); // 更新 Transient

    最后,用 add_option()update_option() 函数把数据存到 _transient_{$transient} 这个 Option 里。 注意,这里的 $value 可以是任何类型的数据,WordPress 会自动把它序列化后存到数据库里。

主角二号:get_transient()

get_transient() 函数的作用,就是从 Transient 里取出数据。它的原型是这样的:

get_transient( string $transient ) : mixed
  • $transient:Transient 的名字,也就是“保温杯”的名字。

get_transient() 源码剖析:

同样,咱们来深入看看 get_transient() 到底做了些什么。

function get_transient( string $transient ) : mixed {
    $transient = '_transient_' . $transient;

    $value = get_option( $transient );

    if ( false === $value ) {
        return false;
    }

    $transient_timeout = '_transient_timeout_' . $transient;
    $timeout = get_option( $transient_timeout );

    if ( false !== $timeout && time() > (int) $timeout ) {

        delete_transient( $transient );

        return false;
    }

    return $value;
}
  1. 给 Transient 起名字:

    $transient = '_transient_' . $transient;

    set_transient() 一样,这里也给 Transient 的名字前面加上了 _transient_ 前缀。

  2. 从数据库里读取数据:

    $value = get_option( $transient );
    
    if ( false === $value ) {
        return false;
    }

    get_option() 函数从 wp_options 表里读取 _transient_{$transient} 这个 Option 的值。 如果不存在,说明没有缓存,直接返回 false

  3. 检查是否过期:

    $transient_timeout = '_transient_timeout_' . $transient;
    $timeout = get_option( $transient_timeout );
    
    if ( false !== $timeout && time() > (int) $timeout ) {
    
        delete_transient( $transient );
    
        return false;
    }

    读取 _transient_timeout_{$transient} 这个 Option 的值,也就是过期时间戳。 如果存在,并且当前时间已经超过了过期时间,说明 Transient 已经过期,需要用 delete_transient() 函数删除,并返回 false

  4. 返回数据:

    return $value;

    如果 Transient 存在且没有过期,就直接返回从数据库里读取到的数据。

黄金配角:delete_transient()

delete_transient() 函数的作用,就是删除 Transient。它的原型是这样的:

delete_transient( string $transient ) : bool
  • $transient:Transient 的名字,也就是“保温杯”的名字。

delete_transient() 源码剖析:

function delete_transient( string $transient ) : bool {

    $transient = '_transient_' . $transient;

    $result = delete_option( $transient );

    if ( $result ) {
        delete_option( '_transient_timeout_' . substr( $transient, 11 ) );
    }

    return $result;
}
  1. 给 Transient 起名字:

    $transient = '_transient_' . $transient;

    和前面一样,这里也给 Transient 的名字前面加上了 _transient_ 前缀。

  2. 删除 Transient:

    $result = delete_option( $transient );

    delete_option() 函数从 wp_options 表里删除 _transient_{$transient} 这个 Option。

  3. 删除过期时间:

    if ( $result ) {
        delete_option( '_transient_timeout_' . substr( $transient, 11 ) );
    }

    如果成功删除了 Transient,就再删除 _transient_timeout_{$transient} 这个 Option,也就是过期时间。 注意,这里用 substr( $transient, 11 ) 去掉了 _transient_ 前缀,因为 _transient_timeout_ 已经包含了这个前缀。

wp_options 表里 Transient 的样子:

咱们来举个例子,假设我们要缓存一个叫做 my_widget_data 的 Transient,过期时间是 3600 秒(1 小时)。 那么,在 wp_options 表里会看到两个 Option:

option_name option_value
_transient_my_widget_data a:3:{s:5:"title";s:10:"My Widget";s:4:"text";s:20:"This is my widget.";s:5:"color";s:5:"green";}
_transient_timeout_my_widget_data 1678886400
  • _transient_my_widget_data 存储的是序列化后的数据,这里是一个数组。
  • _transient_timeout_my_widget_data 存储的是过期时间戳。

使用示例:

<?php
// 设置 Transient
$widget_data = array(
    'title' => 'My Widget',
    'text'  => 'This is my widget.',
    'color' => 'green',
);
set_transient( 'my_widget_data', $widget_data, 3600 ); // 缓存 1 小时

// 获取 Transient
$widget_data = get_transient( 'my_widget_data' );

if ( false === $widget_data ) {
    // Transient 不存在或已过期,需要重新获取数据
    $widget_data = array(
        'title' => 'My Widget',
        'text'  => 'This is my widget.',
        'color' => 'green',
    );
    set_transient( 'my_widget_data', $widget_data, 3600 ); // 重新缓存
}

// 使用数据
echo '<h1>' . esc_html( $widget_data['title'] ) . '</h1>';
echo '<p>' . esc_html( $widget_data['text'] ) . '</p>';
echo '<p style="color:' . esc_attr( $widget_data['color'] ) . ';">Color: ' . esc_html( $widget_data['color'] ) . '</p>';

// 删除 Transient
// delete_transient( 'my_widget_data' );
?>

Transient 的注意事项:

  • Transient 只是短暂的缓存,不能替代数据库。 数据库才是数据的最终归宿。
  • Transient 的名字要唯一。 避免和其他 Transient 冲突。
  • 合理设置过期时间。 过期时间太短,起不到缓存的作用; 过期时间太长,可能会导致数据过期。
  • 不要缓存太大的数据。 wp_options 表有大小限制,缓存太大的数据可能会导致性能问题。
  • 注意数据类型。 从 Transient 里取出的数据是序列化后的,需要用 unserialize() 函数反序列化。 但是get_option会自动反序列化,所以你不需要手动操作。
  • Transient 存储在 wp_options 表中,如果你的 wp_options 表非常庞大,可能会影响性能。 可以考虑使用其他缓存方案,比如 Memcached 或 Redis。

Transient 和 Option 的区别:

特性 Transient Option
用途 短暂缓存数据 存储配置信息
过期时间 可以设置过期时间 一般没有过期时间
存储位置 wp_options wp_options
数据量 适合存储少量数据 适合存储少量数据
使用场景 不经常变化的数据,需要提高性能 网站配置信息,插件设置等

Transient 的最佳实践:

  • 缓存查询结果: 比如缓存分类目录的数量、最新文章的列表等等。
  • 缓存 API 响应: 比如从第三方 API 获取的数据。
  • 缓存复杂的计算结果: 比如一些需要耗费大量 CPU 资源才能计算出来的数据。
  • 结合 WP-Cron 使用: 可以定期更新 Transient,保持数据的时效性。

高级技巧:使用对象缓存

虽然 Transient 存储在数据库中,但WordPress也支持对象缓存,可以将 Transient 存储在内存中,进一步提高性能。 这需要安装和配置对象缓存插件,比如 Memcached 或 Redis。

总结:

Transient 是 WordPress 里一个非常实用的缓存机制,它可以帮助你提高网站的性能。 掌握了 get_transient()set_transient() 函数的使用方法,你就可以像魔法师一样,让你的网站跑得飞快!

好了,今天的讲座就到这里。希望大家能够学有所获,下次再见! 别忘了点赞、收藏、转发哦! (手动滑稽)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注