面试的时候,面试人员总喜欢问在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事务