乐观锁&悲观锁

数据库建表account:

1)乐观锁示例操作
(1)新建实体类,加注解
@Entity
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handle"})
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String aname;
private Double money;
//@Version
private int version;
(2)新建Dao
public interface AccountDao extends JpaRepository<Account,Integer>, JpaSpecificationExecutor<Account>, Serializable {
}
(3)AccountService
public interface AccountService extends BaseService<Account,Integer> {
//悲观锁自定义的两个方法
public Account mod1(int aid);
public Account mod2(int aid);
}
BaseService:
public interface BaseService<G,ID> {
public void add(G g);
public void mod(G g);
public void del(ID sid);
public G get(ID sid);
public List<G> query();
public List<G> query(G g);
//pageNo:表示当前页 pageSize:表示每页显示多少条记录
public Page<G> query(G g, int pageNo, int pageSize);
//把当前面,每页显示多少记录封装到pageable对象中
public Page<G> query(G g, Pageable pageable);
}
(4)新建控制器
@RestController
public class AccountController {
//乐观锁1
@RequestMapping("/testlock1")
//乐观锁失败后重试,自定义方法加的注释方法
//@RetryOnOptimisticLockingFailure
public Account testLock1(){
int aid = 1;
Account a = accountDao.getOne(aid);
a.setMoney(a.getMoney()-100);
accountDao.save(a);
return a;
}
//乐观锁2
@RequestMapping("/testlock2")
//乐观锁失败后重试,自定义方法加的
//@RetryOnOptimisticLockingFailure
public Account testLock2(){
int aid = 1;
Account a = accountDao.getOne(aid);
a.setMoney(a.getMoney()-100);
//睡眠10s 模拟操作
try {
Thread.sleep(10000);
}catch(Exception e){
e.printStackTrace();
}
accountDao.save(a);
return a;
}
//使用悲观锁
@RequestMapping("/testlock3")
public Account testLock3(){
int aid = 1;
Account a = accountService.mod1(aid);
return a;
}
//使用悲观锁
@RequestMapping("/testlock4")
public Account testLock4(){
int aid = 1;
Account a = accountService.mod2(aid);
return a;
}
@Resource
private AccountDao accountDao;
@Resource
private AccountService accountService;
}
(5)开两个浏览器进行测试
先测试testlock2,乐观锁失败

自定义乐观锁失败后重试:
@Aspect
@Component
public class RetryOnOptimisticLockingAspect {
private static final Logger logger = LoggerFactory.getLogger(RetryOnOptimisticLockingAspect.class);
private static final int maxRetries = 5;//乐观锁失败后,最多重试的次数
@Pointcut("@annotation(RetryOnOptimisticLockingFailure)")//自定义切入点
public void retryOnOptFailure(){}
//具体要执行的切面的代码,是一个环绕通知
@Around(value = "retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable{
int numAttempts = 0;//当前重试的次数
do{
numAttempts++;
try {
return pjp.proceed();//执行目标业务方法调用
}catch(Exception e){
if (e instanceof ObjectOptimisticLockingFailureException ||
e instanceof StaleStateException ||e instanceof JpaSystemException) {
logger.info("更新数据---乐观锁重试中---");
if (numAttempts > maxRetries){
logger.info("抛出异常");
throw e;
}
}else throw e;//不属于乐观锁的异常
}
}while(numAttempts<maxRetries);
return null;
}
}
后测试testlock1

使用悲观锁解决问题:
(1)实体类的@Version注释掉
@Entity
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handle"})
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer aid;
private String aname;
private Double money;
//@Version
private int version;
(2)AccountService
public interface AccountService extends BaseService<Account,Integer> {
//悲观锁自定义的两个方法
public Account mod1(int aid);
public Account mod2(int aid);
}
@Service
public class AccountServiceImpl implements AccountService {
@Resource
private AccountDao accountDao;
@Override
@Transactional
public Account mod1(int aid) {
Account a = accountDao.getAid(aid);
a.setMoney(a.getMoney()-100);
accountDao.save(a);
return a;
}
@Override
@Transactional
public Account mod2(int aid) {
Account a = accountDao.getAid(aid);
a.setMoney(a.getMoney()-100);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
accountDao.save(a);
return a;
}}
(3)控制层:同上
(4)打开浏览器,一个过程执行完成后,另一个过程才能被执行。

浙公网安备 33010602011771号