解决并发问题,数据库常用的两把锁!( 二 )


 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <optional>true</optional>
 </dependency>
 <!-- aop -->
 <dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjweaver</artifactId>
 <version>1.8.4</version>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 </plugin>
 </plugins>
 </build>
</project>
项目的结构如下:
介绍一下项目的结构的内容:
entity包: 实体类包 。
repository包:数据库repository
service包: 提供服务的service
controller包: 控制器写入用于编写requestMApping 。相关请求的入口类
annotation包: 自定义注解,用于重试 。
aspect包: 用于对自定义注解进行切面 。
DblockApplication: springboot的启动类 。
DblockApplicationTests: 测试类 。
咱们看一下核心代码的实现,参考如下,使用dataJpa非常方便,集成了CrudRepository就可以实现简单的CRUD,非常方便,有兴趣的同学可以自行研究 。
实现乐观锁的方式有两种:
更新的时候将version字段传过来,然后更新的时候就可以进行version判断,如果version可以匹配上,那么就可以更新(方法:updateCatalogWithVersion) 。
在实体类上的version字段上加入version,可以不用自己写SQL语句就可以它就可以自行的按照version匹配和更新,是不是很简单 。
public interface CatalogRepository extends CrudRepository<Catalog, Long> {
 @Query(value = https://www.isolves.com/it/sjk/bk/2019-04-08/"select * from Catalog a where a.id = :id for update", nativeQuery = true)
 Optional<Catalog> findCatalogsForUpdate(@Param("id") Long id);
 @Lock(value = https://www.isolves.com/it/sjk/bk/2019-04-08/LockModeType.PESSIMISTIC_WRITE) //代表行级锁
 @Query("select a from Catalog a where a.id = :id")
 Optional<Catalog> findCatalogWithPessimisticLock(@Param("id") Long id);
 @Modifying(clearAutomatically = true) //修改时需要带上
 @Query(value = https://www.isolves.com/it/sjk/bk/2019-04-08/"update Catalog set browse_count = :browseCount, version = version + 1 where id = :id " +
 "and version = :version", nativeQuery = true)
 int updateCatalogWithVersion(@Param("id") Long id, @Param("browseCount") Long browseCount, @Param("version") Long version);
}
实现悲观锁的时候也有两种方式:
自行写原生SQL,然后写上for update语句 。(方法:findCatalogsForUpdate)
使用@Lock注解,并且设置值为LockModeType.PESSIMISTIC_WRITE即可代表行级锁 。
还有我写的测试类,方便大家进行测试:
package com.hqs.dblock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DblockApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DblockApplicationTests {
 @Autowired
 private TestRestTemplate testRestTemplate;
 @Test
 public void browseCatalogTest() {
 String url = "http://localhost:8888/catalog";
 for(int i = 0; i < 100; i++) {
 final int num = i;
 new Thread(() -> {
 MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
 params.add("catalogId", "1");
 params.add("user", "user" + num);
 String result = testRestTemplate.postForObject(url, params, String.class);
 System.out.println("-------------" + result);
 }
 ).start();
 }
 }
 @Test
 public void browseCatalogTestRetry() {


推荐阅读