1. 程式人生 > >spring事務詳解(二)實例

spring事務詳解(二)實例

名稱 zha int 分享圖片 必須 .cn reat 回滾事務 current

在Spring中,事務有兩種實現方式:

編程式事務管理: 編程式事務管理使用底層源碼可實現更細粒度的事務控制。spring推薦使用TransactionTemplate,典型的模板模式。

申明式事務管理: 添加@Transactional註解,並定義傳播機制+回滾策略。基於Spring AOP實現,本質是對方法前後進行攔截,

方法開始之前創建或者加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。

關於spring事務實現方式:

引用博文:https://www.cnblogs.com/dennyzhangdd/p/9708499.html

關於分布式鎖的實現方式:

引用博文:https://www.cnblogs.com/dennyzhangdd/p/7133653.html

提供一個具體實例來說明如何使用spring事務

基於數據庫鎖實現

1.悲觀鎖:select for update(一致性鎖定讀)

技術分享圖片
查詢官方文檔如上圖,事務內起作用的行鎖。能夠保證當前session事務所鎖定的行不會被其他session所修改(這裏的修改指更新或者刪除)。
對讀取的記錄加X鎖,即排它鎖,其他事不能對上鎖的行加任何鎖。

BEGIN;(確保以下2步驟在一個事務中:)
SELECT * FROM tb_product_stock WHERE product_id=1 FOR UPDATE--->product_id有索引,鎖行.加鎖
(註:條件字段必須有索引才能鎖行,否則鎖表,且最好用explain查看一下是否使用了索引,因為有一些會被優化掉最終沒有使用索引)
UPDATE tb_product_stock SET number
=number-1 WHERE product_id=1--->更新庫存-1.解鎖 COMMIT;

2.樂觀鎖:版本控制

選一個字段作為版本控制字段,更新前查詢一次,更新時該字段作為更新條件
不同業務場景,版本控制字段,可以0 1控制,也可以+1控制,也可以-1控制,這個隨意。
BEGIN;(確保以下2步驟在一個事務中:)
SELECT number FROM tb_product_stock WHERE product_id=1--》查詢庫存總數,不加鎖
UPDATE tb_product_stock SET number=number-1 WHERE product_id=1 AND number=第一步查詢到的庫存數
--》number字段作為版本控制字段 COMMIT;

場景舉例:

賣商品,先查詢庫存>0,更新庫存-1。

例如:一種商品,有兩件庫存,多人來下單買,一個人一次只能買一件商品

創建表biz_shoe

1 CREATE TABLE `biz_shoe` (
2   `shoe_uuid` char(32) NOT NULL,
3   `inventory_number` int(11) DEFAULT NULL COMMENT ‘庫存數量‘,
4   `is_putaway` int(1) DEFAULT NULL COMMENT ‘是否上架‘,
5   PRIMARY KEY (`shoe_uuid`)
6 ) ENGINE=InnoDB DEFAULT CHARSET=utf8

給庫存賦值,如圖

技術分享圖片

3.基於悲觀鎖實現

 1   /**
 2      * 悲觀鎖
 3      * @param shoe
 4      * @return
 5      */
 6     @Transactional(添加spring事務註解)
 7     @Override
 8     public Integer vieShoe(BizShoe shoe) {
 9         //搶單商品加悲觀鎖
10         BizShoe modleShoe = shoeMapper.lockForUpdate(shoe.getShoeUuid());
11         //商品庫存
12         Integer number = modleShoe.getInventoryNumber();
13         System.out.println("庫存:" + number);
14         System.out.println("線程名稱:" + Thread.currentThread().getName());
15         if (number != 0) {
16             number = number - 1;
17             System.out.println("剩余庫存:" + number);
18             modleShoe.setInventoryNumber(number);
19             shoeMapper.updateByPrimaryKeySelective(modleShoe);
20         } else {
21             AssertUtil.isTrue(number == 0, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
22         }
23         return number;
24     }

在mapping中具體sql語句  

1   <select id="lockForUpdate" parameterType="java.lang.String" resultMap="BaseResultMap">
2 
3     SELECT <include refid="Base_Column_List" /> FROM `biz_shoe` WHERE shoe_uuid = #{shoeUuid,jdbcType=CHAR} FOR UPDATE;
4 
5   </select>

4.基於樂觀鎖

 1   /**
 2      * 樂觀鎖
 3      * @param shoe
 4      * @return
 5      */
 6     @Transactional
 7     @Override
 8     public Integer vieShoe(BizShoe shoe) {
 9 
10         //搶單商品加樂觀鎖
11         BizShoe modleShoe = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
12         //商品庫存
13         Integer number = modleShoe.getInventoryNumber();
14         System.out.println("庫存:" + number);
15         System.out.println("線程名稱:" + Thread.currentThread().getName());
16         if(number >0){
17             int susus = shoeMapper.updateByShoeUuidInventoryNumber(shoe.getShoeUuid(),number);
18             System.out.println("更新成功 "+susus);
19             if(susus==1){//更新成功才算搶單成功
20                 //商品庫存
21                 BizShoe modleShoeNew = shoeMapper.selectByPrimaryKey(shoe.getShoeUuid());
22                 System.out.println("新庫存:" + modleShoeNew.getInventoryNumber());
23             }else{
24                 AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
25             }
26         }else {
27             AssertUtil.isTrue(true, StatusCode.NumberIsNull, StatusCode.NumberIsNull.getMessage());
28         }
29         return number;
30     }

sql語句

1 <update id="updateByShoeUuidInventoryNumber" parameterType="com.zstax.springtest.bean.BizShoe">
2 
3     UPDATE biz_shoe SET inventory_number=inventory_number-1 WHERE
4     shoe_uuid=#{shoeUuid,jdbcType=CHAR} and inventory_number=#{InventoryNumber,jdbcType=INTEGER}
5 
6   </update>

spring事務詳解(二)實例