面試的時候,面試人員總喜歡問在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事務