假设订票的时候,好几个人同时进入,查看这张票是否售出,假如同时购买了这张票,那对于售票行业来说,可能就会发生低级错误。那么如何避免这类事情发生呢?
解决办法:
在一个人访问的时候,另外一个人不可以访问,将票锁住,锁完之后,再更新,让其他的线程来访问。
在C++/C中常见的锁分为两类:表锁,行锁
1、表锁:将整个表都锁柱,整张表都不可以访问 Innodb和MyISAM都可以
1.1、锁住表的读
其他人都不能读
lock table t_vedio read;
1.2、锁住表的写
其他人都不可以写,但是可以读
lock table t_vedio write;
1.2、解锁
unlock tables;
但是,它的缺点就是:假定一张的表里面有很多张票,例如从北京到陕西,北京到甘肃,北京到上海等票都在一个库里面,这个时候,如果你将整个表锁住了,但是他们之间又米有竞争关系,起始就是浪费了资源,其他线程都必须等一个操作完成之后才能进入下一个。所以表锁在很多情况下是没必要的,但是,Innodb和MyISAM都支持表锁。而表锁只适用于Innodb,支持事务的rollback。
2、行锁(事务)
select *from t_tickets XXX for update;
2.1、取票/查看票
//取票
my.StartTransaction();
bool LXMysql::StartTransaction()
{
//有一个start Transaction的接口,只需要调用另外一个接口,也就是把自动提交
return Query("set autocommit=0");
}
2.2、锁住表
select *from t_tickets where sold=0 order by id for update;
2.3、 购买这张票
10s之后这张票的状态置为1,也就是卖出了
//购买这张票
//模拟冲突 3s过后更新这张票
this_thread::sleep_for(10s);
2.4、更新表,将第一张票置为1,售出了,更新一下表
//更新
string id = rows[0][0].data;
//取出第一行的id号 找到了这张票
data["sold"] = "1";
string where = "where id=";
where += id;
//更新成功
cout << my.Update(data, "t_tickets", where) << endl;
2.5、提交事务
my.Commit();
my.StopTransaction();
bool LXMysql::StopTransaction()
{
return Query("set autocommit=1");
}
bool LXMysql::Commit()
{
return Query("commit");
}
3、演示:
3.1、假设现在数据库里的表都没有售出:
3.2、现在进来两个人来买票,找到你的代码的exe文件
启动两次exe
当不使用行表的时候,一张票被两个人购买,
select *from t_tickets where sold=0 order by id
使用行锁,起始也就是加了行锁for update;
根据时间顺序,购买不同的票,id=2的票被买走之后,顺次购买id=3的
select *from t_tickets where sold=0 order by id for update;