如果商城中有一件商品,成本價是80元,售價是100元。經理先是通知小李,說你去把商品價格增加50元。小李正在玩遊戲,耽擱了一個小時。剛好一個小時後,經理覺得商品價格增加到150元,價格太高,可能會影響銷售。又通知小王,你把商品價格降低30元。
此時,小李和小王同時操作商品後台系統。小李操作的時候,系統先取出商品價格100元;小王也在操作,取出的商品價格也是100元。小李將價格加了50元,並將100 50=150元存入了資料庫;小王將商品減了30元,並將100-30=70元存入了資料庫。是的,如果沒有鎖,小李的操作就完全被小王的覆蓋了。
現在商品價格是70元,比成本價低10元。幾分鐘後,這個商品很快就賣了1千多件商品,老闆虧1萬多。
CREATE TABLE product ( id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', price INT(11) DEFAULT 0 COMMENT '价格', version INT(11) DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id) ); INSERT INTO product (id, NAME, price) VALUES (1, '笔记本', 100);
@Data public class Product { private Long id; private String name; private Integer price; private Integer version; }
public interface ProductMapper extends BaseMapper<Product> { }
@RunWith(SpringRunner.class) @SpringBootTest public class ProductVersionTest { @Resource private ProductMapper productMapper; @Test public void testProductUpdate() { //1、小李 Product p1 = productMapper.selectById(1L); //2、小王 Product p2 = productMapper.selectById(1L); //3、小李将价格加了50元,存入了数据库 p1.setPrice(p1.getPrice() + 50); int result1 = productMapper.updateById(p1); System.out.println("小李修改结果:" + result1); //4、小王将商品减了30元,存入了数据库 p2.setPrice(p2.getPrice() - 30); int result2 = productMapper.updateById(p2); System.out.println("小王修改结果:" + result2); //最后的结果 Product p3 = productMapper.selectById(1L); System.out.println("最后的结果:" + p3.getPrice()); } }
最後輸出的是70元,與經理預期的120元不同,導致虧損,如何防止這樣的異常發生,解決方案是使用樂觀鎖
資料庫中新增version欄位:取出記錄時,取得目前version
SELECT id,`name`,price,`version` FROM product WHERE id=1
更新時,version 1,如果where語句中的version版本不對,則更新失敗
UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1
新增@Version 註解
@Version private Integer version;
@Configuration //@MapperScan("com.koo.modules.*.dao") public class MybatisPlusConfig { /** * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); //实现乐观锁,保证数据的准确性 interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return interceptor; } @Bean public ConfigurationCustomizer configurationCustomizer() { return configuration -> configuration.setUseDeprecatedExecutor(false); } }
(判斷第二次更新資料是否成功,不成功則重新取資料進行更新)
@RunWith(SpringRunner.class) @SpringBootTest public class ProductVersionTest { @Resource private ProductMapper productMapper; @Test public void testProductUpdate() { //1、小李 Product p1 = productMapper.selectById(1L); //2、小王 Product p2 = productMapper.selectById(1L); //3、小李将价格加了50元,存入了数据库 p1.setPrice(p1.getPrice() + 50); int result1 = productMapper.updateById(p1); System.out.println("小李修改结果:" + result1); //4、小王将商品减了30元,存入了数据库 p2.setPrice(p2.getPrice() - 30); int result2 = productMapper.updateById(p2); System.out.println("小王修改结果:" + result2); if(result2 == 0){//更新失败,重试 System.out.println("小王重试"); //重新获取数据 p2 = productMapper.selectById(1L); //更新 p2.setPrice(p2.getPrice() - 30); productMapper.updateById(p2); } //最后的结果 Product p3 = productMapper.selectById(1L); System.out.println("最后的结果:" + p3.getPrice()); } }
輸出結果為120,資料正確
以上是怎麼使用MyBatisPlus+SpringBoot實現樂觀鎖定功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!