asp.net网站建设论文,山东建设企业网站,望野拼音,wordpress防伪码记一次并发问题 Synchronized 失效
场景#xff1a;为避免信息提交重复#xff0c;给事务方法增加了synchronized修饰符#xff0c;实际场景中仍然无法完全避免重复#xff0c;原因是因为在第一个线程执行完synchronized代码段后#xff0c;此时spring还未完成事务提交为避免信息提交重复给事务方法增加了synchronized修饰符实际场景中仍然无法完全避免重复原因是因为在第一个线程执行完synchronized代码段后此时spring还未完成事务提交但是其他线程已经进入该代码段导致信息提交重复。 这里是部分spring aop 实现声明式事务的代码
PlatformTransactionManager ptm asPlatformTransactionManager(tm);final String joinpointIdentification methodIdentification(method, targetClass, txAttr);if (txAttr null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal invocation.proceedWithInvocation();// 这里执行完成我们被代理的方法以后资源就已经被释放掉了// 导致后面的线程可以获得这个锁资源可以执行方法中的临界区代码}catch (Throwable ex) {// target invocation exceptioncompleteTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}if (retVal ! null vavrPresent VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...TransactionStatus status txInfo.getTransactionStatus();if (status ! null txAttr ! null) {retVal VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}// 提交事务也就是说这里的事务还没有提交但是后面过来的线程已经在查询数据库了// 所以查询到的数据还是falsecommitTransactionAfterReturning(txInfo);return retVal;}在多线程环境下就可能会出现方法执行完了(synchronized代码块执行完了)事务还没提交别的线程可以进入被synchronized修饰的方法再读取的时候读到的是还没提交事务的数据这个数据不是最新的所以就出现了这个问题。
方案1 很简单 那就是不开事务就行了再这个方法上不加事务就行 因为 Synchronized 可以保证线程安全。 这个方案的意思就是说不要再同一个方法上用Transaction 和 Synchronized 例子图就没有贴了 就像我前面的 把注解去掉就好了 但是前提你这个方案确定是不需要事务
方案2 再这个里面再调用一层service 让那个方法提交事务这样的话加上Synchronized 也能保证线程安全。或者直接在controller层加上锁就可以保证整个方法的原子性了
Synchronized 失效关键原因是因为Synchronized锁定的是当前调用方法对象,而Spring AOP 处理事务会进行生成一个代理对象并在代理对象执行方法前的事务开启方法执行完的事务提交所以说事务的开启和提交并不是在 Synchronized 锁定的范围内。出现同步锁失效的原因是:当A(线程) 执行完insertSelective()方法会进行释放同步锁去做提交事务但在A(线程)还没有提交完事务之前B(线程)进行执行findOrder() 方法执行完毕之后和A(线程)一起提交事务, 这时候就会出现线程。