I have a table called Balance in that table i have employee and the employee points.
Lets say the employee John is using mobile and web app simultaneously he places order at the same time.
So currently when he tries to place order from both the app the point should be updated accordingly.
When he tries to place order simultaneoulsy each request is getting 5000 point and based on cart value of john the point is updated.
From mobile app he redeeemed 2000 points so the updated amount is 5000-2000 ie 3000 From web app he redeemed 1000 point so the updatded amount should be 3000-1000 ie 2000
But in current scenario the updated amount is 5000-1000 = 4000.(For web app dirty read)
What should i do in order to make sure the transaction is proper.
I have added isolation level to SERIALIZABLE but in this case when second request updates the table column points
I get org.springframework.dao.DeadlockLoserDataAccessException:
What should i do in order to make sure that both the simultaneous request update the table with proper points.
Below is my code
@Transactional(isolation=Isolation.SERIALIZABLE)
public void updatePoints(String employee,int points){
Object[] arr = new Object[] {points, employeeId};
getJdbcTemplate().update("UPDATE BALANCE SET POINTS =POINTS -? WHERE EMPLOYEEID=?",arr);
}
PLEASE FIND UPDTAED CODE ABOVE CODE WAS ONLY FOR UNDERSTANDING PURPOSE Used Transactional at service layer not in dao layer
@Override
@Transactional(isolation=Isolation.SERIALIZABLE)
public void putFinalCartItems(String employeeCode, List<String> cartId, Map<String, Object> statusMap,int userId) {
CartItems carPoints = repoDao.getFinalCartItems(cartId,employeeCode);//here i have used select query with join from Balance Table
try {
String orderNo=null;
String mainOrderNo=OrderIdGenerator.getOrderId();
List<CartItems> finalCartItems = repoDao.getBifurcatedFinalCart(cartId,employeeCode);//here i have used select query with join from Balance Table
Integer balance = Integer.parseInt(finalCartItems.get(0).getPoints());
Integer successCount=0;
try {
for(CartItems cartEntityId : finalCartItems) {
balance = balance-Integer.parseInt(cartEntityId.getTotalNoOfPoint());
orderNo="TRANS-"+cartEntityId.getId();
successCount = repoDao.placeOrder(cartEntityId);
}
repoDao.updatePoints(Integer.parseInt(carPoints.getTotalNoOfPoint()),userId,employeeCode);
}catch(Exception e) {
//e.printStackTrace();
successCount=0;
}
if(successCount>0) {
FinalOrder lfo = new FinalOrder();
lfo.setBalance(String.valueOf(totbalance));
lfo.setMainOrderId(mainOrderNo);
lfo.setTotalPointsSpent(carPoints.getTotalNoOfPoint());
statusMap.put("success",lfo );
}
}
catch(Exception e ) {
statusMap.put("error","Please try again after some time" );
}
}
Error stack trace that iam getting on second request
org.springframework.dao.DeadlockLoserDataAccessException: PreparedStatementCallback; SQL [UPDATE BALANCE set Points=points-? where EMPLOYEEID=? ]; Transaction (Process ID 94) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.; nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 94) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:263)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:870)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:931)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:941)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:52)
I want second request to be successfull simultaneoulsy with first request without dirty read.
