Skip to content

Integer类型

概述

Integer(整数)类型是MongoDB中用于存储整数值的基本数据类型。MongoDB支持两种整数类型:32位整数(Int32)和64位整数(Int64/Long)。整数类型在计数器、ID、数量统计、年龄等场景中广泛应用,是数值计算的基础数据类型。

理解整数类型的范围、存储机制和最佳实践,对于避免数值溢出、优化存储空间和确保数据准确性至关重要。本章节将全面介绍MongoDB中整数类型的使用方法和注意事项。

基本概念

整数类型分类

MongoDB支持以下整数类型:

1. Int32(32位整数)

  • 范围:-2,147,483,648 到 2,147,483,647
  • 存储空间:4字节
  • 适用场景:小范围数值、计数器、年龄等

2. Int64/Long(64位整数)

  • 范围:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
  • 存储空间:8字节
  • 适用场景:大数值、时间戳、唯一ID等

3. 自动类型选择

  • MongoDB根据数值大小自动选择Int32或Int64
  • PHP驱动自动处理类型转换

整数类型语法

php
<?php
// 场景说明:演示MongoDB整数类型的基本语法和使用方式

// 1. 连接MongoDB数据库
$client = new MongoDB\Client("mongodb://localhost:27017");
$database = $client->selectDatabase("testdb");
$collection = $database->selectCollection("integer_examples");

// 2. 插入不同类型的整数数据
$document = [
    'small_int' => 100,                                    // 小整数(自动存储为Int32)
    'max_int32' => 2147483647,                            // Int32最大值
    'min_int32' => -2147483648,                           // Int32最小值
    'large_int' => 9223372036854775807,                   // Int64最大值
    'negative_int' => -100,                               // 负整数
    'zero' => 0,                                          // 零值
    'counter' => 1,                                       // 计数器
    'age' => 25,                                          // 年龄
    'quantity' => 1000                                    // 数量
];

// 关键行注释:插入包含各种整数类型的文档
$result = $collection->insertOne($document);
echo "插入成功,文档ID: " . $result->getInsertedId() . "\n";

// 3. 整数查询操作
// 精确匹配
$exactMatch = $collection->findOne(['age' => 25]);
echo "精确匹配结果: " . json_encode($exactMatch) . "\n";

// 范围查询
$rangeQuery = $collection->find([
    'age' => ['$gte' => 20, '$lte' => 30]
])->toArray();
echo "范围查询结果数量: " . count($rangeQuery) . "\n";

// 大于查询
$greaterThan = $collection->find([
    'quantity' => ['$gt' => 500]
])->toArray();
echo "大于查询结果数量: " . count($greaterThan) . "\n";

// 4. 整数运算
// 使用$inc操作符增加数值
$collection->updateOne(
    ['counter' => 1],
    ['$inc' => ['counter' => 1]]
);
echo "计数器已增加\n";

// 运行结果展示:
// 插入成功,文档ID: 507f1f77bcf86cd799439011
// 精确匹配结果: {"_id":"507f1f77bcf86cd799439011","age":25,...}
// 范围查询结果数量: 1
// 大于查询结果数量: 1
// 计数器已增加
?>

常见改法对比

php
<?php
// 错误示例:整数溢出
$overflow = 2147483647 + 1;  // 错误:可能溢出
$collection->insertOne(['value' => $overflow]);

// 正确示例:使用安全的整数运算
$safeValue = gmp_add('2147483647', '1');
$collection->insertOne(['value' => (int)$safeValue]);

// 错误示例:类型混淆
$collection->insertOne(['id' => '12345']);  // 错误:字符串而非整数
$result = $collection->findOne(['id' => 12345]);  // 查询不到

// 正确示例:确保整数类型
$collection->insertOne(['id' => (int)'12345']);
$result = $collection->findOne(['id' => 12345]);  // 查询成功
?>

整数类型规范

1. 类型选择规范

  • 优先使用Int32节省存储空间
  • 超过Int32范围时使用Int64
  • 时间戳使用Int64

2. 存储规范

  • 保持字段类型一致性
  • 避免字符串和整数混用
  • 使用合适的数值范围

3. 查询规范

  • 为常用查询字段创建索引
  • 使用范围查询优化性能
  • 注意整数比较的精度

原理深度解析

整数存储机制

MongoDB使用BSON格式存储整数,存储结构包含:

Int32存储结构

[类型标识(1字节)] + [整数值(4字节)]

Int64存储结构

[类型标识(1字节)] + [整数值(8字节)]
php
<?php
// 场景说明:深入分析整数的存储机制和类型选择

class IntegerStorageAnalyzer {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 分析整数类型选择
    public function analyzeIntegerTypes() {
        $collection = $this->database->selectCollection('integer_types');
        
        $testCases = [
            'small_positive' => 100,
            'small_negative' => -100,
            'int32_max' => 2147483647,
            'int32_min' => -2147483648,
            'int64_small' => 2147483648,
            'int64_large' => 9223372036854775807
        ];
        
        foreach ($testCases as $name => $value) {
            $collection->insertOne([
                'name' => $name,
                'value' => $value,
                'php_type' => gettype($value)
            ]);
        }
        
        // 关键行注释:分析每个值的存储类型
        $analysis = [];
        foreach ($testCases as $name => $value) {
            $analysis[$name] = [
                'value' => $value,
                'range' => $this->getIntegerRange($value),
                'storage_bytes' => $this->getStorageBytes($value),
                'recommended_type' => $this->getRecommendedType($value)
            ];
        }
        
        return $analysis;
    }
    
    // 获取整数范围
    private function getIntegerRange($value) {
        if ($value >= -2147483648 && $value <= 2147483647) {
            return 'Int32 range';
        } else {
            return 'Int64 range';
        }
    }
    
    // 获取存储字节数
    private function getStorageBytes($value) {
        if ($value >= -2147483648 && $value <= 2147483647) {
            return 4;
        } else {
            return 8;
        }
    }
    
    // 获取推荐类型
    private function getRecommendedType($value) {
        if ($value >= -2147483648 && $value <= 2147483647) {
            return 'Int32 (节省空间)';
        } else {
            return 'Int64 (必需)';
        }
    }
}

// 使用示例
$analyzer = new IntegerStorageAnalyzer('testdb');
$analysis = $analyzer->analyzeIntegerTypes();
print_r($analysis);
?>

整数运算原理

php
<?php
// 场景说明:演示整数的运算机制和注意事项

class IntegerOperations {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 原子性递增操作
    public function atomicIncrement($collectionName, $filter, $field, $value = 1) {
        $collection = $this->database->selectCollection($collectionName);
        
        // 关键行注释:使用$inc操作符实现原子性递增
        $result = $collection->findOneAndUpdate(
            $filter,
            ['$inc' => [$field => $value]],
            ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
        );
        
        return $result;
    }
    
    // 批量更新数值
    public function batchUpdate($collectionName, $updates) {
        $collection = $this->database->selectCollection($collectionName);
        
        $bulk = new MongoDB\Driver\BulkWrite;
        
        foreach ($updates as $update) {
            $bulk->update(
                $update['filter'],
                $update['update'],
                ['multi' => $update['multi'] ?? false]
            );
        }
        
        $manager = $this->database->getManager();
        $result = $manager->executeBulkWrite(
            $this->database->getDatabaseName() . '.' . $collectionName,
            $bulk
        );
        
        return [
            'matched' => $result->getMatchedCount(),
            'modified' => $result->getModifiedCount()
        ];
    }
    
    // 数值聚合操作
    public function aggregateNumbers($collectionName) {
        $collection = $this->database->selectCollection($collectionName);
        
        $pipeline = [
            [
                '$group' => [
                    '_id' => null,
                    'total' => ['$sum' => '$value'],
                    'average' => ['$avg' => '$value'],
                    'max' => ['$max' => '$value'],
                    'min' => ['$min' => '$value'],
                    'count' => ['$sum' => 1]
                ]
            ]
        ];
        
        return $collection->aggregate($pipeline)->toArray();
    }
}

// 使用示例
$ops = new IntegerOperations('testdb');

// 插入测试数据
$collection = $ops->database->selectCollection('counters');
$collection->insertOne(['name' => 'page_views', 'value' => 0]);

// 原子递增
for ($i = 0; $i < 5; $i++) {
    $result = $ops->atomicIncrement('counters', ['name' => 'page_views'], 'value');
    echo "当前值: " . $result['value'] . "\n";
}
?>

常见错误与踩坑点

错误1:整数溢出

错误表现

  • 数值超出范围导致数据错误
  • 计算结果不正确
  • 查询结果异常

产生原因

  • 未检查数值范围
  • 运算结果超出类型范围
  • 使用不合适的数据类型

解决方案

php
<?php
// 场景说明:演示整数溢出问题的正确处理

class IntegerOverflowHandler {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 错误示例:未检查溢出
    public function wrongOverflowExample() {
        $collection = $this->database->selectCollection('overflow_errors');
        
        $maxInt32 = 2147483647;
        $overflow = $maxInt32 + 1;  // 错误:可能溢出
        
        try {
            $collection->insertOne(['value' => $overflow]);
            echo "错误:未检测到溢出\n";
        } catch (Exception $e) {
            echo "捕获异常: " . $e->getMessage() . "\n";
        }
    }
    
    // 正确示例:安全处理大整数
    public function correctOverflowExample() {
        $collection = $this->database->selectCollection('overflow_correct');
        
        // 方法1:使用GMP扩展处理大整数
        $largeValue = gmp_add('2147483647', '1');
        $collection->insertOne([
            'value' => (string)$largeValue,
            'type' => 'gmp'
        ]);
        
        // 方法2:使用字符串存储
        $collection->insertOne([
            'value' => '9223372036854775807',
            'type' => 'string'
        ]);
        
        // 方法3:使用Decimal128
        $collection->insertOne([
            'value' => new MongoDB\BSON\Decimal128('9223372036854775807'),
            'type' => 'decimal128'
        ]);
        
        echo "正确:使用安全方式处理大整数\n";
    }
    
    // 安全的整数运算
    public function safeIntegerOperation($a, $b, $operation) {
        switch ($operation) {
            case 'add':
                $result = gmp_add($a, $b);
                break;
            case 'sub':
                $result = gmp_sub($a, $b);
                break;
            case 'mul':
                $result = gmp_mul($a, $b);
                break;
            default:
                throw new Exception("未知操作");
        }
        
        return gmp_strval($result);
    }
}

// 使用示例
$handler = new IntegerOverflowHandler('testdb');
$handler->wrongOverflowExample();
$handler->correctOverflowExample();
?>

错误2:类型混淆

错误表现

  • 字符串数字与整数混淆
  • 查询不到预期结果
  • 类型比较错误

产生原因

  • 未进行类型转换
  • 数据来源不一致
  • 缺少类型验证

解决方案

php
<?php
// 场景说明:演示整数类型混淆的正确处理

class TypeConfusionHandler {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 错误示例:类型混淆
    public function wrongTypeExample() {
        $collection = $this->database->selectCollection('type_confusion');
        
        // 插入字符串类型的数字
        $collection->insertOne(['id' => '12345']);
        
        // 错误:使用整数查询字符串字段
        $result = $collection->findOne(['id' => 12345]);
        
        if (!$result) {
            echo "错误:类型不匹配导致查询失败\n";
        }
    }
    
    // 正确示例:统一类型
    public function correctTypeExample() {
        $collection = $this->database->selectCollection('type_correct');
        
        // 确保整数类型
        $id = (int)'12345';
        $collection->insertOne(['id' => $id]);
        
        // 使用相同类型查询
        $result = $collection->findOne(['id' => 12345]);
        
        if ($result) {
            echo "正确:类型匹配查询成功\n";
        }
    }
    
    // 类型转换工具
    public function ensureInteger($value) {
        if (is_string($value)) {
            return (int)$value;
        } elseif (is_float($value)) {
            return (int)round($value);
        } elseif (is_bool($value)) {
            return $value ? 1 : 0;
        } elseif (is_null($value)) {
            return 0;
        }
        
        return (int)$value;
    }
}

// 使用示例
$handler = new TypeConfusionHandler('testdb');
$handler->wrongTypeExample();
$handler->correctTypeExample();
?>

错误3:浮点数转整数精度丢失

错误表现

  • 浮点数转整数时丢失小数部分
  • 计算结果不准确
  • 数据精度问题

产生原因

  • 直接截断而非四舍五入
  • 未考虑精度要求
  • 不当的类型转换

解决方案

php
<?php
// 场景说明:演示浮点数转整数的正确处理

class FloatToIntegerHandler {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 错误示例:精度丢失
    public function wrongPrecisionExample() {
        $collection = $this->database->selectCollection('precision_errors');
        
        $floatValue = 99.99;
        
        // 错误:直接截断
        $truncated = (int)$floatValue;
        
        $collection->insertOne([
            'original' => $floatValue,
            'converted' => $truncated,
            'error' => '精度丢失'
        ]);
        
        echo "错误:99.99转换为{$truncated},精度丢失\n";
    }
    
    // 正确示例:保留精度
    public function correctPrecisionExample() {
        $collection = $this->database->selectCollection('precision_correct');
        
        $floatValue = 99.99;
        
        // 方法1:四舍五入
        $rounded = (int)round($floatValue);
        
        // 方法2:向上取整
        $ceiled = (int)ceil($floatValue);
        
        // 方法3:向下取整
        $floored = (int)floor($floatValue);
        
        // 方法4:使用Decimal128保留精度
        $decimal = new MongoDB\BSON\Decimal128('99.99');
        
        $collection->insertOne([
            'original' => $floatValue,
            'rounded' => $rounded,
            'ceiled' => $ceiled,
            'floored' => $floored,
            'decimal' => $decimal
        ]);
        
        echo "正确:使用合适的方法处理精度\n";
    }
}

// 使用示例
$handler = new FloatToIntegerHandler('testdb');
$handler->wrongPrecisionExample();
$handler->correctPrecisionExample();
?>

常见应用场景

场景1:计数器系统

场景描述:实现高并发场景下的计数器功能。

使用方法

  • 使用$inc操作符实现原子递增
  • 创建索引提高性能
  • 处理并发冲突

示例代码

php
<?php
// 场景说明:高并发计数器系统

class CounterSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 初始化计数器
    public function initializeCounter($name, $initialValue = 0) {
        $collection = $this->database->selectCollection('counters');
        
        $collection->insertOne([
            'name' => $name,
            'value' => $initialValue,
            'created_at' => new MongoDB\BSON\UTCDateTime()
        ]);
    }
    
    // 原子递增
    public function increment($name, $step = 1) {
        $collection = $this->database->selectCollection('counters');
        
        // 关键行注释:使用findOneAndUpdate实现原子递增
        $result = $collection->findOneAndUpdate(
            ['name' => $name],
            ['$inc' => ['value' => $step]],
            ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
        );
        
        return $result['value'];
    }
    
    // 获取计数器值
    public function getCounter($name) {
        $collection = $this->database->selectCollection('counters');
        
        $result = $collection->findOne(['name' => $name]);
        
        return $result ? $result['value'] : null;
    }
    
    // 重置计数器
    public function resetCounter($name, $value = 0) {
        $collection = $this->database->selectCollection('counters');
        
        $collection->updateOne(
            ['name' => $name],
            ['$set' => ['value' => $value]]
        );
    }
}

// 使用示例
$counter = new CounterSystem('counter_db');

// 初始化
$counter->initializeCounter('page_views', 0);

// 并发递增
for ($i = 0; $i < 10; $i++) {
    $value = $counter->increment('page_views');
    echo "当前计数: $value\n";
}

// 获取最终值
$finalValue = $counter->getCounter('page_views');
echo "最终计数: $finalValue\n";
?>

场景2:分页系统

场景描述:实现高效的分页查询功能。

示例代码

php
<?php
// 场景说明:分页系统实现

class PaginationSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 创建测试数据
    public function createTestData() {
        $collection = $this->database->selectCollection('products');
        
        $products = [];
        for ($i = 1; $i <= 100; $i++) {
            $products[] = [
                'product_id' => $i,
                'name' => "Product $i",
                'price' => rand(10, 1000),
                'stock' => rand(0, 100)
            ];
        }
        
        $collection->insertMany($products);
        $collection->createIndex(['product_id' => 1]);
    }
    
    // 传统分页
    public function paginate($page = 1, $perPage = 10) {
        $collection = $this->database->selectCollection('products');
        
        $skip = ($page - 1) * $perPage;
        $total = $collection->countDocuments();
        $totalPages = ceil($total / $perPage);
        
        $results = $collection->find([], [
            'skip' => $skip,
            'limit' => $perPage,
            'sort' => ['product_id' => 1]
        ])->toArray();
        
        return [
            'current_page' => $page,
            'per_page' => $perPage,
            'total' => $total,
            'total_pages' => $totalPages,
            'items' => $results
        ];
    }
    
    // 基于游标的分页
    public function cursorPaginate($lastId = null, $limit = 10) {
        $collection = $this->database->selectCollection('products');
        
        $query = $lastId ? ['product_id' => ['$gt' => $lastId]] : [];
        
        $results = $collection->find($query, [
            'limit' => $limit,
            'sort' => ['product_id' => 1]
        ])->toArray();
        
        $nextCursor = count($results) === $limit ? end($results)['product_id'] : null;
        
        return [
            'items' => $results,
            'next_cursor' => $nextCursor,
            'has_more' => $nextCursor !== null
        ];
    }
}

// 使用示例
$pagination = new PaginationSystem('pagination_db');
$pagination->createTestData();

// 传统分页
$page1 = $pagination->paginate(1, 10);
echo "第1页: " . count($page1['items']) . " 条记录\n";

// 游标分页
$cursor1 = $pagination->cursorPaginate(null, 10);
echo "游标分页: " . count($cursor1['items']) . " 条记录\n";
?>

场景3:统计数据

场景描述:实现数据的统计和聚合分析。

示例代码

php
<?php
// 场景说明:统计数据聚合

class StatisticsSystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 创建销售数据
    public function createSalesData() {
        $collection = $this->database->selectCollection('sales');
        
        $sales = [];
        for ($i = 0; $i < 100; $i++) {
            $sales[] = [
                'product_id' => rand(1, 10),
                'quantity' => rand(1, 100),
                'amount' => rand(100, 10000),
                'date' => new MongoDB\BSON\UTCDateTime()
            ];
        }
        
        $collection->insertMany($sales);
    }
    
    // 统计分析
    public function analyze() {
        $collection = $this->database->selectCollection('sales');
        
        $pipeline = [
            [
                '$group' => [
                    '_id' => '$product_id',
                    'total_quantity' => ['$sum' => '$quantity'],
                    'total_amount' => ['$sum' => '$amount'],
                    'avg_quantity' => ['$avg' => '$quantity'],
                    'count' => ['$sum' => 1]
                ]
            ],
            [
                '$sort' => ['total_amount' => -1]
            ]
        ];
        
        return $collection->aggregate($pipeline)->toArray();
    }
}

// 使用示例
$stats = new StatisticsSystem('stats_db');
$stats->createSalesData();
$analysis = $stats->analyze();
print_r($analysis);
?>

企业级进阶应用场景

场景1:分布式ID生成器

场景描述:实现分布式环境下的唯一ID生成。

示例代码

php
<?php
// 场景说明:分布式ID生成器

class DistributedIdGenerator {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 初始化序列
    public function initializeSequence($name, $start = 1) {
        $collection = $this->database->selectCollection('sequences');
        
        $collection->insertOne([
            'name' => $name,
            'value' => $start
        ]);
    }
    
    // 生成唯一ID
    public function generateId($prefix = '') {
        $collection = $this->database->selectCollection('sequences');
        
        // 关键行注释:原子递增获取唯一序列号
        $result = $collection->findOneAndUpdate(
            ['name' => 'global_id'],
            ['$inc' => ['value' => 1]],
            [
                'returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_BEFORE,
                'upsert' => true
            ]
        );
        
        $id = $result['value'];
        
        return $prefix . str_pad($id, 10, '0', STR_PAD_LEFT);
    }
    
    // 批量生成ID
    public function generateBatch($count, $prefix = '') {
        $ids = [];
        
        for ($i = 0; $i < $count; $i++) {
            $ids[] = $this->generateId($prefix);
        }
        
        return $ids;
    }
}

// 使用示例
$idGen = new DistributedIdGenerator('id_gen_db');
$idGen->initializeSequence('global_id', 1);

// 生成ID
for ($i = 0; $i < 5; $i++) {
    $id = $idGen->generateId('ORD');
    echo "生成ID: $id\n";
}
?>

场景2:库存管理系统

场景描述:实现高并发库存扣减和恢复。

示例代码

php
<?php
// 场景说明:库存管理系统

class InventorySystem {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 初始化库存
    public function initializeInventory($productId, $quantity) {
        $collection = $this->database->selectCollection('inventory');
        
        $collection->insertOne([
            'product_id' => $productId,
            'quantity' => $quantity,
            'reserved' => 0,
            'available' => $quantity
        ]);
    }
    
    // 扣减库存
    public function deductInventory($productId, $quantity) {
        $collection = $this->database->selectCollection('inventory');
        
        // 关键行注释:使用$inc原子操作扣减库存
        $result = $collection->findOneAndUpdate(
            [
                'product_id' => $productId,
                'available' => ['$gte' => $quantity]
            ],
            [
                '$inc' => [
                    'quantity' => -$quantity,
                    'available' => -$quantity
                ]
            ],
            ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
        );
        
        if (!$result) {
            throw new Exception("库存不足");
        }
        
        return $result;
    }
    
    // 恢复库存
    public function restoreInventory($productId, $quantity) {
        $collection = $this->database->selectCollection('inventory');
        
        $result = $collection->findOneAndUpdate(
            ['product_id' => $productId],
            [
                '$inc' => [
                    'quantity' => $quantity,
                    'available' => $quantity
                ]
            ],
            ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
        );
        
        return $result;
    }
    
    // 查询库存
    public function getInventory($productId) {
        $collection = $this->database->selectCollection('inventory');
        
        return $collection->findOne(['product_id' => $productId]);
    }
}

// 使用示例
$inventory = new InventorySystem('inventory_db');
$inventory->initializeInventory('PROD001', 100);

// 扣减库存
try {
    $result = $inventory->deductInventory('PROD001', 10);
    echo "扣减成功,剩余库存: " . $result['available'] . "\n";
} catch (Exception $e) {
    echo "扣减失败: " . $e->getMessage() . "\n";
}

// 查询库存
$current = $inventory->getInventory('PROD001');
print_r($current);
?>

行业最佳实践

实践1:选择合适的整数类型

实践内容

  • 根据数值范围选择Int32或Int64
  • 考虑未来数据增长
  • 平衡存储空间和性能

推荐理由

  • 优化存储空间
  • 提高查询性能
  • 避免溢出问题
php
<?php
// 好的实践:根据范围选择类型
class IntegerTypeSelector {
    public static function select($value) {
        if ($value >= -2147483648 && $value <= 2147483647) {
            return 'Int32';
        }
        return 'Int64';
    }
}

// 使用示例
$values = [100, 2147483647, 2147483648];
foreach ($values as $value) {
    echo "$value: " . IntegerTypeSelector::select($value) . "\n";
}
?>

实践2:使用原子操作

实践内容

  • 使用$inc进行原子递增
  • 使用findOneAndUpdate避免竞态
  • 处理并发冲突

推荐理由

  • 保证数据一致性
  • 避免竞态条件
  • 提高并发性能
php
<?php
// 好的实践:原子操作
class AtomicOperations {
    private $collection;
    
    public function __construct($collection) {
        $this->collection = $collection;
    }
    
    // 原子递增
    public function atomicIncrement($id, $field, $value = 1) {
        return $this->collection->findOneAndUpdate(
            ['_id' => $id],
            ['$inc' => [$field => $value]],
            ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
        );
    }
}
?>

实践3:创建合适的索引

实践内容

  • 为常用查询字段创建索引
  • 使用复合索引优化多字段查询
  • 定期监控索引使用情况

推荐理由

  • 提高查询性能
  • 减少资源消耗
  • 优化用户体验
php
<?php
// 好的实践:创建索引
$collection->createIndex(['user_id' => 1]);
$collection->createIndex(['created_at' => -1]);
$collection->createIndex(['user_id' => 1, 'created_at' => -1]);
?>

常见问题答疑(FAQ)

问题1:如何选择Int32还是Int64?

问题描述:在什么情况下应该使用Int32,什么情况下使用Int64?

回答内容

根据数值范围和应用场景选择:

php
<?php
// 场景说明:整数类型选择指南

class IntegerTypeGuide {
    public static function selectType($value, $context = []) {
        $int32Max = 2147483647;
        $int32Min = -2147483648;
        
        // 检查是否在Int32范围内
        if ($value >= $int32Min && $value <= $int32Max) {
            // 考虑未来增长
            if (isset($context['growth_rate'])) {
                $projectedValue = $value * $context['growth_rate'];
                if ($projectedValue > $int32Max) {
                    return 'Int64 (考虑未来增长)';
                }
            }
            
            return 'Int32 (节省空间)';
        }
        
        return 'Int64 (必需)';
    }
    
    // 常见场景建议
    public static function getScenarioRecommendations() {
        return [
            'age' => 'Int32 (范围0-150)',
            'quantity' => 'Int32 (一般数量)',
            'price_cents' => 'Int32 (价格以分为单位)',
            'timestamp' => 'Int64 (时间戳)',
            'user_id' => 'Int64 (大量用户)',
            'view_count' => 'Int64 (可能很大)'
        ];
    }
}

// 使用示例
$guide = new IntegerTypeGuide();
echo "选择建议: " . $guide->selectType(1000) . "\n";
print_r($guide->getScenarioRecommendations());
?>

问题2:如何处理大整数运算?

问题描述:如何安全地进行大整数的加减乘除运算?

回答内容

使用GMP扩展或字符串处理:

php
<?php
// 场景说明:大整数运算

class LargeIntegerOperations {
    // 使用GMP扩展
    public static function safeAdd($a, $b) {
        $result = gmp_add($a, $b);
        return gmp_strval($result);
    }
    
    public static function safeSub($a, $b) {
        $result = gmp_sub($a, $b);
        return gmp_strval($result);
    }
    
    public static function safeMul($a, $b) {
        $result = gmp_mul($a, $b);
        return gmp_strval($result);
    }
    
    public static function safeDiv($a, $b) {
        $result = gmp_div($a, $b);
        return gmp_strval($result);
    }
}

// 使用示例
$a = '9223372036854775807';
$b = '12345678901234567890';

echo "加法: " . LargeIntegerOperations::safeAdd($a, $b) . "\n";
echo "乘法: " . LargeIntegerOperations::safeMul($a, $b) . "\n";
?>

问题3:如何优化整数查询性能?

问题描述:如何提高整数字段的查询效率?

回答内容

通过索引和查询优化:

php
<?php
// 场景说明:整数查询优化

class IntegerQueryOptimization {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    // 创建优化的索引
    public function createOptimizedIndexes($collectionName) {
        $collection = $this->database->selectCollection($collectionName);
        
        // 单字段索引
        $collection->createIndex(['user_id' => 1]);
        
        // 复合索引
        $collection->createIndex(['status' => 1, 'created_at' => -1]);
        
        // 范围查询优化
        $collection->createIndex(['age' => 1]);
    }
    
    // 优化的范围查询
    public function optimizedRangeQuery($collectionName, $field, $min, $max) {
        $collection = $this->database->selectCollection($collectionName);
        
        return $collection->find([
            $field => ['$gte' => $min, '$lte' => $max]
        ], [
            'sort' => [$field => 1]
        ])->toArray();
    }
}

// 使用示例
$optimization = new IntegerQueryOptimization('testdb');
$optimization->createOptimizedIndexes('users');
$results = $optimization->optimizedRangeQuery('users', 'age', 20, 30);
echo "查询结果数量: " . count($results) . "\n";
?>

实战练习

练习1:基础练习 - 计数器实现

解题思路

  1. 创建计数器集合
  2. 实现原子递增功能
  3. 处理并发场景

常见误区

  • 未使用原子操作
  • 忽略并发问题
  • 未创建索引

分步提示

  1. 初始化计数器
  2. 使用$inc操作符
  3. 测试并发场景

参考代码

php
<?php
// 练习1:计数器实现

class CounterExercise {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function run() {
        $collection = $this->database->selectCollection('exercise_counter');
        $collection->drop();
        
        // 步骤1:初始化计数器
        $collection->insertOne([
            'name' => 'page_views',
            'value' => 0
        ]);
        
        // 步骤2:原子递增
        for ($i = 0; $i < 10; $i++) {
            $result = $collection->findOneAndUpdate(
                ['name' => 'page_views'],
                ['$inc' => ['value' => 1]],
                ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
            );
            echo "当前值: " . $result['value'] . "\n";
        }
        
        // 步骤3:查询最终值
        $final = $collection->findOne(['name' => 'page_views']);
        echo "最终值: " . $final['value'] . "\n";
    }
}

// 运行练习
$exercise = new CounterExercise('exercise_db');
$exercise->run();
?>

练习2:进阶练习 - 库存管理

解题思路

  1. 设计库存数据结构
  2. 实现原子扣减
  3. 处理库存不足

常见误区

  • 未检查库存充足性
  • 未使用原子操作
  • 未处理并发冲突

参考代码

php
<?php
// 练习2:库存管理

class InventoryExercise {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function run() {
        $collection = $this->database->selectCollection('exercise_inventory');
        $collection->drop();
        
        // 初始化库存
        $collection->insertOne([
            'product_id' => 'PROD001',
            'quantity' => 100
        ]);
        
        // 扣减库存
        try {
            $result = $collection->findOneAndUpdate(
                [
                    'product_id' => 'PROD001',
                    'quantity' => ['$gte' => 10]
                ],
                ['$inc' => ['quantity' => -10]],
                ['returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER]
            );
            
            if ($result) {
                echo "扣减成功,剩余: " . $result['quantity'] . "\n";
            } else {
                echo "库存不足\n";
            }
        } catch (Exception $e) {
            echo "错误: " . $e->getMessage() . "\n";
        }
    }
}

// 运行练习
$exercise = new InventoryExercise('exercise_db');
$exercise->run();
?>

练习3:挑战练习 - 分布式ID生成

解题思路

  1. 设计ID生成策略
  2. 实现原子序列
  3. 处理高并发

参考代码

php
<?php
// 练习3:分布式ID生成

class IdGeneratorExercise {
    private $database;
    
    public function __construct($databaseName) {
        $client = new MongoDB\Client("mongodb://localhost:27017");
        $this->database = $client->selectDatabase($databaseName);
    }
    
    public function run() {
        $collection = $this->database->selectCollection('exercise_sequences');
        $collection->drop();
        
        // 生成唯一ID
        for ($i = 0; $i < 10; $i++) {
            $result = $collection->findOneAndUpdate(
                ['name' => 'order_id'],
                ['$inc' => ['value' => 1]],
                [
                    'returnDocument' => MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_BEFORE,
                    'upsert' => true
                ]
            );
            
            $id = $result ? $result['value'] : 0;
            $orderId = 'ORD' . str_pad($id, 10, '0', STR_PAD_LEFT);
            echo "生成订单ID: $orderId\n";
        }
    }
}

// 运行练习
$exercise = new IdGeneratorExercise('exercise_db');
$exercise->run();
?>

知识点总结

核心要点

  1. 整数类型分类

    • Int32:范围-2^31到2^31-1,占用4字节
    • Int64:范围-2^63到2^63-1,占用8字节
    • 自动类型选择机制
  2. 存储机制

    • BSON格式存储
    • 固定字节数存储
    • 高效的数值运算
  3. 原子操作

    • $inc操作符实现原子递增
    • findOneAndUpdate避免竞态
    • 支持高并发场景
  4. 索引优化

    • 整数字段索引效率高
    • 支持范围查询优化
    • 复合索引提升性能

易错点回顾

  1. 整数溢出

    • 超出类型范围
    • 运算结果溢出
    • 未检查数值范围
  2. 类型混淆

    • 字符串与整数混用
    • 类型转换错误
    • 查询类型不匹配
  3. 精度问题

    • 浮点数转整数精度丢失
    • 不当的类型转换
    • 未考虑精度要求

拓展参考资料

官方文档链接

进阶学习路径建议

本知识点承接:《MongoDB基础概念》→《数据类型概述》

后续延伸至:《Double类型》→《Decimal128类型》→《数值运算优化》

建议学习顺序

  1. MongoDB基础概念
  2. 数据类型概述
  3. Integer类型(本章节)
  4. Double类型
  5. Decimal128类型
  6. 数值运算优化