面试的时候,面试人员总喜欢问在spring中,

1. 如果一个主线程上有一个事务,在事务中开启了一个线程。子线程跑出异常,对主线程有没有影响,或者主线程产生异常对子线程有没有影响。

这个时候,你只要记住主线程和子线程是不同的事务即可回答上面的问题,主线程跑出异常肯定对子线程没有影响,但是子线程抛出异常对主线程有没有影响,那就要看,抛出的异常是否为事务回滚有需要的异常类型,

如果是肯定会回滚,如果不是就不会回滚。

2.主线程为啥和子线程是不同的事务(在所有的事务传播机制中)

因为 spring 中使用的ThreadLocal变量来保存 事务的执行者,entityManager。而ThreadLocal只能保证在当前线程中获取entityManager。所以主子线程肯定是不同的事务。

        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.发送短信或邮件--由于短信和邮件比较耗时,所以用异步进行操作。 要求:必须在保存客户信息成功后,发送短信和邮件。

上面例子的问题是,发送短信和邮件,执行时,可能在事务完成后执行,也可能在事务完成之前执行。

事务的同步:就是事务完成后,同时执行发送短信和邮件。

因此上面的例子可以更改为

    @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事务

java 事务解释。的更多相关文章

  1. 转!!java事务的处理

    java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务.如果数据库操作在某一步没有执行或出现异常而导致事务失败,这样有的事务被执行有的就没有被执行,从而就有了事务的回滚,取消先前 ...

  2. 深入Java事务的原理与应用

    一.什么是JAVA事务    通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 ( ...

  3. java事务的类型——面试被问到

    Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务. 1.JDBC事务 JDBC 事务是用 Connection 对象控制的.JDBC Conne ...

  4. java事务管理

    一.什么是Java事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性(isol ...

  5. java事务的处理

    java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务. 如果数据库操作在某一步没有执行或出现异常而导致事务失败,这样有的事务被执行有的就没有被执行,从而就有了事务的回滚,取消先 ...

  6. 常见 Java 异常解释(恶搞版)

    常见 Java 异常解释:(译者注:非技术角度分析.阅读有风险,理解需谨慎o(╯□╰)o) java.lang ArithmeticException 你正在试图使用电脑解决一个自己解决不了的数学问题 ...

  7. Java是解释型还是编译型语言?

    有人说Java是编译型的.因为所有的Java代码都是要编译的,.java不经过编译就无法执行. 也有人说Java是解释型的.因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释型 ...

  8. 分布式事务(二)Java事务API(JTA)规范

    一.引子 既然出现了分布式场景(DTP模型), 大java也及时制定出一套规范来给各大应用服务器.数据库/mq等厂商使用,以方便管理互通--->JTA闪亮登场.JTA(Java Transact ...

  9. java事务 深入Java事务的原理与应用

    一.什么是JAVA事务 通常的观念认为,事务仅与数据库相关. 事务必须服从ISO/IEC所制定的ACID原则.ACID是原子性(atomicity).一致性(consistency).隔离性 (iso ...

随机推荐

  1. Entity Framework 简介

    Entity Framework Entity Framework 的全称为 ADO.NET Entity Framework,简称 EF. 1.与 ADO.NET 的关系      Entity F ...

  2. hadoop docker ...

    hadoop docker ... 待办 昨天待办 decription decription 今日待办 decription decription decription decription had ...

  3. CI框架Email类发送邮件提示Unable to send data: . The following SMTP error was encountered: Unable to .......

    最近服务器迁移,然后CI框架做的项目发邮件全挂掉了,刚开始是25端口没开,然后开了正好还是有问题, 1.打印请求信息和返回信息 echo $this->email->print_debug ...

  4. 2019牛客多校第三场H Magic Line 思维

    Magic Line 题意 给出n(偶)个整点 整点范围1000,找出一条直线,把n个点分成均等的两部分 分析 因为都是整数,并且范围比较小,所以直接按x排序找到在中间那一部分,并且把中间那一部分的点 ...

  5. 题解 P6013 【压岁钱】

    月赛\(\text{Div2T1}\),窝唯一一道\(\text{AC}\)的题(我太菜啦!) \(\text{solution:}\) 根据题面,显然三个操作对应三种情况,我们发现每次这三种操作均不 ...

  6. Qt5 error LNK2019 无法解析的外部符号的解决办法

    今天在使用Qt Create 4.5.2时遇到一个莫名其妙的问题: 在原有工程里添加一个新类(有界面的),在调用的mainwindow.cpp中添加#include "a.h",然 ...

  7. vue+vuex项目中怎么实现input模糊查询

    1,首先给input框添加方法,但是用的是element-ui的组件,对input进行了封装,不能直接用原生的方法!,在element组件中,input框中方法有实例参数$event,代表事件对象  ...

  8. 吴裕雄 python 机器学习——数据预处理标准化MinMaxScaler模型

    from sklearn.preprocessing import MinMaxScaler #数据预处理标准化MinMaxScaler模型 def test_MinMaxScaler(): X=[[ ...

  9. 使用Newtonsoft序列化对象,实现深拷贝

    工作记录 深拷贝:全新创建一个对象,值与复制对象一致,两个对象互不相关,修改一个对象不会影响到另一个对象 浅拷贝:全新创建一个对象,值与复制对象一致,两个对象相关,修改一个对象影响到另一个对象 在工作 ...

  10. linux shell seq命令详解

    seq: squeue  是一个序列的缩写,主要用来输出序列化的东西 seq常见命令参数 用法:seq [选项]... 尾数 或:seq [选项]... 首数 尾数 或:seq [选项]... 首数 ...