分析 WordPress `get_transient()` 函数源码:如何处理过期缓存,并解释其与 `wp_options` 表的交互。

各位朋友,大家好!我是老码,今天咱们来聊聊 WordPress 缓存机制中一个非常重要的函数:get_transient()。 别看它名字挺学术,其实用起来非常简单,但要真正理解它背后的原理,特别是它如何处理过期缓存以及与 wp_options 表的爱恨情仇,那就需要好好研究一下源码了。

咱们今天的讲座,就围绕这两个核心问题展开:

  1. get_transient() 如何判断缓存是否过期,并处理过期情况?
  2. get_transient() 如何与 wp_options 表交互,存储和检索缓存数据?

准备好了吗? 让我们开始吧!

一、get_transient() 的基本用法

首先,咱们简单回顾一下 get_transient() 的基本用法,避免有些朋友对它还不太熟悉。

get_transient() 函数的作用是从 WordPress 数据库中检索一个瞬态(transient)值。 瞬态可以理解为一种临时缓存,用于存储一些需要频繁访问但又不希望每次都重新计算的数据。

<?php
// 设置一个瞬态
$transient_name = 'my_super_important_data';
$transient_value = array( 'key1' => 'value1', 'key2' => 'value2' );
$expiration = 3600; // 缓存有效期,单位为秒 (1 小时)

set_transient( $transient_name, $transient_value, $expiration );

// 获取瞬态
$data = get_transient( $transient_name );

if ( false === $data ) {
    // 瞬态不存在或已过期,重新计算数据
    $data = calculate_expensive_data(); // 假设这是一个耗时的函数
    set_transient( $transient_name, $data, $expiration );
}

// 使用缓存的数据
print_r( $data );
?>

这段代码展示了 get_transient() 的典型用法:

  1. 使用 set_transient() 设置一个瞬态,包括瞬态名称、值和过期时间。
  2. 使用 get_transient() 尝试获取瞬态。
  3. 如果 get_transient() 返回 false,表示瞬态不存在或者已经过期,需要重新计算数据并再次设置瞬态。

二、get_transient() 源码分析:过期检测机制

现在,让我们深入 get_transient() 的源码,看看它如何判断缓存是否过期。

get_transient() 函数位于 wp-includes/option.php 文件中。 为了方便阅读,我将代码简化并添加了注释:

<?php
function get_transient( $transient ) {
    global $wpdb;

    $transient = sanitize_key( $transient ); // 安全起见,清理瞬态名称
    $option = '_transient_' . $transient; // 构建存储瞬态值的选项名称

    $cache = wp_cache_get( $option, 'transient' );  // 首先尝试从对象缓存中获取

    if ( false === $cache ) {
        // 对象缓存未命中,从数据库中获取
        $cache = get_option( $option );

        if ( false !== $cache ) {
            wp_cache_set( $option, $cache, 'transient' );  // 将结果存入对象缓存
        }
    }

    if ( false === $cache ) {
        return false; // 瞬态不存在
    }

    $expiration = get_option( '_transient_timeout_' . $transient ); // 获取瞬态的过期时间

    if ( false !== $expiration && time() > $expiration ) {
        // 瞬态已过期
        delete_transient( $transient ); // 删除瞬态
        return false; // 返回 false
    }

    return $cache; // 返回缓存的值
}
?>

从上面的代码可以看出,get_transient() 判断缓存是否过期的核心逻辑如下:

  1. 构建选项名称: get_transient() 首先根据瞬态名称构建两个选项名称:
    • _transient_$transient:存储瞬态的值。
    • _transient_timeout_$transient:存储瞬态的过期时间戳。
  2. 对象缓存优先: get_transient() 优先从对象缓存中获取瞬态的值。 如果对象缓存命中,则直接跳过数据库查询。
  3. 数据库查询: 如果对象缓存未命中,则从 wp_options 表中获取瞬态的值。
  4. 获取过期时间:wp_options 表中获取瞬态的过期时间戳。
  5. 过期判断: 将当前时间戳与过期时间戳进行比较。 如果当前时间戳大于过期时间戳,则表示瞬态已过期。
  6. 删除过期瞬态: 如果瞬态已过期,则使用 delete_transient() 函数删除瞬态的值和过期时间。
  7. 返回结果: 如果瞬态存在且未过期,则返回瞬态的值。 否则,返回 false

用一个表格来更清晰地展示这个过程:

步骤 说明 对应代码
1 构建存储瞬态值和过期时间的选项名称。 $option = '_transient_' . $transient;
$expiration_option = '_transient_timeout_' . $transient;
2 尝试从对象缓存中获取瞬态的值。 $cache = wp_cache_get( $option, 'transient' );
3 如果对象缓存未命中,则从 wp_options 表中获取瞬态的值。 $cache = get_option( $option );
4 如果成功从数据库获取瞬态,则将瞬态存入对象缓存。 wp_cache_set( $option, $cache, 'transient' );
5 wp_options 表中获取瞬态的过期时间戳。 $expiration = get_option( '_transient_timeout_' . $transient );
6 比较当前时间戳和过期时间戳,判断瞬态是否过期。 if ( false !== $expiration && time() > $expiration ) { ... }
7 如果瞬态已过期,则使用 delete_transient() 函数删除瞬态的值和过期时间。 delete_transient( $transient );
8 如果瞬态存在且未过期,则返回瞬态的值。 否则,返回 false return $cache; / return false;

重点: get_transient() 并没有在每次获取瞬态时都去检查是否过期。 只有当对象缓存未命中,需要从数据库中获取瞬态时,才会进行过期检查。 这也是为什么使用对象缓存可以显著提高性能的原因之一。

三、wp_options 表的交互:存储与检索

get_transient()wp_options 表的交互主要体现在 get_option()update_option() 函数的使用上。 让我们来看一下 set_transient()delete_transient() 函数的源码,以了解它们是如何与 wp_options 表交互的。

3.1 set_transient() 源码分析

<?php
function set_transient( $transient, $value, $expiration = 0 ) {
    $transient = sanitize_key( $transient );
    if ( empty( $transient ) ) {
        return false;
    }

    $expiration = (int) $expiration;

    $option = '_transient_' . $transient;
    $expiration_option = '_transient_timeout_' . $transient;

    if ( false === get_option( $option ) ) {
        $autoload = 'yes';
        if ( $expiration ) {
            $autoload = 'no';
        }

        add_option( $option, $value, '', $autoload );

        if ( $expiration ) {
            update_option( $expiration_option, time() + $expiration, $autoload );
        }
        return true;
    } else {

        if ( $expiration ) {
            update_option( $expiration_option, time() + $expiration );
        } else {
            delete_option( $expiration_option );
        }

        return update_option( $option, $value );
    }
}
?>

set_transient() 函数的作用是设置一个瞬态。 它主要完成以下几件事情:

  1. 构建选项名称:get_transient() 类似,set_transient() 也需要构建存储瞬态值和过期时间的选项名称。
  2. 判断瞬态是否存在: 使用 get_option() 函数判断瞬态是否已经存在。
  3. 新增瞬态: 如果瞬态不存在,则使用 add_option() 函数将瞬态的值和过期时间添加到 wp_options 表中。
    • add_option() 的第四个参数 $autoload 决定了该选项是否在 WordPress 初始化时自动加载。 如果设置了过期时间,则 $autoload 设置为 'no',因为过期瞬态不需要自动加载。否则设置为'yes'
  4. 更新瞬态: 如果瞬态已经存在,则使用 update_option() 函数更新瞬态的值和过期时间。
  5. 删除过期时间: 如果设置了$expiration = 0,则删除过期时间,避免过期时间存在,但瞬态值不存在的情况。

3.2 delete_transient() 源码分析

<?php
function delete_transient( $transient ) {
    global $wpdb;

    $transient = sanitize_key( $transient );

    $option = '_transient_' . $transient;
    $expiration_option = '_transient_timeout_' . $transient;

    $deleted = delete_option( $option );
    $deleted_timeout = delete_option( $expiration_option );

    return $deleted || $deleted_timeout;
}
?>

delete_transient() 函数的作用是删除一个瞬态。 它非常简单,主要完成以下几件事情:

  1. 构建选项名称:get_transient()set_transient() 类似,delete_transient() 也需要构建存储瞬态值和过期时间的选项名称。
  2. 删除瞬态: 使用 delete_option() 函数从 wp_options 表中删除瞬态的值和过期时间。

3.3 wp_options 表的存储结构

wp_options 表是 WordPress 的一个核心数据表,用于存储各种配置选项和数据。 瞬态数据也是存储在 wp_options 表中的。

wp_options 表的结构如下:

字段名 数据类型 说明
option_id bigint(20) 选项 ID,自增长
option_name varchar(191) 选项名称,例如 _transient_my_super_important_data_transient_timeout_my_super_important_data
option_value longtext 选项值,可以是字符串、数组、对象等
autoload varchar(20) 是否自动加载。 yes 表示在 WordPress 初始化时自动加载, no 表示不自动加载。 用于优化性能,避免加载不必要的选项。

可以看到,瞬态数据在 wp_options 表中以键值对的形式存储。 选项名称以 _transient__transient_timeout_ 开头,选项值则是瞬态的实际数据或过期时间戳。

四、对象缓存的作用:性能优化

前面我们提到,get_transient() 函数会优先从对象缓存中获取瞬态的值。 那么,对象缓存到底是什么,它又如何提高性能呢?

对象缓存 是 WordPress 提供的一种内存缓存机制,用于存储 PHP 对象。 它可以将数据库查询结果、计算结果等数据存储在内存中,以便下次可以直接从内存中获取,而无需再次查询数据库或重新计算。

WordPress 提供了多种对象缓存的实现,例如:

  • WP_Object_Cache (默认): 这是 WordPress 自带的一个简单的对象缓存实现,它将数据存储在 PHP 的全局变量中。 这种缓存方式的性能相对较低,但在没有其他缓存插件的情况下,可以提供一定的性能提升。
  • Memcached: 这是一个高性能的分布式内存对象缓存系统。 WordPress 可以通过 Memcached 客户端连接到 Memcached 服务器,并将数据存储在 Memcached 服务器的内存中。 Memcached 的性能非常高,可以显著提高 WordPress 的性能。
  • Redis: 这是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息代理。 Redis 的性能也非常高,并且提供了丰富的数据结构,可以满足各种缓存需求。

对象缓存如何提高性能?

  • 减少数据库查询: 对象缓存可以将数据库查询结果存储在内存中,避免重复查询数据库。
  • 减少计算量: 对象缓存可以将计算结果存储在内存中,避免重复计算。
  • 提高响应速度: 从内存中获取数据的速度比从数据库中获取数据的速度快得多,因此可以显著提高网站的响应速度。

get_transient() 函数中,对象缓存的作用是:

  1. 缓存瞬态的值: get_transient() 函数会将从 wp_options 表中获取的瞬态值存储在对象缓存中。
  2. 避免重复查询数据库: 下次访问同一个瞬态时,get_transient() 函数会首先从对象缓存中获取瞬态的值。 如果对象缓存命中,则可以直接返回瞬态的值,而无需再次查询 wp_options 表。
  3. 加速过期判断: 虽然过期判断仍然需要从数据库获取过期时间,但是大大减少了值本身的获取次数,也降低了数据库压力。

五、瞬态的注意事项

在使用瞬态时,需要注意以下几点:

  1. 瞬态名称的唯一性: 瞬态名称必须是唯一的,否则可能会导致数据冲突。
  2. 过期时间的合理性: 过期时间应该根据实际情况进行设置。 如果过期时间太短,则会导致缓存失效频繁,无法发挥缓存的作用。 如果过期时间太长,则可能会导致数据不一致。
  3. 数据大小的限制: wp_options 表的 option_value 字段的数据类型为 longtext,可以存储较大的数据。 但是,为了避免影响性能,建议尽量控制瞬态数据的大小。
  4. 对象缓存的配置: 为了充分发挥瞬态的性能优势,建议配置一个高性能的对象缓存系统,例如 Memcached 或 Redis。
  5. 自动加载的控制: 只有在WordPress初始化时就需要用到的瞬态,才应该设置autoloadyes,否则应该设置为no, 避免加载不必要的选项,优化性能。

六、总结

今天,我们深入分析了 WordPress get_transient() 函数的源码,了解了它如何处理过期缓存以及与 wp_options 表的交互。 总结一下:

  • get_transient() 函数用于从 WordPress 数据库中检索瞬态值。
  • get_transient() 函数通过比较当前时间戳和过期时间戳来判断缓存是否过期。
  • get_transient()set_transient()delete_transient() 函数使用 get_option()update_option()delete_option() 函数与 wp_options 表进行交互。
  • 对象缓存可以显著提高 get_transient() 函数的性能,减少数据库查询和计算量。

希望今天的讲座能够帮助大家更好地理解 WordPress 的缓存机制,并能够更加灵活地使用瞬态来优化网站性能。

好了,今天的分享就到这里。 感谢大家的聆听! 如果大家有什么问题,欢迎随时提问。 下次再见!

发表回复

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