我有一个用例,如下所述,我试图使用SERIALIZABLE或REPEATALBE READ ISOLATION中的事务来完成它。
这是一个书店系统。最简单,没有用户管理和价格扣除限制。这家书店有好几本书。对于每个订单请求,我需要检查可用副本的数量,如果大于0,则扣减1。
为此,我尝试使用交易1.阅读书籍对象并进行计数2.如果count>0,则更新数据库中的count(count-1(。
这两者都必须在单个事务中完成,以确认原子性/一致性。
我在我的春季启动服务中写了这个方法:
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)
@Override
public Book updateBookQuantity(String isbn) {
Book book = null;
Optional<Book> bookRecord = bookRepository.findById(isbn);
try {
System.out.println("threadname on hold= " + Thread.currentThread().getId());
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("threadname resumed = " + Thread.currentThread().getId());
if (bookRecord.isPresent()) {
book = bookRecord.get();
System.out.println("book count == " + Thread.currentThread().getId() + " "+ book.getQuantity());
if (book.getQuantity() > 0) {
book = bookRecord.get();
book.setQuantity(bookRecord.get().getQuantity() - 1);
bookRepository.save(book);
} else {
throw new BookOutOfStockException(book.getTitle());
}
}
return book;
}
现在,当我尝试使用Rest api运行它(同时命中2次(时,我在哪里出错了。两个线程并行运行,都将计数读取为1并将其更新为0。理想情况下,一个应该已经通过,另一个应该抛出BookOutOfStockException
异常。我还没有配置任何特定于事务管理器的东西,它都是由spring引导处理的。
这个代码哪里出了问题?配置是造成这种情况的原因吗?注:使用spring数据jpa,数据库:mysql
使用InnoDB引擎解决了这个问题。要更换发动机,请使用正确的方言。spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
MyIASM不支持交易。这就是为什么在上述问题中没有创建事务的原因。Innodb还支持事务和外键。