乐观锁&悲观锁

 

 

 

数据库建表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)打开浏览器,一个过程执行完成后,另一个过程才能被执行。




 

posted @ 2019-10-21 22:23  duStar96  阅读(209)  评论(0)    收藏  举报