如何减少多库存、单笔交易或单笔交易?
How to reduce multi inventory, each transaction or only one transaction?
那样method1
@Transactional(rollbackFor = Exception.class)
public void reduce(list) {
for (someone : list) {
xxx
}
}
或method2
public void reduce(list) {
for (someone : list) {
reduceOne();
}
}
@Transactional(rollbackFor = Exception.class)
private void reduceOne(one) {
xxx
}
并发系统哪个更好?为什么?
如果选择method2
,如何解决someone reduce fail?
两者各有优缺点
第一个选项为整个循环创建一个事务,因此如果列表中有 1000 个元素:
- 如果第1000个元素发生异常,则不会持久化所有999
- 如果没有发生异常,您将获得性能优势,因为您只创建了一个事务
对于第二个选项:
- 如果第1000个元素发生异常,则全部持久化999
- 然而,您为每个循环迭代创建一个事务,这会显着降低您的程序速度
就并发而言,这完全取决于您的 RBMS 的事务隔离级别。
例如对于Oracle来说,就是READ_COMMITTED
,那么在一个线程更新行的情况下,不管更新的事务是否完成,其余的都可以自由读取这一行。因此,这两个选项的行为应该相似。
MySql 是 REPEATABLE_READ
。因此,第一个选项可能会通过一个线程锁定许多行,从而阻止其余线程读取那些锁定的行。那样的话,第二个选项可能更好。
如您所见,影响因素很多,没有最佳答案。这取决于您使用的数据库、异常频率以及您的方法中 xxx 背后的内容。
那样method1
@Transactional(rollbackFor = Exception.class)
public void reduce(list) {
for (someone : list) {
xxx
}
}
或method2
public void reduce(list) {
for (someone : list) {
reduceOne();
}
}
@Transactional(rollbackFor = Exception.class)
private void reduceOne(one) {
xxx
}
并发系统哪个更好?为什么?
如果选择method2
,如何解决someone reduce fail?
两者各有优缺点
第一个选项为整个循环创建一个事务,因此如果列表中有 1000 个元素:
- 如果第1000个元素发生异常,则不会持久化所有999
- 如果没有发生异常,您将获得性能优势,因为您只创建了一个事务
对于第二个选项:
- 如果第1000个元素发生异常,则全部持久化999
- 然而,您为每个循环迭代创建一个事务,这会显着降低您的程序速度
就并发而言,这完全取决于您的 RBMS 的事务隔离级别。
例如对于Oracle来说,就是READ_COMMITTED
,那么在一个线程更新行的情况下,不管更新的事务是否完成,其余的都可以自由读取这一行。因此,这两个选项的行为应该相似。
MySql 是 REPEATABLE_READ
。因此,第一个选项可能会通过一个线程锁定许多行,从而阻止其余线程读取那些锁定的行。那样的话,第二个选项可能更好。
如您所见,影响因素很多,没有最佳答案。这取决于您使用的数据库、异常频率以及您的方法中 xxx 背后的内容。