【面试题】使用springBoot写一个用户给文章点赞的接口,需要考虑并发问题,保证文章的点赞数是准确的。
第一种方法(乐观锁字段)
在表中添加一个版本号(或者称之为乐观锁字段)来手动实现乐观锁的功能。
@Override public int Like(Long id) throws InterruptedException { //获取当前点赞量和点赞版本 Article article = articleDao.selectById(id); Long likes = article.getLikes(); Long version = article.getVersion(); //设置点赞和版本+1 article.setLikes((likes+1)); article.setVersion((version+1)); //设置修改点赞量条件 UpdateWrapper wrapper = new UpdateWrapper(); wrapper.eq("likes",likes); wrapper.eq("version",version); //模拟点赞用时1秒 Thread.sleep(1000); //修改点赞和版本 int updateCount = articleDao.update(article, wrapper); if (updateCount <= 0 ){ //如果返回修改成功条数为0,就代表被其他人修改了,那就重新再执行一次 return this.Like(id); }else { System.out.println("点赞成功,增加点赞记录"); return updateCount; } }
当然也可以设置循环执行次数,防止进入死循环或消耗过多性能,这里就不再演示代码了。
第二种方法(使用行级锁)
使用SELECT ... FOR UPDATE语句获取行级锁,锁定需要更新的行,然后再更新点赞数。
@Select("SELECT * FROM article WHERE id = #{id} FOR UPDATE") Article selectForUpdate(Long id); @Update("UPDATE article SET likes = #{article.likes} WHERE id = #{article.id} AND likes = #{currentLikes}") int updateLikesWithRowLock(Article article, int currentLikes);
测试
import com.example.lianshou.domain.Article; import com.example.lianshou.service.IArticleService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; @SpringBootTest public class ArticleTests { @Autowired private IArticleService articleService; //乐观锁字段 @Test void test() throws Exception { List<CompletableFuture<?>> futureAll = new ArrayList<>(); //模拟10人同时点赞 for (int i = 0; i < 10; i++) { int finalI = i; futureAll.add( CompletableFuture.supplyAsync(() -> { try { int like = articleService.Like(1L); } catch (InterruptedException e) { e.printStackTrace(); } return finalI; }) ); } //等待全部执行完成 CompletableFuture.allOf(futureAll.toArray(new CompletableFuture[0])).join(); } //行级锁 @Test void test2() throws Exception { List<CompletableFuture<?>> futureAll = new ArrayList<>(); //模拟10人同时点赞 for (int i = 0; i < 10; i++) { Article article = articleService.selectForUpdate(1L); Long currentLikes = article.getLikes(); article.setLikes(currentLikes+1); articleService.updateLikesWithRowLock(article,currentLikes.byteValue()); } //等待全部执行完成 CompletableFuture.allOf(futureAll.toArray(new CompletableFuture[0])).join(); } }
文章评论