一、我们之前在hibernate的时候,需要直接写事务,需要绑定当前线程保证获取同一个连接,虽然hibernate的帮我们封装绑定当前现成的操作,但是需要我们手动的去开启和关闭事务。
而spring帮我们自动管理事务。
二:事务:
spring 事务的隔离级别的定义:
TransactionDefinition
1. 事务隔离级别的常量
* static int ISOLATION_DEFAULT -- 采用数据库的默认隔离级别
* static int ISOLATION_READ_UNCOMMITTED
* static int ISOLATION_READ_COMMITTED
* static int ISOLATION_REPEATABLE_READ
* static int ISOLATION_SERIALIZABLE
PROPAGATION(propagation)传播的意思。
因为复杂的业务层之间的调用的话,会出现一个情况就是在业务方法中调用另一个业务方法,而这2个方法之间有事务的操作,针对这种情况,出现了事务的传递行为。
作用:解决业务之间的方法调用
需要掌握的:
1)PROPAGATION_REQUIRED(默认值):A B两个方法,A中有事务使用A的事务,如果没有B方法开启一个新的事务将A包含进来(B调用A的方法,保证AB在同一个事务中)。这个是默认值。
2)PROPAGATION_REQUIRES_NEW:--A中有事务,将A中的事务挂起,B创建一个新事物,(保证A B没有在同一个事务)。
3)PROPAGATION_NESTED(记):嵌套事务,当A执行之后,就会在这个位置设置一个保存点,如果B没有问题,执行通过,如果B出现异常,运行客户根据需求回滚(选择保存丶或者最初状态。)
三、spring事务设置:
接口:1)PlatformTransactionManager:platform平台,即平台事务管理器,该接口有实现类,根据不同的持久框架选择不同的实现类,我们需要关注的是:DataSourceTransactionManager和HibernateTransactionManager
2)TransactionDefinition接口:事务定义信息(事务的隔离级别、传播行为、超时、只读等。)
3)TransactionStatus接口:事务的状态
总结:上述对象之间的关系:平台事务管理器是真正管理事务的对象的。跟实物的定义信息(transactiondefinition)进行事务的管理,在管理事务中产生一些状态,将状态记录到transactionstatus中。
声明事务方式:两种方式:1)XML配置文件方式、
2)注解方式。
XML配置文件方式:
1、
将事务管理器注入到spring中:因为我们使用的jdbc所有使用DataSourceTransactionManager
1 <!--配置事务管理器--> 2 <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager" > 3 <property name="dataSource" ref="dataSource"/> 4 </bean>
需要设置dataSource属性值。
1 <property name="dataSource" ref="dataSource"/>
2、配置事务增强:
1 <tx:advice id="interceptor" transaction-manager="dataSourceTransactionManager"> 2 <tx:attributes> 3 <tx:method name="toaccount"/> 4 </tx:attributes> 5 </tx:advice>
注意:1)、使用标签<tx:advice> 子标签<tx:attributes> attributes说明可以配置多个tx:method 也就是说可以同时给多个service层的方法添加事务。
2)、标签:<tx:method> name属性为需要给那个方法添加事务。 propagation属性 传播行为采用Require 默认值(PROPAGATION_REQUIRED),isolation:事务级别,采取默认值,采用本地数据库事务级别。该标签可以写:<tx:method name="toaccount"/> 即可其他的传播行为和
事务级别采用默认值。
3)、transaction-manager属性是引用那个平台事务管理器的id值,我们使用的jdbc的事务管理器。
3、配置AOP切面:
1 <!--配置切面--> 2 <aop:aspectj-autoproxy expose-proxy="true"/> 3 <aop:config> 4 <aop:advisor advice-ref="interceptor" pointcut="execution(public * jd.com.UserService.UserServiceImpl.toaccount(..))"/> 5 </aop:config>
1)开启动态代理。
1 <aop:aspectj-autoproxy expose-proxy="true"/>
2)配置切面:使用标签<aop:config>
1 <aop:config> 2 <aop:advisor advice-ref="interceptor" pointcut="execution(public * jd.com.UserService.UserServiceImpl.toaccount(..))"/> 3 </aop:config>
3)注意:我们自己的写增强或者切面类的时候使用<aop:aspect>标签,使用的别人的增强的时候使用<aop:advisor>.
4)编写测试类:
1 package jd.com.UserService; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.test.context.ContextConfiguration; 6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 8 import javax.annotation.Resource; 9 10 11 @RunWith(SpringJUnit4ClassRunner.class) 12 @ContextConfiguration("classpath:applicationContext.xml") 13 public class TestDemo { 14 15 @Resource(name= "userService") 16 private UserService userService; 17 18 19 @Test 20 public void add(){ 21 System.out.println(11111113); 22 System.out.println(this.userService); 23 this.userService.toaccount(111,222); 24 } 25 }
service层:
1 package jd.com.UserService; 2 3 4 import jd.com.UserDao.userdao; 5 import org.springframework.stereotype.Service; 6 7 import javax.annotation.Resource; 8 9 10 public class UserServiceImpl implements UserService { 11 12 private userdao userdaoIMpl; 13 14 public void setUserdaoIMpl(userdao userdaoIMpl) { 15 this.userdaoIMpl = userdaoIMpl; 16 } 17 18 @Override 19 public void toaccount(int mon1, int mon2) { 20 21 System.out.println(this.userdaoIMpl); 22 userdaoIMpl.addMoney(mon1); 23 userdaoIMpl.delMoney(mon2); 24 } 25 }
持久层:
1 package jd.com.UserDao; 2 3 4 import javafx.scene.chart.ValueAxis; 5 import org.apache.commons.dbcp.BasicDataSource; 6 import org.springframework.jdbc.core.support.JdbcDaoSupport; 7 import org.springframework.stereotype.Repository; 8 9 import javax.annotation.Resource; 10 11 12 13 public class userdaoIMpl extends JdbcDaoSupport implements userdao { 14 15 16 @Override 17 public void addMoney(int mon) { 18 System.out.println(this.getDataSource()); 19 System.out.println(this.getJdbcTemplate()); 20 this.getJdbcTemplate().update(" UPDATE t_account SET money = money-? WHERE id = ? ",mon,1); 21 22 } 23 24 @Override 25 public void delMoney(int mon) { 26 this.getJdbcTemplate().update(" UPDATE t_account SET money = money+? WHERE id = ? ",mon,2); 27 } 28 }
2、第二种方法:注解方式
1)开启注解
1 <!--开启注解--> 2 <tx:annotation-driven transaction-manager="dataSourceTransactionManager" /> 3 <!--配置切面-->
2)配置管理器:
1 <!--配置事务管理器--> 2 <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager" > 3 <property name="dataSource" ref="dataSource"/> 4 </bean
3)在目标类或者目标方法加注解:
1 import jd.com.UserDao.userdao; 2 import org.springframework.stereotype.Service; 3 import org.springframework.transaction.annotation.Isolation; 4 import org.springframework.transaction.annotation.Propagation; 5 import org.springframework.transaction.annotation.Transactional; 6 7 import javax.annotation.Resource; 8 9 10 public class UserServiceImpl implements UserService { 11 12 private userdao userdaoIMpl; 13 14 public void setUserdaoIMpl(userdao userdaoIMpl) { 15 this.userdaoIMpl = userdaoIMpl; 16 } 17 18 @Transactional(isolation= Isolation.DEFAULT ,propagation = Propagation.REQUIRED) 19 @Override 20 public void toaccount(int mon1, int mon2) { 21 22 System.out.println(this.userdaoIMpl); 23 userdaoIMpl.addMoney(mon1); 24 userdaoIMpl.delMoney(mon2); 25 } 26 }
可以在注解内设置相应的参数 如果不设置可以直接使用@Transactional
1 @Transactional(isolation= Isolation.DEFAULT ,propagation = Propagation.REQUIRED)
也可以在类上加注解,那这个类下面的所有方法都受事务影响。