|
我们知道Spring事务的底层是Spring AOP,而Spring AOP的底层是动态代理技术。跟大家一起回顾一下动态代理:
- public static void main(String[] args) {
-
- // 目标对象
- Object target ;
-
- Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), Main.class, new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-
- // 但凡带有@Transcational注解的方法都会被拦截
-
- // 1... 开启事务
-
- method.invoke(target);
-
- // 2... 提交事务
-
- return null;
- }
-
- });
- }
(详细请参考我之前写过的动态代理:给女朋友讲解什么是代理模式)
实际上Spring做的处理跟以上的思路是一样的,我们可以看一下TransactionAspectSupport类中invokeWithinTransaction():
调用方法前开启事务,调用方法后提交事务
在多线程环境下,就可能会出现:方法执行完了(synchronized代码块执行完了),事务还没提交,别的线程可以进入被synchronized修饰的方法,再读取的时候,读到的是还没提交事务的数据,这个数据不是最新的,所以就出现了这个问题。
三、解决问题
从上面我们可以发现,问题所在是因为@Transcational注解和synchronized一起使用了,加锁的范围没有包括到整个事务。所以我们可以这样做:
新建一个名叫SynchronizedService类,让其去调用addEmployee()方法,整个代码如下:
- @RestController
- public class EmployeeController {
-
- @Autowired
- private SynchronizedService synchronizedService ;
-
- @RequestMapping("/add")
- public void addEmployee() {
- for (int i = 0; i < 1000; i++) {
- new Thread(() -> synchronizedService.synchronizedAddEmployee()).start();
- }
- }
- }
-
- // 新建的Service类
- @Service
- public class SynchronizedService {
-
- @Autowired
- private EmployeeService employeeService ;
-
- // 同步
- public synchronized void synchronizedAddEmployee() {
- employeeService.addEmployee();
-
- }
- }
-
- @Service
- public class EmployeeService {
-
- @Autowired
- private EmployeeRepository employeeRepository;
-
-
- @Transactional
- public void addEmployee() {
-
- // 查出ID为8的记录,然后每次将年龄增加一
- Employee employee = employeeRepository.getOne(8);
- System.out.println(Thread.currentThread().getName() + employee);
- Integer age = employee.getAge();
- employee.setAge(age + 1);
-
- employeeRepository.save(employee);
-
- }
- }
(编辑:PHP编程网 - 金华站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|