Spring事务管理
TransactionDefinition:
业务的传播行为:
为的是解决业务层方法之间的相互调用问题(一个service层里的方法调用另一个service里中的方法,这两个service中又分属于两个不同的事务,传播行为就是为了解决方法调用时事务的传递)
业务:实现转账功能,需保证业务的事务性
构思:
业务层:继承一个Service接口,该接口实现转账方法;
Dao层:继承Dao接口,实现具体的转入和转出功能
Dao层的参数从Service实现类传入(转出、转入、转账值)
编程式的业务管理:
Service实现类:
package com.spring.demo1; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; //转账案例实现类 public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //注入事务管理模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transfer(final String out, final String in, final Double money) { // TODO Auto-generated method stub transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { // TODO Auto-generated method stub accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }); } }
这里通过事务管理模板的注入,使用其内置方法对业务进行事务处理
Dao实现类:
package com.spring.demo1; import org.springframework.jdbc.core.support.JdbcDaoSupport; //转账案例Dao的实现类 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void outMoney(String out, Double money) { // TODO Auto-generated method stub String sql = "update account set money = money - ? where name = ?"; this.getJdbcTemplate().update(sql,money,out); } @Override public void inMoney(String in, Double money) { // TODO Auto-generated method stub String sql = "update account set money = money + ? where name = ?"; this.getJdbcTemplate().update(sql,money,in); } }
这里通过继承JdbcDaoSupport类,里面定义了一个dataSource参数,将实例化的连接池传入这个参数后即可连接到数据库;再调用getJdbcTemplate方法对sql语句进行执行操作;
相关的spring.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:c="http://www.springframework.org/schema/c" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" 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"> <context:property-placeholder location = "classpath:jdbc.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 在Dao层直接通过继承JdbcDaoSupport接口,在这实例化时对接口里定义好的参数:DataSource,进行注入连接池,使Dao层连接数据库成功 --> <bean id="accountDao" class="com.spring.demo1.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountService" class="com.spring.demo1.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></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>
运行类或测试类:
package com.spring.demo1; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.spring.demo2.AccountServiceImpl; public class test01 { public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); AccountServiceImpl bean = context.getBean("accountService",AccountServiceImpl.class); bean.transfer("aaa", "bbb", 200.0); System.out.println("hahha"); } }
这种是通过先配置好连接数据库的配置文件,再配置连接池,进而配置事务管理器,形成对应的事务管理模板,在调用模板里的方法进行与数据库的交互;
声明式的业务管理器(一)<xml形式>:
这里的事务的实现更像是AOP那种,通过实例化一个代理类,在代理类中添加事务管理器,以及管理的事务属性:
业务Service实现类:
package com.spring.demo2; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; //转账案例实现类 public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //注入事务管理模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transfer(final String out, final String in, final Double money) { // TODO Auto-generated method stub accountDao.outMoney(out, money); //int i = 6/0; accountDao.inMoney(in, money); } }
Dao实现类:
package com.spring.demo2; import org.springframework.jdbc.core.support.JdbcDaoSupport; //转账案例Dao的实现类 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void outMoney(String out, Double money) { // TODO Auto-generated method stub String sql = "update account set money = money - ? where name = ?"; this.getJdbcTemplate().update(sql,money,out); } @Override public void inMoney(String in, Double money) { // TODO Auto-generated method stub String sql = "update account set money = money + ? where name = ?"; this.getJdbcTemplate().update(sql,money,in); } }
Spring2.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:c="http://www.springframework.org/schema/c" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" 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"> <context:property-placeholder location = "classpath:jdbc.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="accountDao" class="com.spring.demo2.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountService" class="com.spring.demo2.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置业务层的代理 --> <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="target" ref="accountService"></property> <property name="transactionManager" ref="transactionManager"></property> <property name="transactionAttributes"> <!-- prop的格式: PROPAGATION:事务的传播行为 ISOLATION:事务的隔离级别 readOnly:只读 -Exception:发生哪些异常时回滚事务 +Exception:发生哪些异常时不回滚事务 --> <props> <prop key="transfer"> PROPAGATION_REQUIRED </prop> </props> </property> </bean> </beans>
测试或运行类:
package com.spring.demo2; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.spring.demo2.AccountServiceImpl; public class test01 { public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext context = new ClassPathXmlApplicationContext("spring2.xml"); AccountService bean = (AccountService)context.getBean("accountServiceProxy"); bean.transfer("aaa", "bbb", 200.0); System.out.println("hahha"); } }
这里需要实例化的时候不是原本的"accountService",而是"accountServiceProxy";
可对比编程式的事务管理,申明式的管理基本无需改动Servicr里的代码,主要是在Spring2.xml就可配置实现好事务管理功能了
声明式的业务管理器(二)<基于Asoectj>
对于Dao层和Service层无需做改变,对spring3.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:c="http://www.springframework.org/schema/c" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" 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"> <context:property-placeholder location = "classpath:jdbc.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="accountDao" class="com.spring.demo3.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountService" class="com.spring.demo3.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- propagation:事务传播行为 isolation:事务隔离级别(DEFAULT表示按数据库的默认隔离级别) --> <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <aop:pointcut expression="execution(* com.spring.demo3.AccountService+.*(..))" id="pointcut1"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config> </beans>
声明式的业务管理器(三)<基于注解的方式>
在spring4.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:c="http://www.springframework.org/schema/c" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" 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"> <context:property-placeholder location = "classpath:jdbc.properties" /> <!-- 配置连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <bean id="accountDao" class="com.spring.demo4.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountService" class="com.spring.demo4.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
在需要进行事务处理的业务层进行注解@Transactional(),对该类下的所有public方法进行事务管理,同时也可在这注解后进行详细的注解