2. Spring的声明式事务式通过AOP实现的
1. 基于 TransactionProxyFactoryBean (很少使用) 2. 基于 AspectJ的XML方式 (经常使用) 一旦配置好了,不需要在添加任何东西 3. 基于 注解 (经常使用) 配置简单,需要在每个业务层类上面加 @Transcational 注解
做的一个实例 是 转账问题 a 转 b 两个人的账户相应增加,减少,当发生异常,则事务不进行提交,a,b的金额没有发生改变
在 SpringTest 测试类中 需要加入 @RunWith(SpringJUnit4ClassRunner.class) // //使用junit4进行测试 @ContextConfiguration("classpath:applicationContext.xml") // 加载配置文件 这两个注解
搭建测试环境
userDao,userDaoImpl
import org.springframework.jdbc.core.support.JdbcDaoSupport; public class UserDaoImpl extends JdbcDaoSupport implements UserDao{ @Override public void outPrice(String name, double price) { // TODO Auto-generated method stub String sql = "update user set price = price - ? where username = ?"; this.getJdbcTemplate().update(sql,price,name); } @Override public void intPrice(String name, double price) { // TODO Auto-generated method stub String sql = "update user set price = price + ? where username = ?"; this.getJdbcTemplate().update(sql,price,name); } } public interface UserDao { /** * 转账 */ public void outPrice(String name,double price); /** * 收账 */ public void intPrice(String name,double price); }userService,userServiceImpl
public interface UserService { public void out(String name,String name2,double price); } import javax.annotation.Resource; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; public class UserServiceImpl implements UserService{ @Resource(name="userDao") public UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } // 事务模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void out(String name, String name2, double price) { // TODO Auto-generated method stub transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus tr) { // TODO Auto-generated method stub userDao.intPrice(name, price); int a = 1 / 0; userDao.outPrice(name2, price); } } ); } }1. 编程式的事务管理
在 service 中使用TransactionTemplate TransactionTemplate 依赖 DataSourceTransactionManager DataSourceTransactionManager依赖DataSource构造 1.1 在 applicationContext 中配置事务管理器
<?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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd" > <!-- 数据库配置文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 创建数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" > <property name="driverClassName" value="${driver}"></property> <property name="url" value="${url}"></property> <property name="username" value="${name}"></property> <property name="password" value="${password}"></property> <property name="maxActive" value="10"></property> <property name="maxIdle" value="5"></property> </bean> <!-- 配置数据层 --> <bean id="userDao" class="com.zyh.UserDaoImpl" scope="prototype"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置业务层 --> <bean id="userService" class="com.zyh.UserServiceImpl" scope="prototype"> <property name="userDao" ref="userDao"></property> <!-- 注入事务管理的模板 --> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <!-- 编程式的事务管理 --> <!-- 创建事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 将数据连接注入过来 --> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 创建一个 事务管理模板 简化 底层代码 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <!-- 将真正进行事务管理的 注入进来 --> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>1.2 在 service 实现类中注入 transactionTemplate 模板来实现事务管理
// 当在service 方法中注入了transactionTemplate 那么在 applicationContext 中相应的 service // 也注入transactionTemplate private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate){ this.transactionTemplate = transactionTemplate; } 然后调用 transactionTemplate 中的方法 execute 此方法呢需要一个匿名内部类 new TransactionCallbackWithoutResult(){ @Override protected void doInTransactionWithoutResult(TransactionStatus tr) { // TODO Auto-generated method stub userDao.intPrice(name, price); int a = 1 / 0; userDao.outPrice(name2, price); } }1.3 然后进行测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringTest { @Resource(name="userService") public UserService userService; public void setUserService(UserService userService) { this.userService = userService; } @Test public void springDemo() { userService.out("aaa", "bbb", 200); } }然后查看数据库,发现中间发生异常,事务是不会提交的
2. spring声明式的事务管理
声明式的事务管理是基于spring aop思想的
将环境恢复到 一开始状态,(将所有的关于 transactionTemplate 的都删除)
1. 配置事务管理 <!-- 创建事务管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 将数据连接注入过来 --> <property name="dataSource" ref="dataSource"></property> </bean>2. 配置代理 <!-- 配置 代理 --> <bean id="userServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!-- 配置目标对象 --> <property name="target" ref="userService"></property> <!-- 注入事务管理 --> <property name="transactionManager" ref="transactionManager"></property> <!-- 注入事务属性 --> <property name="transactionAttributes"> <props> <!-- prop格式: PROPAGATION : 事务的传播行为 ISOLATION : 事务的隔离级别 readOnly : 只读 -Exception : 发生哪些异常回滚事务 +Exception : 发生那修异常事务不会滚 --> <prop key="out">PROPAGATION_REQUIRED</prop> </props> </property> </bean> 然后service层不需要再进行修改了,只需要修改SpringTest将userService的 注入换为 userServiceProxy
import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class SpringTest { /** * 注入代理类 */ // @Resource(name="userService") @Resource(name="userServiceProxy") public UserService userService; @Test public void springDemo() { userService.out("aaa", "bbb", 200); } }然后进行测试.成功, 当有异常的时候是不会进行 事务提交,没有异常正常提交事务.
然后在 配置文件 bean userServiceProxy 的 事务属性中
<!-- 注入事务属性 --> <property name="transactionAttributes"> <props> <!-- prop格式: PROPAGATION : 事务的传播行为 ISOLATION : 事务的隔离级别 readOnly : 只读 -Exception : 发生哪些异常回滚事务 +Exception : 发生那修异常事务不会滚 --> <prop key="out">PROPAGATION_REQUIRED,readOnly</prop> </props> </property>多配置一个readonly 然后进行测试会 报异常
因为进行的是修改操作.所有当设置为只读的话 就会报异常
上面那个是第一种方式 基于 TransactionProxyFactoryBean的原始方式 缺点 只能对一个业务层类 管理,当有多个模块的话就需要配置多个Proxy来实现事务管理 声明式事务管理,第二种方式As
在 applicationConext 中
<!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- propagation : 事务传播行为 isolation : 事务隔离级别 readOnly : 只读 rollback-for : 发生哪些异常回滚 no-rollback-for: 发生哪些异常不回滚 timeout : 过期信息 --> <tx:method name="out" propagation="REQUIRED" isolation="DEFAULT" /> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* zyh.UserService+.*(..))" id="pointcut1"/> <aop:advisor advice-ref="pointcut1" pointcut="pointcut1"/> </aop:config> 这种方式的只需要在配置文件配置后就可以 实现对事务管理, 代理对象在对应类生成时生成 第三种 基于注解的 声明式事务管理 <!-- 开启事务注解 --> <tx:annotation-driven transaction-manager="transactionManager"/> 然后只需要在 指定的类上面添加Transactional /** * propagation : 事务传播行为 isolation : 事务隔离级别 readOnly : 只读 rollback-for : 发生哪些异常回滚 no-rollback-for: 发生哪些异常不回滚 timeout : 过期信息 */ @Transactional public class UserServiceImpl implements UserService
