@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRES_NEW) 没有按预期工作
@Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRES_NEW) not working as expected
我有一个如下所述的用例,我试图在 SERIALIZABLE 或 REPEATALBE READ ISOLATION 中使用事务来完成。
这是一个书店系统。最简单,没有用户管理和价格扣除限制。书店用它来清点册数。
对于每个订单请求,我需要检查可用的份数,如果大于 0,则减去 1。
为此,我尝试使用我在其中进行的交易
1. 读取 book 对象并计数
2. 如果 count > 0 更新 db.
中的计数 ( count -1 )
这两项都必须在单个事务中完成以确认原子性/一致性。
我在我的 spring 启动服务中写了这个方法:
@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-data-jpa,数据库:mysql
使用 InnoDB 引擎解决了这个问题。要更换引擎,请使用正确的方言。
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
MyIASM 不支持事务。这就是为什么在上述问题中没有创建任何交易的原因。
Innodb 也支持事务和外键。
我有一个如下所述的用例,我试图在 SERIALIZABLE 或 REPEATALBE READ ISOLATION 中使用事务来完成。
这是一个书店系统。最简单,没有用户管理和价格扣除限制。书店用它来清点册数。 对于每个订单请求,我需要检查可用的份数,如果大于 0,则减去 1。
为此,我尝试使用我在其中进行的交易 1. 读取 book 对象并计数 2. 如果 count > 0 更新 db.
中的计数 ( count -1 )这两项都必须在单个事务中完成以确认原子性/一致性。
我在我的 spring 启动服务中写了这个方法:
@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-data-jpa,数据库:mysql
使用 InnoDB 引擎解决了这个问题。要更换引擎,请使用正确的方言。
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
MyIASM 不支持事务。这就是为什么在上述问题中没有创建任何交易的原因。 Innodb 也支持事务和外键。