@ Transactional 실효 장면 및 원리

6114 단어 spring
1. @ Transactional 수식 방법 은 비 Public 방법 입 니 다. 이때 @ Transactional 이 실 현 됩 니 다.실패 의 원 리 는 @ Transactional 은 동적 대 리 를 바탕 으로 이 루어 진 것 입 니 다. 비 Public 방법 입 니 다. 그 는 @ Transactional 의 동적 대리 대상 정보 가 비어 있 기 때문에 스크롤 백 할 수 없습니다.2. 클래스 내부 에 @ Transactional 방법 을 추가 하지 않 았 습 니 다. @ Transactional 방법 을 호출 했 을 때 다음 과 같이 테스트 코드 를 스크롤 하지 않 습 니 다.
@Service
public class UserServiceImpl extends BaseServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @Transactional
    public void insertOne() {
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername("Michael_C_2019");
        //      
        userMapper.insertSelective(userEntity);
        //      
        throw new IndexOutOfBoundsException();
    }

    @Override
    public void saveOne() {
        insertOne();
    }
}

실패 의 원리: @ Transactional 은 동적 에이전트 대상 을 바탕 으로 이 루어 집 니 다. 클래스 내부 에서 의 방법 호출 은 this 키 워드 를 통 해 이 루어 집 니 다. 동적 에이전트 대상 을 거치 지 않 았 기 때문에 트 랜 잭 션 스크롤 이 실 효 됩 니 다.3. @ Transactional 방법 내부 에서 이상 을 잡 았 습 니 다. catch 코드 블록 에서 이상 을 다시 던 지지 않 았 고 트 랜 잭 션 도 굴 러 가지 않 았 습 니 다.코드 는 다음 과 같 습 니 다:
@Override
    @Transactional
    public void insertOne() {
        try {
            UserEntity userEntity = new UserEntity();
            userEntity.setUsername("Michael_C_2019");
            //      
            userMapper.insertSelective(userEntity);
            //      
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
    }

그래서 알 리 바 바 의 자바 개발 자 매 뉴 얼 에 명확 한 규정 이 있 습 니 다. @ Transactional 방법 에서 이상 을 잡 았 습 니 다. 수 동 으로 스크롤 백 해 야 합 니 다. 코드 는 다음 과 같 습 니 다.
 @Override
    @Transactional
    public void insertOne() {
        try {
            UserEntity userEntity = new UserEntity();
            userEntity.setUsername("Michael_C_2019");
            //      
            userMapper.insertSelective(userEntity);
            //      
            throw new IndexOutOfBoundsException();
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }


실패 원리: 이때 spring 의 소스 코드 를 살 펴 보 겠 습 니 다: Transaction AspectSupport 류 의 invoke WithinTransaction 방법
TransactionAspectSupport
@Nullable
    protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
        TransactionAttributeSource tas = this.getTransactionAttributeSource();
        TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;
        PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
        String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
        Object result;
        if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
            TransactionAspectSupport.ThrowableHolder throwableHolder = new TransactionAspectSupport.ThrowableHolder(null);

            try {
                result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, (status) -> {
                    TransactionAspectSupport.TransactionInfo txInfo = this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                    Object var9;
                    try {
                        Object var8 = invocation.proceedWithInvocation();
                        return var8;
                    } catch (Throwable var13) {
                        if (txAttr.rollbackOn(var13)) {
                            if (var13 instanceof RuntimeException) {
                                throw (RuntimeException)var13;
                            }

                            throw new TransactionAspectSupport.ThrowableHolderException(var13);
                        }

                        throwableHolder.throwable = var13;
                        var9 = null;
                    } finally {
                        this.cleanupTransactionInfo(txInfo);
                    }

                    return var9;
                });
                if (throwableHolder.throwable != null) {
                    throw throwableHolder.throwable;
                } else {
                    return result;
                }
            } catch (TransactionAspectSupport.ThrowableHolderException var19) {
                throw var19.getCause();
            } catch (TransactionSystemException var20) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    var20.initApplicationException(throwableHolder.throwable);
                }

                throw var20;
            } catch (Throwable var21) {
                if (throwableHolder.throwable != null) {
                    this.logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                }

                throw var21;
            }
        } else {
            TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            result = null;

            try {
                result = invocation.proceedWithInvocation();
            } catch (Throwable var17) {
              //   , catch       
                this.completeTransactionAfterThrowing(txInfo, var17);
                throw var17;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }

            this.commitTransactionAfterReturning(txInfo);
            return result;
        }
    }

그 는 이상 을 포착 하고 catch 에서 사 무 를 스크롤 백 하 는 사람 이기 때문에 자신의 방법 에서 catch 가 이상 하 다 면 catch 에서 새로운 이상 을 던 지지 않 으 면 사 무 는 스크롤 백 하지 않 을 것 이다.

좋은 웹페이지 즐겨찾기