悲观锁代码java_悲观锁的代码实现如何编写?
悲觀鎖相信大家都不陌生了,之前說過了悲觀鎖的各種原理,這次我們就來聊聊悲觀鎖是如何實現的吧。
悲觀鎖,就跟它的名字意思一樣,它非常悲觀,它的機制就是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度,所以,在全部的數據處理過程中,它會把數據處于鎖定狀態。悲觀鎖的實現,會依賴數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。
一段執行邏輯加上悲觀鎖,不同線程同時執行時,只能有一個線程執行,其他的線程在入口處等待,直到鎖被釋放。
具體實現代碼:
1)環境:mysql + jdbctemplate
2)商品表 goods:DROP?TABLE?IF?EXISTS?`goods`;
CREATE?TABLE?`goods`(
`id`
int(11)?unsigned?NOT?NULL?AUTO_INCREMENT
,?`name`
varchar(100)?DEFAULT?NULL?COMMENT?'商品名稱'
,?`stock`
int(11)?unsigned?NOT?NULL?COMMENT?'商品庫存'
,?`version`
int(2)?DEFAULT?NULL?COMMENT?'版本號'
,?`token_time`
datetime?NOT?NULL?COMMENT?'樂觀鎖時間戳'
,?PRIMARY?KEY(`id`)
)?ENGINE?=?InnoDB?AUTO_INCREMENT?=?10?DEFAULT?CHARSET?=?utf8;
--?--?--?--?--?--?--?--?--?--?--?--?--?--?--
--Records?of?goods
--?--?--?--?--?--?--?--?--?--?--?--?--?--?--
BEGIN;
INSERT?INTO?`goods`
VALUES(1,?'product',?9999,?1,?'2018-11-30?22:06:20');
COMMIT;
SET?FOREIGN_KEY_CHECKS?=?1;
3)DAO層代碼package?org.yugh.goodsstock.pessimistic_lock.repository;
import?org.springframework.jdbc.core.JdbcTemplate;
import?org.springframework.stereotype.Repository;
import?javax.annotation.Resource;
import?java.util.List;
import?java.util.Map;
/**
*?@author:?YuGenHai
*?@name:?SeckRepository
*?@creation:?2018/11/28?00:30
*?@notes:?悲觀鎖DAO層
*?@notes:?悲觀鎖需要注意mysql自帶自動commit,用行鎖需要開啟事務?set?transation?或者set?autocommit?=0
*?防止自動提交,set?autocommit?=1?自動提交
*/
@Repository
public?class?PessimisticLockRepository
{
/**
*?測試使用?{@link?JdbcTemplate}
*/
@Resource
private?JdbcTemplate?jdbcTemplate;
/**
*?獲取現有庫存量
*?@param?id
*?@return
*?@author?yugenhai
*/
public?int?queryStock(long?id)
{
//開啟事務
String?lock?=?"set?autocommit=0";
jdbcTemplate.update(lock);
//獲得當前庫存?并上鎖
String?sql?=?"select?*?from?goods?where?id=1?for?update";
List?>?list?=?jdbcTemplate.queryForList(sql);
if?(null?!=?list?&&?list.size()?>?0)
{
Map??map?=?list.get(0);
System.out.println("當前庫存值:?"?+?map.get("stock"));
return?Integer.valueOf(String.valueOf(map.get("stock")));
}
return?0;
}
/**
*?還有庫存量,并且要釋放當前鎖
*?@author?yugenhai
*?@return
*/
public?int?updateStock()
{
String?update?=?"update?goods?set?stock=stock-1?where?id=1";
jdbcTemplate.update(update);
String?unlock?=?"commit";
jdbcTemplate.update(unlock);
return?1;
}
/**
*?商品被搶光后需要釋放
*?@author?yugenhai
*?@return
*/
public?int?unlock()
{
String?unlock?=?"commit";
jdbcTemplate.update(unlock);
return?1;
}
}
4)悲觀鎖測試:package?org.yugh.goodsstock.pessimistic_lock;
import?org.junit.Test;
import?org.junit.runner.RunWith;
import?org.springframework.boot.test.context.SpringBootTest;
import?org.springframework.test.context.junit4.SpringRunner;
import?org.yugh.goodsstock.pessimistic_lock.repository.PessimisticLockRepository;
import?javax.annotation.Resource;
/**
*?@author:?YuGenHai
*?@name:?PessimisticLockTest
*?@creation:?2018/11/28?00:32
*?@notes:?悲觀鎖測試秒殺商品
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public?class?PessimisticLockTest
{
@Resource
PessimisticLockRepository?pessimisticLockRepository;
/**
*?STOCK庫存總數,測試可以理解為購買者
*?表里的stock對應庫存
*/
private?static?final?int?STOCK?=?10000;
/**
*?悲觀鎖秒殺商品
*?@author?yugenhai
*/
@Test
public?void?pessimisticLockTest()
{
long?beTime?=?System.currentTimeMillis();
for?(int?i?=?0;?i?
{
//獲得當前庫存
//順帶上鎖,開啟事務
int?stock?=?pessimisticLockRepository.queryStock(1);
if?(stock?>?0)
{
//庫存還有
//當前用戶繼續秒殺一個商品?并提交事務?釋放鎖
pessimisticLockRepository.updateStock();
System.out.println(new?Thread()
.getName()?+?"?搶到了第?"?+?(i?+?1)?+?"?商品");
}
else
{
//沒有庫存后釋放鎖
System.err.println(new?Thread()
.getName()?+?"?抱歉,商品沒有庫存了!");
pessimisticLockRepository.unlock();
//break;
}
}
System.out.println("秒殺?"?+?STOCK?+?"?件商品使用悲觀鎖需要花費時間:"?+?(System.currentTimeMillis()?-?beTime));
}
}
5)模擬一萬用戶在搶購,最后只有一位用戶沒有搶到:當前庫存值:?8
Thread?-?9994?搶到了第?9992?商品
當前庫存值:?7
Thread?-?9995?搶到了第?9993?商品
當前庫存值:?6
Thread?-?9996?搶到了第?9994?商品
當前庫存值:?5
Thread?-?9997?搶到了第?9995?商品
當前庫存值:?4
Thread?-?9998?搶到了第?9996?商品
當前庫存值:?3
Thread?-?9999?搶到了第?9997?商品
當前庫存值:?2
Thread?-?10000?搶到了第?9998?商品
當前庫存值:?1
Thread?-?10001?搶到了第?9999?商品
當前庫存值:?0
秒殺?10000?件商品使用悲觀鎖需要花費時間:?9922
Thread?-?10002?抱歉,?商品沒有庫存了!
2018?-?12?-?01?00:?51:?06.914?INFO?9125--?-?[Thread?-?2]?s.c.a.AnnotationConfigApplicationContext:?Closing?org.springframework.context.annotation.AnnotationConfigApplicationContext?@f0da945:?startup?date[Sat?Dec?01?00:?50:?56?CST?2018];
root?of?context?hierarchy
2018?-?12?-?01?00:?51:?06.915?INFO?9125--?-?[Thread?-?2]?com.zaxxer.hikari.HikariDataSource:?HikariPool?-?1?-?Shutdown?initiated...
2018?-?12?-?01?00:?51:?06.920?INFO?9125--?-?[Thread?-?2]?com.zaxxer.hikari.HikariDataSource:?HikariPool?-?1?-?Shutdown?completed.
以上就是今天的全部內容了,悲觀鎖一般適合寫入操作比較頻繁的場景;如若想要了解更多鎖機制相關java常見問答知識,煩請持續關注我們的網站吧。
推薦閱讀:
總結
以上是生活随笔為你收集整理的悲观锁代码java_悲观锁的代码实现如何编写?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 农夫山泉股票怎么买
- 下一篇: ps怎么涂抹(ps教程如何抠图)