java web进销存
【實(shí)例簡(jiǎn)介】mysql eclipse tomcat開(kāi)發(fā),可直接發(fā)布使用
項(xiàng)目描述
該項(xiàng)目的架構(gòu)搭建使用的是maven,后臺(tái)是使用的是spring boot框架,數(shù)據(jù)庫(kù)的CRUD使用的是注解的方式,權(quán)限管理使用的是shiro框架,前端使用的框架是jquery,bootstrap,highcharts4插件,主要有以下功能:用戶(hù)管理、角色管理、日志管理、供應(yīng)商管理、客戶(hù)管理、商品管理、庫(kù)存管理、進(jìn)貨/退貨管理、商品報(bào)損,報(bào)溢管理、商品采購(gòu),銷(xiāo)售統(tǒng)計(jì)、商品銷(xiāo)售按日分析統(tǒng)計(jì)。
運(yùn)行環(huán)境
jdk8 tomcat8 mysql IDEA maven
項(xiàng)目技術(shù)
Spring boot spring data jpa apache shiro bootstrap jquery highcharts4
使用當(dāng)今最火的java框架springBoot
本系統(tǒng)采用企業(yè)級(jí)開(kāi)發(fā)標(biāo)準(zhǔn),使用SpringBoot架構(gòu),數(shù)據(jù)訪問(wèn)層采用Spring Data Jpa,業(yè)務(wù)控制層采用SpringMvc,安全框架采用Shiro,實(shí)現(xiàn)了完整權(quán)限系統(tǒng),Controller方法采用shiro注解,來(lái)實(shí)現(xiàn)有效的權(quán)限控制;界面采用了Easyui技術(shù);本視頻教程詳細(xì)講解了次系統(tǒng)的完整開(kāi)發(fā),亮點(diǎn)是SpringBoot的綜合應(yīng)用,以及權(quán)限系統(tǒng)的設(shè)計(jì),以及基于Shiro的安全控制,以及Easyui的高級(jí)應(yīng)用工具:eclipse mysql JDK tomcat
技術(shù):SpringBoot Spring Data Jpa SpringMvc Shiro安全認(rèn)證 完整權(quán)限系統(tǒng) easyui
文件:590m.com/f/25127180-492989525-bc357d(訪問(wèn)密碼:551685)
【實(shí)例截圖】
以下內(nèi)容無(wú)關(guān):
-------------------------------------------分割線---------------------------------------------
前言
在我們學(xué)習(xí)多線程開(kāi)發(fā)的時(shí)候,在線程同時(shí)針對(duì)同一個(gè)資源進(jìn)行操作的時(shí)候都需要加鎖;一般會(huì)用到reentrantLock和synchronized兩種鎖方案,至于他們之間的區(qū)別也是面試的時(shí)候經(jīng)常問(wèn)到的,小伙伴們可自行網(wǎng)補(bǔ)。這里介紹企業(yè)經(jīng)常用到的另一種鎖,分布式鎖。大家肯定聽(tīng)說(shuō)過(guò),但是就不一定用對(duì)哦。今天就深入的介紹一下分布式鎖方案的演變。
常見(jiàn)用法
我們也不免俗套來(lái)舉個(gè)并發(fā)扣除庫(kù)存的例子
圖片
我們來(lái)看一下代碼
//扣除商品庫(kù)存
//產(chǎn)品id: productId
//扣除數(shù)量: count
public void reduce(int productId,int count){
//步驟1 從數(shù)據(jù)庫(kù)獲得產(chǎn)品實(shí)體
Product product = getProduct(productId);
//步驟2 獲得當(dāng)前庫(kù)存數(shù)量
int stockCount = product.getStock();
if(stockCount >= count){
//步驟3 扣除庫(kù)存
product.setStock(stockCount - count);
//步驟4 把產(chǎn)品實(shí)體更新到數(shù)據(jù)庫(kù)
productService.update(product);
log.info(“購(gòu)買(mǎi)成功!”)
}else{
log.info(“庫(kù)存不足,無(wú)法購(gòu)買(mǎi)!”)
}
}
購(gòu)買(mǎi)場(chǎng)景
當(dāng)前產(chǎn)品的庫(kù)存數(shù)為10
請(qǐng)求A買(mǎi)了2個(gè)產(chǎn)品,那應(yīng)該扣除2
請(qǐng)求B買(mǎi)了3個(gè)產(chǎn)品,那應(yīng)該再扣除3
那最終的庫(kù)存剩余為5
上面代碼在分布式環(huán)境中,只要稍微流量大點(diǎn),這邊就會(huì)出現(xiàn)扣減庫(kù)存不是預(yù)期的情況。原因就是
圖片
兩個(gè)請(qǐng)求同時(shí)到來(lái)時(shí),都同時(shí)執(zhí)行了步驟1,在同一時(shí)刻都獲取到了同一個(gè)產(chǎn)品庫(kù)存當(dāng)前庫(kù)存都為10;但在步驟3的時(shí)候都是用10減count值,那么不管是請(qǐng)求A和請(qǐng)求B哪個(gè)先執(zhí)行步驟4,庫(kù)存剩余要么剩余是8或者7;都不是最終的5。
原因知道了,那怎么解決?小伙伴想到的就是弄個(gè)鎖,而且還要分布式鎖。
分布式鎖登場(chǎng)
上面的問(wèn)題很多小伙伴應(yīng)該都知道要用分布式鎖,那用什么技術(shù)方案呢?我相信很多小伙伴都會(huì)說(shuō)用redis方案,很簡(jiǎn)單setnx就行了。
setnx命令 是redis的一條原生命令大意為 set if not exists, 在指定的key不存在的情況下,命令執(zhí)行成功,如果key存在就命令執(zhí)行不成功。
這個(gè)方案是很多公司都這么用的,那我們調(diào)整一下代碼
圖片
需要考慮到一些業(yè)務(wù)異常,需要把鎖釋放掉,加上try/finally,這個(gè)千萬(wàn)不要忘了
當(dāng)是還是有一些問(wèn)題,就是如果加鎖成功后,業(yè)務(wù)沒(méi)有完成。突然斷電或者運(yùn)維人員用kill -9命令把線程刪除了;那就導(dǎo)致了鎖一直沒(méi)有釋放,因?yàn)椴粫?huì)執(zhí)行finally里面的代碼了。
那怎么辦呢?有經(jīng)驗(yàn)的小伙伴應(yīng)該就知道解決方案了
優(yōu)化分布式鎖
方案還是比較簡(jiǎn)單的,加個(gè)過(guò)期時(shí)間就行了
圖片
這樣即使斷電,過(guò)了10秒鐘之后鎖也會(huì)自動(dòng)過(guò)期,也就是失效;別的請(qǐng)求就可以正常請(qǐng)求了
現(xiàn)在到了這里,就是很多公司應(yīng)用分布式鎖的常用方案了。小伙伴們這樣就沒(méi)有問(wèn)題了嗎
問(wèn)題分析
我們來(lái)看看問(wèn)題出現(xiàn)在哪里?我們來(lái)調(diào)整一下業(yè)務(wù)代碼
圖片
因?yàn)槲覀兛蹘?kù)存的業(yè)務(wù),不可能像寫(xiě)的很簡(jiǎn)單的業(yè)務(wù);正式場(chǎng)景中業(yè)務(wù)是比較多的,不可能就這么簡(jiǎn)單;如果業(yè)務(wù)代碼執(zhí)行的時(shí)間超出了鎖的過(guò)期時(shí)間,那么鎖到期失效了,但業(yè)務(wù)代碼還沒(méi)有執(zhí)行完;這種場(chǎng)景就會(huì)導(dǎo)致數(shù)據(jù)錯(cuò)亂。
那這個(gè)問(wèn)題怎么解決呢?
解決思路
這個(gè)問(wèn)題的本質(zhì)是鎖在沒(méi)有執(zhí)行完成業(yè)務(wù)時(shí),到期失效了;那我們可以不讓他失效不就行了嗎?那怎么不讓他失效呢?
方案很簡(jiǎn)單
啟動(dòng)一個(gè)后臺(tái)線程,可以每3秒或者5秒執(zhí)行一次,找到這個(gè)鎖的key,延長(zhǎng)這個(gè)鎖key的過(guò)期時(shí)間;這樣就達(dá)到了鎖過(guò)期時(shí)間續(xù)期的功能了。是不是很簡(jiǎn)單?
我們自己寫(xiě)代碼去實(shí)現(xiàn)是沒(méi)有問(wèn)題的,但是現(xiàn)在市面上已經(jīng)有了輪子了,不需要我們自己再去寫(xiě)這個(gè)代碼了,直接用人家的輪子;這個(gè)就是大名鼎鼎的Redisson。
總結(jié)
以上是生活随笔為你收集整理的java web进销存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 小程序下拉菜单组件(含多层筛选)
- 下一篇: 通过API执行AutoCAD命令来…