Previously wrote some auxiliary work related to how spring boot uses AOP. Here continue to the topic, how to reduce the spring Boot optimistic lock plus lock error situation (basic can be resolved).
1. Package dependencies
SPRING-BOOT-STARTER-DATA-JPA, Spring Boot's JPA starter
H2, H2 Memory Database
spring-boot-starter-test,spring Boot's junit test starter
1 <Dependency>2 <groupId>Org.springframework.boot</groupId>3 <Artifactid>Spring-boot-starter-data-jpa</Artifactid>4 <version>1.2.6.RELEASE</version>5 </Dependency>6 7 <Dependency>8 <groupId>Com.h2database</groupId>9 <Artifactid>H2</Artifactid>Ten <version>1.4.188</version> One <Scope>Runtime</Scope> A </Dependency> - - <Dependency> the <groupId>Org.springframework.boot</groupId> - <Artifactid>Spring-boot-starter-test</Artifactid> - <version>1.2.6.RELEASE</version> - <Scope>Test</Scope> + </Dependency>
2. How do I turn on optimistic locking?
I'm using JPA, so it's easy to add a field to the entity class and annotate @version.
1 @Entity2 Public classAccount {3 4 //primary key, auto generated5 @Id6@GeneratedValue (strategy =Generationtype.auto)7 Private intID;8 9 PrivateString name;Ten One //enable optimistic locking version control A @Version - Private intversion; - the/*omitted Getter/setter, but required*/ -}
3. Using AOP to achieve retryonoptimisticlockingfailureexception recovery
To reduce the intrusion to the code, make a few changes to the previous AOP example:
- Customize an annotation to annotate the interface that needs to recover this error
1 @Retention (retentionpolicy.runtime) 2 public @Interface retryonoptimisticlockingfailure {34 }
- Pointcut expressions use annotations and no longer use execution
1 @Pointcut ("@annotation (retryonoptimisticlockingfailure)") 2 Public voidretryonoptfailure () {3 //pointcut Mark4 }5 6@Around ("Retryonoptfailure ()")7 PublicObject doconcurrentoperation (Proceedingjoinpoint PJP)throwsThrowable {8 intnumattempts = 0;9 Do {Tennumattempts++; One Try { A returnpjp.proceed (); -}Catch(Optimisticlockingfailureexception ex) { - if(Numattempts >maxretries) { the //log failure information, and throw exception - Throwex; -}Else{ - //log failure information for audit/reference + //Would try recovery - } + } A} while(Numattempts <= This. maxretries); at - return NULL; -}
- Add recovery labels to restful interfaces that require recovery of errors
As to why it must be added on the restful interface, not elsewhere (such as the service layer), because the context of the transaction management of Spring boot is established from the resource layer, and the service layer recovery is not valid, Because the operation of the database is still in the previously failed transaction, then elaborate on it.
1 @RestController2@RequestMapping ("/account")3 Public classAccountresource {4 5 @Autowired6 PrivateAccountservice Accountservice;7 8@RequestMapping (value = "/{id}/{name}", method =requestmethod.put)9 @ResponseBodyTen @RetryOnOptimisticLockingFailure One Public voidUpdateName (@PathVariable Integer ID, @PathVariable String name) { A accountservice.updatename (ID, name); - } -}
4. Test Cases
@Test Public voidtestupdate () {NewThread (() This. Client.put (base + "/1/llt-2",NULL) . Start (); NewThread (() This. Client.put (base + "/1/llt-3",NULL) . Start (); Try { //waiting for execution result of serviceThread.Sleep (5000); } Catch(interruptedexception e) {//TODO auto-generated Catch blockE.printstacktrace (); } }
5. Test how it works
- There is no UpdateName method in Accountresource plus @retryonoptimisticlockingfailure:
Servlet.service () for Servlets [Dispatcherservlet] in the context with path [] threw exception [Request processing failed; nest Ed exception is Org.springframework.orm.ObjectOptimisticLockingFailureException:Object of class [ Com.leolztang.sb.aop.model.Account] with identifier [1]: Optimistic locking failed; Nested exception is Org.hibernate.StaleObjectStateException:Row were updated or deleted by another transaction (or unsaved -value mapping was incorrect): [com.leolztang.sb.aop.model.account#1]] with root Causeorg.hibernate.StaleObjectStateException:Row is updated or deleted by another transaction (or Unsaved-value mapping was incorrect): [Com.leolztang.sb.aop.model.account#1]at Org.hibernate.persister.entity.AbstractEntityPersister.check (abstractentitypersister.java:2541) at Org.hibernate.persister.entity.AbstractEntityPersister.update (abstractentitypersister.java:3285)
- UpdateName method plus @retryonoptimisticlockingfailure in Accountresource:
Original:name=[llz-1],version=[0],new:name=[llt-2],version=[1]original:name=[llt-2],version=[1],new: Name=[llt-3],version=[2]
6. Complete code
Http://files.cnblogs.com/files/leolztang/sb.aop-v2.tar.gz
Spring Boot optimistic locking lock failure-using AOP recovery error