叉烧店并不卖叉烧

Spring @Transactional注释控制事务

spring TTT 74℃ 0评论

参考 参考2 参考3

使用Spring的@Transactional注释控制事务,需要在xml文件中配置以下内容

	<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
 
    <tx:annotation-driven transaction-manager="transactionManager" />

对于<beas>标签的内容如下:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

@Transactional注释方式

当标于类前,表示类中的所有方法都进行事务处理

@Transactional
public class TTest implements ITTest{
}

当标于方法前,表示该方法进行事务处理

@Transactional
public AppointExecution appoint(long bookId, long studentId) {
}

当类中某些方法不需要事务时

@Transactional
public class TTest {
	private IUserDao dao;
	public void setDao(IUserDao dao) {
		this.dao = dao;
	}
	@Transactional(propagation = Propagation.NOT_SUPPORTED)
	public List getList() {
		return null;
	}
}

事务传播行为

@Transactional(propagation=Propagation.REQUIRED):如果有事务,那么加入事务,没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED):容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新事务原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY):必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER):必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS):如果其他bean调用这个方法,在其他bean中声明事务,那就用事务,如果其他bean没有声明事务,那就不用事务

事务超时设置

@Transactional(timeout=30) // 默认是30秒

事务隔离级别

@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,不可重复读)基本不用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已经提交的数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化

MySQL:默认为REPEATABLE_READ级别
SQL Server:默认为READ_COMMITTED级别

脏读:一个事务读取到另一个事务未提交的更新数据
不可重复读:在同一事务中,多次读取同一个数据返回的结果不同,换句话说后续读取可以读到另一个事务已经提交的更新数据
可重复读:在同一事务多次读取数据时,能够保证每次读取的数据都先沟通相同,也就是后续读取不能读取到另一个事务已经提交的更新书

@Transactional注解中常用的参数说明

参数名称

功能描述


readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)


rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})


rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”)

指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})


noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})


noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)

指定多个异常类名称:

@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})


propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)


isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置


timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

注意点

1.@Transacional只能被应用到public方法上,对于其他非public方法,如果标记了@Transactional方法也不会报错,但方法没有事务功能

2.默认情况下,如果在事务中抛出了未检查异常(继承自RuntimeException的异常)或者Error,则Spring将回滚事务;除此之外,Spring不会回滚事务

如果在事务中抛出其他类型的异常,并期望Spring能够回滚事务,可以指定rollbackFor。例如

@Transactional(propagation=Propagation.REQUIRED, rollbackFor=MyException.class)

通过分析Spring源码可以知道,若在目标方法中抛出的异常是rollbackFor指定的异常的子类,事务同样会回滚

清单1.RollbackRuleAttribute的getDepth方法

private int getDepth(Class<?> exceptionClass, int depth) {
        if (exceptionClass.getName().contains(this.exceptionName)) {
            // Found it!
            return depth;
}
        // If we've gone as far as we can go and haven't found it...
        if (exceptionClass == Throwable.class) {
            return -1;
}
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}

?避免Spring的AOP自调用问题

在Spring的AOP代理下,只有目标方法由外部调用,目标方法才由Spring生成的代理对象来管理,这会造成自调用问题。若同一个类中的其他没有@Transactional注解的方法内部调用有@Transactional注解的方法,有@Transactional注解的方法的事务会被忽略不会发生回滚。见清单举例代码

自调用问题举例

@Service
-->public class OrderService {
    private void insert() {
insertOrder();
}
@Transactional
    public void insertOrder() {
        //insert log info
        //insertOrder
        //updateAccount
       }
}

insertOrder尽管有@Transactional注解,但它被内部方法insert调用,事务被忽略,出现异常不会发生回滚

使用 AspectJ代理

上面两个问题@Transactional注解只应用到public方法和自调用问题,是由于使用SpringAOP代理造成的。为解决这两个问题,使用AspectJ取代Spring AOP代理

需要将下面的AspectJ信息添加到xml配置信息中

AspectJ的xml配置信息

<tx:annotation-driven mode="aspectj" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</bean
class="org.springframework.transaction.aspectj.AnnotationTransactionAspect"
factory-method="aspectOf">
<property name="transactionManager" ref="transactionManager" />
</bean>

同时在Maven中的pom文件加入spring-aspects和aspectjrt的dependency以及aspect-maven-plugin

AspectJ的pom配置信息

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.9</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>

转载请注明:叉烧店 » Spring @Transactional注释控制事务

喜欢 (0)
发表我的评论
取消评论

CAPTCHA Image
Reload Image
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址