spring事务管理

SpringMvc事务管理 Aop的xml配置方式和注解配置方法详解

1、介绍

事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务就将回到最开始的状态,仿佛一切都没发生过,而通常我们的事务操作都是在业务层中,所以一下的事务管理当加持在Service类上。Spring事务是基于面向切面编程(Aspect Oriented Programming,AOP)实现的(文中会简单讲解AOP)。Spring的事务属性分别为传播行为、隔离级别、回滚规则、只读和事务超时属性,所有这些属性提供了事务应用方法和描述策略。

2、Spring提供了两种事务管理方式

a、编程序事务管理
编写程序式的事务管理可以清楚的定义事务的边界,可以实现细粒度的事务控制,比如你可以通过程序代码来控制你的事务何时开始,何时结束等
b、声明式事务管理 其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
如果你并不需要细粒度的事务控制,你可以使用声明式事务,在Spring中,你只需要在Spring配置文件中做一些配置,即可将操作纳入到事务管理中,解除了和代码的耦合, 这是对应用代码影响最小的选择,从这一点再次验证了Spring关于AOP的概念。当你不需要事务管理的时候,可以直接从Spring配置文件中移除该设置

声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。
下面注重介绍声明式事务管理的配置方法

pom.xml加入依赖spring-tx4.3.17

3、xml配置方法:

1、在applicationContext.xml中加入的配置依次如下

<<?xml version="1.0" encoding="UTF-8"?>
<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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd
     http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
     <!-- 包扫描   扫描指定包下的备注的类  自动注入bean-->
    <context:component-scan base-package="com.yc"></context:component-scan>
   
	
<!-- 	我这里用的是springMvc进行演示  如果君用的是spring 可忽略掉1 2 3 4两段配置 -->
		<!--1   mybatis 数据源      -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!--2     加入mapper的扫描 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.yc.cars.dao" />
</bean>

  <!--3 mvc注解驱动 -->
	<mvc:annotation-driven></mvc:annotation-driven>
	
	<!--4  加入mapper的扫描 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.yc.cars.dao" />
</bean>
    
    	<!-- 配置spring的数据源  也叫连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1/cars"/>
    <property name="username" value="root"/>
    <property name="password" value="a"/>
</bean>

<!-- 事务管理 -->
<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

    <!-- spring事务增强  配置事务通知 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
          <!-- 以方法为单位,指定拦截login方法   应用什么事务属性 isolation:隔离级别 propagation:传播行为  read-only:是否只读  timeout 超时 -1不超时-->
            <tx:method name="login*" read-only="true" isolation="REPEATABLE_READ"
                propagation="REQUIRED"  timeout="-1" />
        </tx:attributes>
    </tx:advice>   
    
<!--aop配置织入,拦截哪些方法(切入点表达式,拦截上面的事务增强)-->
    <aop:config>
        <!-- 配置切点表达式  expression指定拦截的包下所有类的方法  遇到login机会进行事务增强 -->
        <aop:pointcut expression="execution(* com.yc.cars.biz.*.*(..))" id="txPc" />
        <!-- 配置切面 : 通知+切点 advice-ref:通知的名称 pointcut-ref:切点的名称 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
    </aop:config>

    </beans>

tx:method/的设置
name:要与事务属性关联的方法名。通配符()字符可用于将相同的事务属性设置与多个方法相关联;例如 get,handle*,on*Event

xml配置业务方法
//该业务类的login方法拦截已经在xml中配置了  此处的@Service注解与aop无关,是springmvc的注解,此注解替代了xml文件中<bean>注入
@Service
public class UserInfoBiz {
	@Resource 
	private UserInfoMapper umapper;
	public UserInfo login(UserInfo user) throws Exception
	{
		if(user.getName()!=null&&user.getName().trim().isEmpty())
		{
			throw new BizException("请输入用户名");
		}
		if(user.getPwd() !=null&&user.getPwd().trim().isEmpty())
		{
			throw new BizException("请输入密码");
		}
		
		UserInfoExample example=new UserInfoExample();
		example.createCriteria()
		.andNameEqualTo(user.getName())
		.andPwdEqualTo(user.getPwd());
		List<UserInfo> list=umapper.selectByExample(example);
		if(list.size()==0)
		{
			throw new Exception("用户名或者密码错误!");
		}
		return list.get(0);
		
	}

}
xml配置的测试类:
@RunWith(SpringRunner.class)
//此处将参数换成配置的xml
@ContextConfiguration("/applicationContext.xml")
public class UserInfoMapperTest {
	
	@Resource
	private UserInfoMapper umapper;
	
	@Test//下面的操作代码不需要理解,只需要知道业务类调用在下面即可
	public void test()
	{
		//查询所有
		/*umapper.selectByPrimaryKey(1);
		umapper.selectByExample(null);*/
		
		//查询指定用户名
		UserInfoExample uie=new UserInfoExample();
		
		uie.createCriteria().andNameEqualTo("张三");
		umapper.selectByExample(uie);
		
		uie=new UserInfoExample();
		Criteria c=uie.createCriteria();
		c.andNameLike("%三%");
		c.andPwdEqualTo("123");
		c.andEmailLike("%123%");
		umapper.selectByExample(uie);
		
	}

}

4、事务注入的注解方式;

a、在xml文件中将tx标签和aop标签屏蔽,保留数据源和jdc模板的bean 再加入一行代码即可<tx:annotation-driven transaction-manager=“txManager”/>
b、则在需要拦截的事务类上方加入注解@Transactional(rollbackFor={BizException.class})

注解方式xml的修改:
<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:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd
     http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">
     <!-- 包扫描   扫描指定包下的备注的类  自动注入bean-->
    <context:component-scan base-package="com.yc"></context:component-scan>
   
	
<!-- 	我这里用的是springMvc进行演示  如果君用的是spring 可忽略掉1 2 3 4两段配置 -->
		<!--1   mybatis 数据源      -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
	</bean>
	
	<!--2     加入mapper的扫描 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.yc.cars.dao" />
</bean>

  <!--3 mvc注解驱动 -->
	<mvc:annotation-driven></mvc:annotation-driven>
	
	<!--4  加入mapper的扫描 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="com.yc.cars.dao" />
</bean>
    
    	<!-- 配置spring的数据源  也叫连接池-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1/cars"/>
    <property name="username" value="root"/>
    <property name="password" value="a"/>
</bean>

<!-- 事务管理 -->
<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

<!-- 事务注解驱动  transaction-manager 属性写有  在class上方就不需要在写该属性-->
<tx:annotation-driven transaction-manager="txManager"/>

    </beans>
注解方式的业务类写法;
@Service
//事务管理注解在类上    因为spring容器的事务回滚值会自动回滚系统自带的运行期异常,自定义的异常无法回滚,此时需要我们为自定义的异常设置回滚功能 
//或者在此括号里加入事务增强参数@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
//此处不做过多诠释,文章末尾会介绍事务增强的属性
@Transactional(rollbackFor=BizException.class)
public class UserInfoBiz {
	@Resource 
	private UserInfoMapper umapper;
	public UserInfo login(UserInfo user) throws Exception
	{
		if(user.getName()!=null&&user.getName().trim().isEmpty())
		{
			throw new BizException("请输入用户名");
		}
		if(user.getPwd() !=null&&user.getPwd().trim().isEmpty())
		{
			throw new BizException("请输入密码");
		}
		
		UserInfoExample example=new UserInfoExample();
		example.createCriteria()
		.andNameEqualTo(user.getName())
		.andPwdEqualTo(user.getPwd());
		List<UserInfo> list=umapper.selectByExample(example);
		if(list.size()==0)
		{
			throw new Exception("用户名或者密码错误!");
		}
		return list.get(0);
		
	}

}
注解方式的测试类:同xml配置的测试类

5、spring事务的传播行为:

常用;
REQUIRED;业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务
REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行
SUPPORTS:
这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行
不常用:
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行
MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
Neve:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按REQUIRED属性执行.它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效

Spring事务的隔离级别:
DEFAULT 使用后端数据库默认的隔离级别(spring中的的选择项)
READ_UNCOMMITED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读和不可重复读仍可发生
REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。
SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。

脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据是无效的。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了。再后来的查询中,第一个事务就会发现有些原来没有的记录。
序列操作:完全遵循ACID事务四大原则 同时也带来性能的底下

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值