在图书管理系统中处理并发问题,主要是为了避免多个用户同时对同一本图书进行操作(如同时更新、删除)时产生的数据不一致问题。下面我们从几个方面来优化之前的图书管理控制器以处理并发情况。
1. 使用数据库乐观锁
乐观锁是一种并发控制机制,它假设在大多数情况下不会发生冲突,只有在更新数据时才检查数据是否被其他事务修改过。我们可以在 books 表中添加一个 version 字段,用于记录数据的版本号。
2. 创建数据库表
假设你使用 MySQL 数据库,创建一个名为 books 的表,用于存储图书信息:
CREATE TABLE `books` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`author` varchar(255) NOT NULL,
`price` decimal(10, 2) NOT NULL,
`version` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 创建模型
在 app/model 目录下创建 Book.php 模型文件:
<?php
namespace app\model;
use think\Model;
class Book extends Model
{
// 表名
protected $name = 'books';
// 乐观锁字段
protected $optimisticLock = 'version';
}
3. 创建控制器
在 app/controller 目录下创建 BookController.php 控制器文件:
<?php
namespace app\controller;
use app\model\Book;
use think\facade\Cache;
use think\facade\Db;
class BookController
{
/**
* 添加图书
*/
public function addBook()
{
$data = request()->post();
$book = new Book();
$book->title = $data['title'];
$book->author = $data['author'];
$book->price = $data['price'];
if ($book->save()) {
// 新增图书后清除缓存
Cache::store('redis')->rm('books_list');
return json(['code' => 200, 'msg' => '图书添加成功']);
} else {
return json(['code' => 500, 'msg' => '图书添加失败']);
}
}
/**
* 获取图书列表
*/
public function getBooks()
{
$cacheKey = 'books_list';
$books = Cache::store('redis')->get($cacheKey);
if (!$books) {
$books = Book::select();
Cache::store('redis')->set($cacheKey, $books, 3600); // 缓存 1 小时
}
return json(['code' => 200, 'msg' => '获取图书列表成功', 'data' => $books]);
}
/**
* 更新图书信息
*/
public function updateBook()
{
$id = request()->post('id');
$data = request()->post();
Db::startTrans();
try {
$book = Book::find($id);
if ($book) {
$book->title = $data['title'];
$book->author = $data['author'];
$book->price = $data['price'];
if ($book->save()) {
// 更新图书后清除缓存
Cache::store('redis')->rm('books_list');
Db::commit();
return json(['code' => 200, 'msg' => '图书信息更新成功']);
} else {
Db::rollback();
return json(['code' => 500, 'msg' => '图书信息更新失败,可能数据已被其他事务修改']);
}
} else {
Db::rollback();
return json(['code' => 404, 'msg' => '未找到该图书']);
}
} catch (\Exception $e) {
Db::rollback();
return json(['code' => 500, 'msg' => '更新图书时发生错误:' . $e->getMessage()]);
}
}
/**
* 删除图书
*/
public function deleteBook()
{
$id = request()->post('id');
Db::startTrans();
try {
$book = Book::find($id);
if ($book) {
if ($book->delete()) {
// 删除图书后清除缓存
Cache::store('redis')->rm('books_list');
Db::commit();
return json(['code' => 200, 'msg' => '图书删除成功']);
} else {
Db::rollback();
return json(['code' => 500, 'msg' => '图书删除失败,可能数据已被其他事务修改']);
}
} else {
Db::rollback();
return json(['code' => 404, 'msg' => '未找到该图书']);
}
} catch (\Exception $e) {
Db::rollback();
return json(['code' => 500, 'msg' => '删除图书时发生错误:' . $e->getMessage()]);
}
}
}
4. 配置路由
在 app/route/route.php 中配置路由:
use think\facade\Route;
Route::post('add_book', 'BookController@addBook');
Route::get('get_books', 'BookController@getBooks');
Route::post('update_book', 'BookController@updateBook');
Route::post('delete_book', 'BookController@deleteBook');
*. Redis 分布式锁(可选)
如果系统并发量非常高,还可以使用 Redis 分布式锁来进一步控制并发访问。以下是一个简单的 Redis 分布式锁实现示例:
// ... 已有代码 ...
use think\facade\Cache;
// 获取 Redis 分布式锁
function getRedisLock($key, $expire = 10)
{
$redis = Cache::store('redis')->handler();
$lockKey = 'lock:' . $key;
$value = uniqid();
if ($redis->set($lockKey, $value, ['NX', 'EX' => $expire])) {
return $value;
}
return false;
}
// 释放 Redis 分布式锁
function releaseRedisLock($key, $value)
{
$redis = Cache::store('redis')->handler();
$lockKey = 'lock:' . $key;
if ($redis->get($lockKey) === $value) {
$redis->del($lockKey);
return true;
}
return false;
}
// 修改 updateBook 方法使用分布式锁
public function updateBook()
{
$id = request()->post('id');
$data = request()->post();
$lockValue = getRedisLock('book:' . $id);
if (!$lockValue) {
return json(['code' => 503, 'msg' => '当前图书正在被其他用户操作,请稍后再试']);
}
Db::startTrans();
try {
$book = Book::find($id);
if ($book) {
$book->title = $data['title'];
$book->author = $data['author'];
$book->price = $data['price'];
if ($book->save()) {
// 更新图书后清除缓存
Cache::store('redis')->rm('books_list');
Db::commit();
releaseRedisLock('book:' . $id, $lockValue);
return json(['code' => 200, 'msg' => '图书信息更新成功']);
} else {
Db::rollback();
releaseRedisLock('book:' . $id, $lockValue);
return json(['code' => 500, 'msg' => '图书信息更新失败,可能数据已被其他事务修改']);
}
} else {
Db::rollback();
releaseRedisLock('book:' . $id, $lockValue);
return json(['code' => 404, 'msg' => '未找到该图书']);
}
} catch (\Exception $e) {
Db::rollback();
releaseRedisLock('book:' . $id, $lockValue);
return json(['code' => 500, 'msg' => '更新图书时发生错误:' . $e->getMessage()]);
}
}
// ... 已有代码 ...
解释
乐观锁:通过在数据库表中添加 version 字段,在更新数据时检查版本号是否一致,若不一致则表示数据已被其他事务修改,更新失败。
Redis 分布式锁:在高并发场景下,使用 Redis 分布式锁可以确保同一时间只有一个用户能够对某本图书进行操作,避免数据冲突。
通过以上优化,可以有效处理图书管理系统中的并发问题。
免责申明:本站内容大部分来自互联网,部分来源于个人原创。仅供个人学习使用,本站不承担任何法律责任。如有侵权请联系删除!