事务的隔离级别疑惑

package com.alibaba.tboss.biz.demo.transaction;

public interface IsolationBiz {

    // /**
    // * 这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition. ISOLATION_READ_COMMITTED。
    // */
    public void defaultLevel();

    // /**
    // * 该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
    // */
    public void readCommit();

    // /**
    // * 该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读和不可重复读,因此很少使用该隔离级别。
    // */
    public void readUncommit();

    // /**
    // * 该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。即使在多次查询之间有新增的数据满足该查询, 这些新增的记录也会被忽略。该级别可以防止脏读和不可重复读。
    // */
    public void repeatableRead();

    // /**
    // * 所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。 通常情况下也不会用到该级别。
    // */
    public void serializable();
}

上面的代码配置了事务的隔离级别,再看它的实现类,代码如下:

public class IsolationBizImpl implements IsolationBiz {
    private static Logger logger = LoggerFactory.getLogger(IsolationBizImpl.class);
    @Autowired
    private CallerBiz     callerBiz;

    @Override
    @Transactional(isolation = Isolation.DEFAULT)
    public void defaultLevel() {
        callerBiz.addTeacherWithDeleteAll("Isolation.DEFAULT");
        sleep();
    }

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void readCommit() {
        callerBiz.addTeacherWithDeleteAll("Isolation.READ_COMMITTED");
        sleep();
    }

    @Override
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public void readUncommit() {
        callerBiz.addTeacherWithDeleteAll("Isolation.READ_UNCOMMITTED");
        sleep();
    }

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void repeatableRead() {
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public void serializable() {
        callerBiz.addTeacherWithDeleteAll("Isolation.SERIALIZABLE");
        sleep();
    }

    private void sleep() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            logger.error(" IsolationBizImpl_sleep_error:", e);
        }
    }
}

针对项目中的这段代码,有两个疑问:
1.明明defaultLevel方法使用的就是READ_COMMITTED的隔离级别,为什么它要专门弄出一个默认的值??它在本质上还是READ_COMMITTED隔离级别的啊?
2.为什么在实现类中,每个隔离级别的实现类的方法中都要sleep()一会儿?

public interface CallerBiz {
    void propagationRequired();

    void propagationSupports();

    void propagationMandatory();

    void propagationRequiresNew();

    void propagationNotSopported();

    void propagationNever();

    void addTeacherWithDeleteAll(String name);

    void addTeacherWithoutDeleteAll(String name);

    void roolBackException();
}

在上述代码中,IsolationBiz和CallerBiz之间的关系是抽象工厂模式,在CallerBiz的实现类中代码如下:

public class CallerBizImpl implements CallerBiz {
    private static Logger        logger = LoggerFactory.getLogger(CallerBizImpl.class);
    @Autowired
    private PropagationBiz       propagationBiz;
    @Autowired
    private DemoTeacherBo        demoTeacherBo;
    @Autowired
    private PrivilegeInfo        privilegeInfo;
    @Autowired
    private DemoTeacherMapperExt demoTeacherMapperExt;

    @Override
    public void propagationRequired() {
        String name = "co@Propagation.REQUIRED";
        addTeacherWithDeleteAll(name);
        propagationBiz.required(name);
    }

    @Override
    public void propagationSupports() {
        String name = "co@Propagation.SUPPORTS";
        addTeacherWithDeleteAll(name);
        propagationBiz.supports(name);
    }

    @Override
    public void propagationMandatory() {
        String name = "co@Propagation.MANDATORY";
        addTeacherWithDeleteAll(name);
        propagationBiz.mandatory(name);
    }

    @Override
    public void propagationRequiresNew() {
        String name = "co@Propagation.REQUIRES_NEW";
        addTeacherWithDeleteAll(name);
        try {
            propagationBiz.requiresNew(name);
        } catch (Exception e) {
            logger.error(" CallerBizImpl_propagationRequiresNew_error:", e.getMessage(), e);
        }
    }

    @Override
    public void propagationNotSopported() {
        String name = "co@Propagation.NOT_SUPPORTED";
        addTeacherWithDeleteAll(name);
        try {
            propagationBiz.notSopported(name);
        } catch (Exception e) {
            logger.error(" CallerBizImpl_propagationNotSopported_error:", e.getMessage(), e);
        }
    }

    @Override
    public void propagationNever() {
        String name = "co@Propagation.NEVER";
        addTeacherWithDeleteAll(name);
        propagationBiz.never(name);
    }

    @Override
    public void addTeacherWithDeleteAll(String name) {
        addTeacher(name, true);
    }

    @Override
    public void addTeacherWithoutDeleteAll(String name) {
        addTeacher(name, false);
    }

    @Override
    @Transactional
    public void roolBackException() {
        addTeacher("roolBackException", false);
        throw new BizException();
    }

    private void addTeacher(String name, boolean deleteAll) {
        if (deleteAll) {
            for (DemoTeacher temp : demoTeacherMapperExt.selectByExample(new DemoTeacherExample())) {
                demoTeacherMapperExt.deleteByPrimaryKey(temp);
            }
        }

        DemoTeacher teacher = new DemoTeacher();
        teacher.setName(name);
        teacher.setDescription(name);
        DomainUtil.setCommonValueForCreate(teacher, privilegeInfo);
        demoTeacherMapperExt.insertSelective(teacher);
    }
}

上述代码定义了spring的传播特性,同样的问题:
1.此处定义的代码是如何发挥传播机制的作用的?也没有找到引用部分啊?

补充代码,在CallerBizImpl注入了PropagationBiz,代码如下:

public interface PropagationBiz {

    // /**
    // * 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。(默认情况下)
    // */
    public void required(String name);

    // /**
    // * 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    // */
    public void supports(String name);

    //
    // /**
    // * 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
    // */
    public void mandatory(String name);

    // /**
    // * 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    // */
    public void requiresNew(String name);

    // /**
    // * 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    // */
    public void notSopported(String name);

    //
    // /**
    // * 以非事务方式运行,如果当前存在事务,则抛出异常。(与Propagation.MANDATORY相反)
    // */
    public void never(String name);

    // /**
    // * 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.
    // * PROPAGATION_REQUIRED。<br>
    // * PROPAGATION_NESTED是 Spring 所特有的。以 PROPAGATION_NESTED
    // * 启动的事务内嵌于外部事务中(如果存在外部事务的话
    // * ),此时,内嵌事务并不是一个独立的事务,它依赖于外部事务的存在,只有通过外部的事务提交,才能引起内部事务的提交,嵌套的子事务不能单独提交。如果熟悉
    // * JDBC 中的保存点(SavePoint)的概念,那嵌套事务就很容易理解了,其实嵌套的子事务就是保存点的一个应用,一个事务中可以包括多个保存点,
    // * 每一个嵌套子事务。另外,外部事务的回滚也会导致嵌套子事务的回滚。
    // */
    public void nested(boolean rollBack, String name);
}

其实现类代码如下:

public class PropagationBizImpl implements PropagationBiz {
    @Autowired
    private DemoTeacherBo demoTeacherBo;
    @Autowired
    private PrivilegeInfo pvgInfo;
    @Autowired
    private CallerBiz callerBiz;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void required(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
        throw new BizException();
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public void supports(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
        throw new BizException();
    }

    @Override
    @Transactional(propagation = Propagation.MANDATORY)
    public void mandatory(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requiresNew(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
        throw new BizException();
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void notSopported(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
        throw new BizException();
    }

    @Override
    @Transactional(propagation = Propagation.NEVER)
    public void never(String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
    }

    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void nested(boolean rollBack, String name) {
        callerBiz.addTeacherWithDeleteAll("callee@" + name);
        if (rollBack) {
            throw new BizException();
        }
    }
}
阅读 3.3k
1 个回答

1.就我所知Mysql的默认隔离级别是repeatable read,Oracle等多数数据库默认隔离级别是Read Committed,所以这边的defaultLevel起的是适配作用吧

3.
下面这段解释我觉得很好理解这个问题http://javasam.iteye.com/blog/1902177

由于Spring的事务管理是通过线程相关的ThreadLocal来保存数据访问基础设施的(Connection对象),再结合IoC和AOP实现高级声明式事务的功能,所以Spring的事务天然的和线程有着千丝万缕的关系。

Spring通过ThreadLocal可以将大部分Bean无状态化(线程安全的)所以Spring中单实例Bean对线程安全问题拥有一种天然的免疫力。

所以Spring中DAO和Service都以单实例的方式存在,Spring将有状态的变量(Connection)本地线程化,达到另一个层面上的线程无关,从而实现线程无关。

 在相同的线程中进行相互嵌套调用的事务方法工作于相同的事务中,不同的线程中,则各自独立工作与独立的事务中。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题