[Spring Boot] @Transactional 和 synchronized 不能在一个方法中使用!
@Transactional
和锁一起用会出现一些问题,具体请看 Spring Boot 锁。
tip:[start]
@Transactional
是 Spring AOP 切入编程的一种,切入点有三种基本的通知类型,如 @Before
、@After
、@Around
,因此,事务开启在方法执行之前,事务提交在方法执行结束。但是,方法上锁和释放锁都在方法执行时,所以,在下一个线程进入之后,事务可能没有提交,数据库数据也没有更新,下一个线程读取的数据就有问题。
tip:[end]
如图1所示,红色是线程1,黄色是线程2。线程1执行,一旦释放锁,线程2就会立马执行。但是,此时的线程1释放锁之后还没提交事务,数据库数据也未更新,线程2因锁释放也执行,导致线程2读取数据库的数据不是最新的。
而且 Idea 也会标一个黄色波浪线提示你。因此,可以新建一个类,专门调用 Mapper 做事务,也就是改变顺序。
file:[DiscussionService.java]
@Service
public class DiscussionService implements IDiscussionService {
// ......
@Override
public synchronized int upgradeArticle(ArticleModel model, DiscussionCriteria criteria) {
return transactionalWrapper.doUpgradeArticle(model, criteria);
}
}
@AllArgsConstructor
class TransactionalWrapper {
// ......
@Transactional
public int doUpgradeArticle(ArticleModel model, DiscussionCriteria criteria) {
try {
// ...
Integer affectRows = discussionMapper.upgradeArticle(model);
return affectRows > 0 ? 1 : 0;
} catch (Exception e) {
throw new JdbcErrorException(e);
}
}
}