I am working on a school project to demonstrate unrepeatable read error with read_committed isolation level. I am using MySql, and spring with hibernate. Somehow I cannot produce the unrepeatable issue.
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-hibernate.xml");
WarehouseService service = ctx.getBean("warehouseServiceImpl", WarehouseService.class);
int prodId = 3;
IncreaseInventoryThread thrdIncInvent = new IncreaseInventoryThread(service, prodId, 10);
thrdIncInvent.start();
for(int i=0; i<30; i++){
service.checkProduct(prodId);
}
}
My thread simply keeps increasing product inventory
public class IncreaseInventoryThread extends Thread {
WarehouseService service;
int prodId;
int iteration;
public IncreaseInventoryThread(WarehouseService service, int prodId, int iteration) {
this.service = service;
this.prodId = prodId;
this.iteration = iteration;
}
@Override
public void run() {
for(int i=0; i<iteration; i++){
service.increaseInventory(prodId);
}
}
}
And here is my Service Class
@Service
@Transactional(propagation=Propagation.SUPPORTS, readOnly=false)
public class WarehouseServiceImpl implements WarehouseService {
static final int INITIAL_TOTAL_ORDER = 40;
static final int DEFAULT_MAX_INVENTORY = 100;
static final int DEFAULT_INC_INVENTORY = 5;
@Autowired
private ProductDao productDao;
@Override
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED)
public void checkProduct(int prodId){
Product product = productDao.getProductById(prodId);
System.out.println("current product "+product.getName() +
" is "+ product.getStock());
if(stock != productDao.getProductById(prodId).getStock()){
System.out.println("Error: Unrepeatable read");
}else{
System.out.println("Read value consistent");
}
}
@Override
@Transactional(propagation=Propagation.REQUIRED, readOnly=false)
public void increaseInventory(int prodId) {
productDao.addInvetory(prodId, DEFAULT_INC_INVENTORY);
Product product = productDao.getProductById(prodId);
System.out.println(product.getName()+" now has " + product.getStock());
}
My Dao Class has no transaction annotation
@Repository
public class HibernateProductDao implements ProductDao {
@Autowired
private SessionFactory sessionFactory;
@Override
public Session currentSession() {
return this.sessionFactory.getCurrentSession();
}
@Override
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void addProduct(Product product) {
currentSession().saveOrUpdate(product);
}
@Override
public Product getProductById(int id) {
Product product = (Product) currentSession().get(Product.class, id);
return product;
}
@Override
public void addInvetory(int id, int quantity) {
Product product = getProductById(id);
int newStock = product.getStock()+quantity;
product.setStock(newStock);
addProduct(product);
}
}
The idea is to use two threads. One to keep incrementing product inventory, the other thread read product inventory twice within one transaction. Since the read transaction (service.checkProduct(prodId)) is read committed, I should see a unrepeatable read at some point. But for some reason, I cannot produce it. I even add delay between two reads within transaction to no avail. Any suggestion is appreciated. Following the the debug print:
current product TV Set is 100
TV Set now has 105
Read value consistent
current product TV Set is 100
Read value consistent
current product TV Set is 105
Read value consistent
TV Set now has 110
current product TV Set is 110
Read value consistent
TV Set now has 115
current product TV Set is 115
Read value consistent
TV Set now has 120
current product TV Set is 120
Read value consistent
TV Set now has 125
current product TV Set is 125
Read value consistent
TV Set now has 130
current product TV Set is 130
Read value consistent
current product TV Set is 130
Read value consistent
current product TV Set is 130
Read value consistent
TV Set now has 135
current product TV Set is 135
TV Set now has 140
Read value consistent
TV Set now has 145