Spring中的事务管理

配置注解

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

创建事务bean,配置数据源属性

<tx:annotation-driven transaction-manager="transactionManager" /> 

事务注解驱动

 

声明式事务

@Transactional
public void hasTranInsertData() {
    Book book = new Book();
        
    book.setIsbn("0002");
    book.setBookName("java编程思想");
    book.setPrice(79);
        
    this.bookMapper.insertSelective(book);
        
    int i = 1 / 0;
}
public void notHasTranInsertData() {
    Book book = new Book();
        
    book.setIsbn("0003");
    book.setBookName("算法导论");
    book.setPrice(109);
        
    this.bookMapper.insertSelective(book);
        
    int i = 1 / 0;
}

以上可以看出上面的数据回滚了,而下面的保存到数据库了。

 

事务的传播

REQUIRED 如果现有的事务正在进行,当前方法应该在这个事务中运行,否则它该启动新事务,并在自己的十五中运行。
REQUIRES_NEW 当前方法必须启动新事务,并在自己的事务中运行,如果现有的事务正在进行,它应该挂起。
SUPPORTS 如果现有事务正在进行,当前方法应该运行在该事务中,否则它没有必要运行在事务中。
NOT_SUPPORTED 当前方法不应该运行在事务中,如果现有事务正在运行,它应该挂起。
MANDATORY 当前方法必须运行于事务中,如果没有事务在进行中,将抛出一个异常。
NEVER 当前方法不应该运行于事务中,如果现有事务在运行中,将抛出一个异常。
NESTED 如果现有事务正在进行,当前方法应该运行在嵌套的事务中,否则它应该启动一个新事务并运行在自己的事务之中。

 

 

 

 

 

 

 

例如:

@Override
@Transactional
public void nestedBook() {
        
    Book book = new Book();
        
    book.setIsbn("0004");
    book.setBookName("分布式架构");
    book.setPrice(89);
        
    this.bookMapper.insertSelective(book);
        
    for (int i = 0; i < 10; i ++) {
        try {
            this.testService1.nestedAccount(i + 2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
        
}
@Override
@Transactional(propagation=Propagation.NESTED)
public void nestedAccount(int i) {
    System.out.println(i);
    Account account = new Account();
    account.setUsername("user" + i);
    account.setBalance(new Random().nextInt(100));
        
    this.accountMapper.insertSelective(account);
        
    if (7 == i) {
        int j = 1 / 0;
    }
}

这里一个REQUIRED事务去调用NESTED事务,NESTED特性是在嵌套的事务里,如果发生异常他只会回滚他自己的事务,而不会影响调用他的事务。

他与REQUIRES_NEW的区别是,前面方法没有事务是每次需要创建自己的事务,如果前面有事务时,前面方法如果报错了会回滚所有操作,而REQUIRES_NEW不会回滚操作。

NESTED的好处在于既能保证前者方法抛异常时所有数据能回滚,也能保证后者方法一个抛异常不会影响后续的操作,只会回滚后者操作失败的数据。

 

隔离事务

DEFAULT 使用底层数据库的默认隔离级别。对于大部分数据库,默认隔离级别是READ_COMMITED,mysql是REPEATABLE_READ
READ_UNCOMMITED 允许事务读取其他事务的未提交修改。可能发生脏读数据、不可重复读幻读问题。
READ_COMMITED  仅允许事务读取其他事务已经提交的修改。能够避免脏读数据问题,但是不可重复读幻读问题仍然可能发生。
REPEATABLE_READ 确保事务能够多次从一个字段读到相同值。在本事务期间,其他事务的更新被禁止。能够避免脏读数据和不可重复读问题,但是幻读问题仍然可能发生。
SERIALIZABLE 确保一个事务能从表中多次读取相同的行。在事务期间,其他事务做出的对该表插入、更新和删除将被禁止。能避免所有并发性问题,但是性能将会很

 

 

 

 

 

 

 

 

RollBack属性

默认情况下,只有非受控异常(也就是RuntimeExceptionError类型)将导致事务回滚,而受控异常不会。

@Override
@Transactional
public void hasTranInsertData() throws FileNotFoundException, ClassNotFoundException {
    Book book = new Book();
        
    book.setIsbn("0005");
    book.setBookName("java编程思想");
    book.setPrice(79);
        
    this.bookMapper.insertSelective(book);
        
    try {
        int i = 1 / 0;
    } catch (Exception e) {
        throw new FileNotFoundException("错误");
    }
}

严重警告:上面的这段代码是不会回滚的,就因为抛出的异常时受控异常

 

rollbackFor:会发生回滚的异常

noRollbackFor:不会发生回滚的异常

将@Transaction变为下面这样

@Transactional(rollbackFor=FileNotFoundException.class, noRollbackFor=ClassNotFoundException.class)

改变之后就会进行回滚

如果抛出的异常改为

throw new ClassNotFoundException("错误");

则又不会回滚

 

超时和只读

timeout:表示事务在被强制回滚之前存活的时间。这能够避免长时间的事务占用资源。

readOnly:表示该事务仅仅读取而不更新数据。只读标志只是让资源优化事务的一个提醒,如果试图写入,资源不一定会发生故障。

 

posted @ 2018-03-31 16:50  huanStephen  阅读(244)  评论(0编辑  收藏  举报