java 事務解釋。

面試的時候,面試人員總喜歡問在spring中,git

1. 若是一個主線程上有一個事務,在事務中開啓了一個線程。子線程跑出異常,對主線程有沒有影響,或者主線程產生異常對子線程有沒有影響。github

這個時候,你只要記住主線程和子線程是不一樣的事務便可回答上面的問題,主線程跑出異常確定對子線程沒有影響,可是子線程拋出異常對主線程有沒有影響,那就要看,拋出的異常是否爲事務回滾有須要的異常類型,面試

若是是確定會回滾,若是不是就不會回滾。spring

2.主線程爲啥和子線程是不一樣的事務(在全部的事務傳播機制中)數據庫

由於 spring 中使用的ThreadLocal變量來保存 事務的執行者,entityManager。而ThreadLocal只能保證在當前線程中獲取entityManager。因此主子線程確定是不一樣的事務。session

JpaTransactionObject txObject = new JpaTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed());      //事務中的EntityManager 是從當前線程中獲取 即ThreadLocal EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(obtainEntityManagerFactory()); if (emHolder != null) { if (logger.isDebugEnabled()) { logger.debug("Found thread-bound EntityManager [" + emHolder.getEntityManager() +
                        "] for JPA transaction"); } txObject.setEntityManagerHolder(emHolder, false); } if (getDataSource() != null) {
       //事務中connectionHolder也是從threadLocal中獲取。  ConnectionHolder conHolder
= (ConnectionHolder) TransactionSynchronizationManager.getResource(getDataSource()); txObject.setConnectionHolder(conHolder); }

 

3.事務的同步多線程

  提到同步,首先想到的確定是多線程。多線程確定屬於不一樣的事務,事務的同步就是解決多線程之間事務的同步問題。異步

@Override @Transactional(propagation = Propagation.REQUIRED) public void saveRequire(Customer customer) throws Exception {  //1.保存客戶信息  repository.save(customer); exectorService.execute(()->{ //2.發送短信或郵件  });

這個例子是 1.保存客戶信息,2.發送短信或郵件--因爲短信和郵件比較耗時,因此用異步進行操做。 要求:必須在保存客戶信息成功後,發送短信和郵件。ide

上面例子的問題是,發送短信和郵件,執行時,可能在事務完成後執行,也可能在事務完成以前執行。ui

事務的同步:就是事務完成後,同時執行發送短信和郵件。

所以上面的例子能夠更改成

@Transactional(propagation = Propagation.REQUIRED) public void saveRequire(Customer customer) throws Exception { //1.保存客戶信息  repository.save(customer);
     //判斷當前事務是否激活 if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { exectorService.execute(()->{ //2.發送短信或郵件 }); } }); }else { exectorService.execute(()->{ //2.發送短信或郵件 }); }

4.事務中的主要對象介紹。

TransactionInfo 事務的對象。

protected final class TransactionInfo {      //事務管理器(獲取事務) @Nullable private final PlatformTransactionManager transactionManager; //事務屬性 (@Transactional(propagation = Propagation.REQUIRED)對應的這個註解的屬性) @Nullable private final TransactionAttribute transactionAttribute;  //標記@Transactional的類和方法組成的字符串(com.zhou.test.transaction_test.service.impl.User1ServiceImpl.saveRequire) private final String joinpointIdentification;      //當前事務的狀態(是不是新的事務,是否完成,是否有保存點,當前事務對象,當前被暫停的資源) @Nullable private TransactionStatus transactionStatus; @Nullable
     //被暫停的事務(例如require_new 須要一個新的事務,老的事務會被掛起)
private TransactionInfo oldTransactionInfo;

JpaTransactionObject 事務對象 (保存在 transactionStatus裏面)

private class JpaTransactionObject extends JdbcTransactionObjectSupport { //jpa 操做數據庫對象 @Nullable private EntityManagerHolder entityManagerHolder; private boolean newEntityManagerHolder;      //多是jpaTransactionObject(事務暫停) 多是SavepointManager(netesd,同一個事務回滾到保存點) @Nullable private Object transactionData;
JpaTransactionManager.SuspendedResourcesHolder 暫停的對象
private static class SuspendedResourcesHolder {      //數據源操做對象 private final EntityManagerHolder entityManagerHolder; //數據源操做對象 @Nullable private final ConnectionHolder connectionHolder;

TransactionSynchronization  事務的同步類  實現下面的方法,能夠在事務執行對應操做時,增長對應的處理。

default void suspend() { } default void resume() { } @Override default void flush() { } default void beforeCommit(boolean readOnly) { } default void beforeCompletion() { } default void afterCommit() { } default void afterCompletion(int status) { }

AbstractPlatformTransactionManager.SuspendedResourcesHolder 暫停的資源

protected static class SuspendedResourcesHolder {      //被暫停的對象,(存放 connectionHolder,entityManagerHoler)   @Nullable private final Object suspendedResources;      //存放當前事務同步的事件 @Nullable private List<TransactionSynchronization> suspendedSynchronizations;

 

DefaultTransactionStatus  事務狀態類。

public class DefaultTransactionStatus extends AbstractTransactionStatus {   //當前事務對象(JPATransactionObject)。 @Nullable private final Object transaction; private final boolean newTransaction; private final boolean newSynchronization; private final boolean readOnly; private final boolean debug; //暫停的資源(AbstractPlatformTransactionManager.SuspendedResourcesHolder) @Nullable private final Object suspendedResources;

5.nested 中的保存點

依賴的connection 中保存點實現。回滾時,回滾到保存點。

 6.事務的回滾原理

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
                        "] after exception: " + ex); }
        //根據註釋transactionAttribute的rollbackFor屬性判斷此種異常是否回滾,若是找不到須要回滾的指定異常,就根據是不是父類中的RuntimeException和Error進行回滾
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } }
private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { boolean unexpectedRollback = unexpected; try { triggerBeforeCompletion(status); if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Rolling back transaction to savepoint"); }
            //1.回滾的事務的保存點 status.rollbackToHeldSavepoint(); }
else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction rollback"); }
//2.若是是新建的事務,直接回滾 doRollback(status); }
else { // Participating in larger transaction if (status.hasTransaction()) { if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { if (status.isDebug()) { logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); }
                 //3.若是用的已經存在的事務,則標記事務爲回滾,等回到主事務中進行回滾 doSetRollbackOnly(status); }
else { if (status.isDebug()) { logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } } } else { logger.debug("Should roll back transaction but cannot - no transaction available"); } // Unexpected rollback only matters here if we're asked to fail early if (!isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = false; } } }

 

 

事務的處理過程 :TransactionInterceptor(只需關注事務攔截器便可。)

最後領着你們看下spring 的源碼,事務的處理原理:

1.先熟悉下 JPA事務   能夠去hibernatenate官網下載實例:https://github.com/hibernate/hibernate-demos   

 

 

EntityManager entityManager = openEntityManager(); Session session = entityManager.unwrap(Session.class); session.beginTransaction(); Tool tool = new Tool(); tool.setName("Hammer111"); session.save(tool); Future<?> future= exectorService.submit(()->{ Tool tool1 = new Tool(); tool1.setName("Hammer222"); session.save(tool1); throw new RuntimeException(); }); future.get(); session.getTransaction().commit();

 2. spring 中處理過程。

  主要查看 JpaTransactionManager.getTransaction(@Nullable TransactionDefinition definition)

  

 @Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
     //1.先獲取一個事務對象 Object transaction
= doGetTransaction();
protected Object doGetTransaction() { JpaTransactionObject txObject = new JpaTransactionObject(); txObject.setSavepointAllowed(isNestedTransactionAllowed());      //2.獲取當前線程對應的EntityManagerHolder EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(obtainEntityManagerFactory()); if (emHolder != null) { if (logger.isDebugEnabled()) { logger.debug("Found thread-bound EntityManager [" + emHolder.getEntityManager() +
                        "] for JPA transaction"); } txObject.setEntityManagerHolder(emHolder, false); } if (getDataSource() != null) { ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(getDataSource()); txObject.setConnectionHolder(conHolder); } return txObject; }
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); // Cache debug flag to avoid repeated checks.
        boolean debugEnabled = logger.isDebugEnabled(); if (definition == null) { // Use defaults if no transaction definition given.
            definition = new DefaultTransactionDefinition(); }      //3.判斷當前是否有一個事務,而且事務是開啓的狀態 if (isExistingTransaction(transaction)) { // Existing transaction found -> check propagation behavior to find out how to behave.
            return handleExistingTransaction(definition, transaction, debugEnabled); } // Check definition settings for new transaction.
        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } // No existing transaction found -> check propagation behavior to find out how to proceed.
        if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition); } try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
         //4.若是當前沒有事務,就開啓一個事務,而且把這個事務綁定到當前線程 doBegin(transaction, definition); prepareSynchronization(status, definition);
return status; } catch (RuntimeException | Error ex) { resume(null, suspendedResources); throw ex; } } else { // Create "empty" transaction: no actual transaction, but potentially synchronization. if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { logger.warn("Custom isolation level specified but no actual transaction initiated; " + "isolation level will effectively be ignored: " + definition); } boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); } }

 

5.在一個代理類的內部方法互相調用是不會添加切面方法的。(這個時候,若是想在內部方法互相調用時加入代理該怎麼辦?)

1.啓用暴露代理對象屬性

@EnableAspectJAutoProxy(exposeProxy=true)

2.內部互相調用時,寫法修改。

((Service) AopContext.currentProxy()).callMethodB();

 6. JDBC事務

相關文章
相關標籤/搜索