SPRING事务_2
参照资料:Spring资料 http://www.cnblogs.com/charles999/p/6699113.html
上篇:Spring事务_1
jdbc.properties 文件的配置
----------------------------
Spring支持两种方式事务管理
-编程式事务管理
·实际应用中很少使用
·通过TransactionTemplate手动管理事务
-使用XML配置声明式事务管理
·开发中推荐使用(代码侵入性最小)
·Spring的声明式事务是通过AOP实现的
---转账环境搭建(http://www.imooc.com/video/9330)--------------------------------------------------------
创建数据表account
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`money` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `account` VALUES ('1', 'aaa', '1000');
INSERT INTO `account` VALUES ('2', 'bbb', '1000');
INSERT INTO `account` VALUES ('3', 'ccc', '1000');
----interface define-------------------------------------------------------
AccountDao
AccountService
----interface implement-------------------------------------------------------
项目实例:银行转账
第一步:AccountDao.java AccountDaoImpl.java
public interface AccountDao { public void outMoney(String out,Double money); public void inMoney(String in,Double money); }
AccountDaoImpl.java
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{ public void outMoney(String out,Double money) { String sql="update account set money=money-? where name=?"; this.getJdbcTemplate().update(sql, money, out); } public void inMoney(String in,Double money) { String sql="update account set money=money+? where name=?"; this.getJdbcTemplate().update(sql, money, in); } }
第二步:AccountService.java AccountServiceImpl.java
public interface AccountService { public void tranfer(String out,String in,Double money); }
以下蓝色字为匿名内部类
transactionTemplate.execute(new TransactionCallbackWithoutResult() { //如果匿名内部类要拿到外层包裹它的方法的参数,那么要将final修饰成final
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
// TODO Auto-generated method stub
accountDao.outMoney(out, money);
int i=1/0;//发生异常
accountDao.inMoney(in, money);
}
});
public class AccountServiceImpl implements AccountService { //注入DAO类 private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //注入事务管理的模板 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } public void tranfer(final String out,final String in,final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { //如果匿名内部类要拿到外层包裹它的方法的参数,那么要将final修饰成final @Override protected void doInTransactionWithoutResult(TransactionStatus arg0) { // TODO Auto-generated method stub accountDao.outMoney(out, money); int i=1/0;//发生异常 accountDao.inMoney(in, money); } }); }
}
第三步:xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xmlns:aop="http://www.springframework.org/schema/aop" 6 xmlns:p="http://www.springframework.org/schema/p" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xsi:schemaLocation="http://www.springframework.org/schema/beans 9 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 10 http://www.springframework.org/schema/context 11 http://www.springframework.org/schema/context/spring-context-3.0.xsd 12 http://www.springframework.org/schema/aop 13 http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 14 <!-- 引入外部的属性文件 --> 15 <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> 16 <!-- 配置连接池 --> 17 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 18 <property name="driverClass" value="${jdbc.driverClass}"></property> 19 <property name="jdbcUrl" value="${jdbc.url}"></property> 20 <property name="user" value="${jdbc.username}"></property> 21 <property name="password" value="${jdbc.password}"></property> 22 </bean> 23 24 <!-- 配置业务层 --> 25 <bean id="accountService" class="com.imooc.demo1.AccountServiceImpl"> 26 <property name="accountDao" ref="accountDao"></property> 27 <!-- 注入事务管理的模板 --> 28 <property name="transactionTemplate" ref="transactionTemplate"></property> 29 </bean> 30 <!-- 配置DAO层 --> 31 <bean id="accountDao" class="com.imooc.demo1.AccountDaoImpl"> 32 <property name="dataSource" ref="dataSource"></property> 33 </bean> 34 35 <!-- 配置事务管理器 --> 36 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 37 <property name="dataSource" ref="dataSource"></property> 38 </bean> 39 40 <!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 --> 41 <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> 42 <property name="transactionManager" ref="transactionManager"></property> 43 </bean> 44 45 </beans>
27-29 注入事务管理的模板(通过set方法注入)
35-38 配置事务管理器
40-43 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类
测试类:第三步没有配置事务管理时(27-29 35-38 40-43)
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContestConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** *转账测试类 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class SpringDemo1 { //注解注入 @Resource(name="accountService") private AccountService accountService; @Test public void demo1(){ accountService.tranfer("aaa", "bbb", 200); } }
错误信息:
2017-06-22 11:15:00,866 [main] DEBUG [org.springframework.transaction.support.TransactionTemplate] - Initiating transaction rollback on application exception java.lang.ArithmeticException: / by zero at com.imooc.transaction.AccountServiceImpl$1.doInTransactionWithoutResult(AccountServiceImpl.java:30) at org.springframework.transaction.support.TransactionCallbackWithoutResult.doInTransaction(TransactionCallbackWithoutResult.java:34) at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) at com.imooc.transaction.AccountServiceImpl.transfer(AccountServiceImpl.java:26) at com.imooc.test.TestTransaction.testAspect(TestTransaction.java:22) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 2017-06-22 11:15:00,867 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Initiating transaction rollback 2017-06-22 11:15:00,868 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Rolling back JDBC transaction on Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@662ac478] 2017-06-22 11:15:00,936 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - Releasing JDBC Connection [com.mchange.v2.c3p0.impl.NewProxyConnection@662ac478] after transaction 2017-06-22 11:15:00,936 [main] DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - Returning JDBC Connection to DataSource 2017-06-22 11:15:00,937 [main] DEBUG [com.mchange.v2.resourcepool.BasicResourcePool] - trace com.mchange.v2.resourcepool.BasicResourcePool@7dcf94f8 [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@248c3047) 2017-06-22 11:15:00,938 [main] DEBUG [org.springframework.test.context.support.DirtiesContextTestExecutionListener] - After test method: context [DefaultTestContext@256216b3 testClass = TestTransaction, testInstance = com.imooc.test.TestTransaction@2a18f23c, testMethod = testAspect@TestTransaction, testException = java.lang.ArithmeticException: / by zero, mergedContextConfiguration = [MergedContextConfiguration@d7b1517 testClass = TestTransaction, locations = '{classpath:spring-transaction.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], class dirties context [false], class mode [null], method dirties context [false]. 2017-06-22 11:15:00,941 [main] DEBUG [org.springframework.test.context.support.DirtiesContextTestExecutionListener] - After test class: context [DefaultTestContext@256216b3 testClass = TestTransaction, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [MergedContextConfiguration@d7b1517 testClass = TestTransaction, locations = '{classpath:spring-transaction.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]], dirtiesContext [false]. 2017-06-22 11:15:00,942 [Thread-1] INFO [org.springframework.context.support.GenericApplicationContext] - Closing org.springframework.context.support.GenericApplicationContext@7a79be86: startup date [Thu Jun 22 11:14:59 CST 2017]; root of context hierarchy 2017-06-22 11:15:00,943 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Returning cached instance of singleton bean 'lifecycleProcessor' 2017-06-22 11:15:00,945 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@10a035a0: defining beans [org.springframework.context.support.PropertySourcesPlaceholderConfigurer#0,dataSource,accountService,accountDao,transactionManager,transactionTemplate,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor]; root of factory hierarchy 2017-06-22 11:15:00,945 [Thread-1] DEBUG [org.springframework.beans.factory.support.DefaultListableBeanFactory] - Retrieved dependent beans for bean 'accountService': [com.imooc.test.TestTransaction]
---6-1 Spring声明式编程:使用XML (原始方式)-----------------------------------------------------------------
Spring声明式编程:使用XML (原始方式)
1 引入包(以AOP形式开发,AOP传统开发需要以下两个包)
2 com.springsource.org.aopalliance-1.0.0.jar AOP联盟包
spring-aop-3.2.0.RELEASE.jar AOP包
配置:
1 <!-- 配置事务管理器 --> 配置dateSource属性
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2 <!-- 配置业务层的管理 --> //对目标进行增强
<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置目标对象 -->
<property name="target" ref="accountService"></property>
<!-- 注入事务管理器 -->
<property name="transactionManager" ref="transactionManager"></property>
<!-- 注入事务属性 -->
<property name="transactionAttributes">
<props>
<!--
prop的格式:
* PROPAGATION:事务的传播行为
* ISOLATION :事务的隔离级别
* readOnly : 只读
* -Exception 发生哪些异常回滚事务
* +Exception 发生哪些异常事务不回滚
-->
//类里的方法,tranfer方法。("*"代表所有方法,此处也可用,因为只有tranfer一个方法)
<prop key="tranfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
</props>
</property>
</bean>
第一步:
<?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:p="http://www.springframework.org/schema/p" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 引入外部的属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!-- 配置连接池 --> <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="accountService" class="com.imooc.demo2.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!-- 配置DAO层 --> <bean id="accountDao" class="com.imooc.demo2.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></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"> <props> <!-- prop的格式: * PROPAGATION 事务的传播行为 * ISOLATION 事务的隔离级别 * readOnly 只读(不可更新,插入和删除) * -Exception 发生哪些异常回滚事务 * +Exception 发生哪些异常事务不回滚(,+java.lang.ArithmeticException 就是1/0的异常,此时发生也正常处理) --> <prop key="tranfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> </props> </property> </bean> </beans>
service类:
public class AccountServiceImpl implements AccountService { //注入DAO类 private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void tranfer(final String out,final String in,final Double money) { accountDao.outMoney(out, money); int i=1/0;//发生异常 accountDao.inMoney(in, money); } }
第二步:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext2.xml") public class Demo2Test { //配置 注入代理类(代理类被增强了) accountServiceProxy //@Resource(name="accountService") @Resource(name="accountServiceProxy") private AccountService accountService; @Test public void demo2(){ accountService.tranfer("aaa", "bbb", 200d); } }
---6-2 声明式事务管理方式二:基于AspectJ的XML方式----------------------------------------------------------------------
Spring声明式编程:使用XML(AspectJ方式)
JAR包:
com.springsource.org.aspectj.weaver-1.6.8.RELEASE
spring-aspects-3.2.0.RELEASE
第一步:
引入约束:
<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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<?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:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> <!-- 引入外部的属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置c3p0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置业务层类 --> <bean id="accountService" class="com.zs.spring.demo3.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> </bean> <!-- 配置DAO类(简化,会自动配置JdbcTemplate) --> <bean id="accountDao" class="com.zs.spring.demo3.AccountDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <!-- ==================================3.使用XML配置声明式的事务管理,基于tx/aop=============================================== --> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- propagation :事务传播行为 isolation :事务的隔离级别 read-only :只读 rollback-for:发生哪些异常回滚 no-rollback-for :发生哪些异常不回滚 timeout :过期信息 --> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!-- 配置切面 --> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/> <!-- 配置切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config> </beans>
*代表方法返回值(*为任意返回值)
+代表子类
<aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
advisor:一个切入点一个通知时使用(aspect多个切入点和多个通知时使用)
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--
propagation :事务传播行为
isolation :事务的隔离级别
read-only :只读
rollback-for:发生哪些异常回滚
no-rollback-for :发生哪些异常不回滚
timeout :过期信息
-->
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
<!-- 配置切面 :在"pointcut1"切入点上用"txAdvice"增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>
第二步:测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class Demo3Test {
@Resource(name="accountService")
private AccountService accountService;
@Test
public void demo3(){
accountService.tranfer("aaa", "bbb", -200d);
}
}
----6-3 Spring声明式编程:使用XML(注解方式)-----------------------------------------------------------------------------------------------
Spring声明式编程:使用XML(注解方式)
第一步:
1. 配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入连接池 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
2. 开启注解事务
<!-- 开启注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
3.在业务层添加注解
/*
* @Transactional注解属性: *
* propagation:事务传播行为
isolation:事务隔离级别
readOnly:只读
rollBbackFor:发生哪些异常回滚
noRollbackFor:发生哪些异常不回滚
*/
@Transactional//不添加注解property时,采用默认值
//@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false) 可添加注解property
public class AccountServiceImpl implements AccountService {
<?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:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> <!-- 引入外部的属性文件 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 配置c3p0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- 配置业务层类 --> <bean id="accountService" class="com.zs.spring.demo4.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> </bean> <!-- 配置DAO类(简化,会自动配置JdbcTemplate) --> <bean id="accountDao" class="com.zs.spring.demo4.AccountDaoImpl"> <property name="dataSource" ref="dataSource" /> </bean> <!-- ==================================4.使用注解配置声明式事务============================================ --> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启注解事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
第二步:
/*
* @Transactional注解属性: *
* propagation:事务传播行为
isolation:事务隔离级别
readOnly:只读
rollBbackFor:发生哪些异常回滚
noRollbackFor:发生哪些异常不回滚
*/
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false)
public class AccountServiceImpl implements AccountService {
---7 事务总结----------------------------------------------------------------
Spring将事务管理分成了两类:
1. 编程式事务管理
手动编写代码进行事务管理.(很少使用)
2. 声明式事务管理:
* 基于TransactionProxyFactoryBean的方式.(很少使用)
* 需要为每个进行事务管理的类,配置一个TransactionProxyFactoryBean进行增强.
* 基于AspectJ的XML方式.(经常使用)
1)XML可很清晰的看到那些类配置了事务管理
2)一旦配置好之后,类上不需要添加任何东西
* 基于注解方式.(经常使用)
1) 配置简单,需要在业务层上添加一个@Transactional的注解.
=================================================
总结:
Spring的编程式事务管理(事务管理模板)(很少使用)
1.通过TrasactionTemplate手动管理事务
2.在AccountService中使用TransactionTemplate
3.TransactionTemplate依赖DataSourceTransactionManager
4.DataSourceTransactionManager依赖DataSource构造
(事务管理器有了连接池才能获得链接进行事务管理)
Spring的声明式事务管理(通过AOP实现的)
第一种:基于代理TransactionProxyFactoryBean;
注入:目标,事务管理器,事务属性:
1.PROPAGATION :事务的传播行为
2.ISOLATION :事务的隔离级别
3.readOnly :只读,(不可以进行修改,插入,删除)
4.-Exception :发生那些异常回滚事务
5.+Exception :发生那些异常事务不回滚
第二种:基于AspectJ的XML方式(aspectJ的话,就是分的更加的详细,切入点(类),切入面(方法))
1.配置事务的通知<tx>
2.配置切面,切点<aop>
第三种:基于注解的方式
1.开启事务<tx:annotation-driven transaction-Manager="" />
2.service类@Transactional(name=value)
======================================================
事务的特性:
事务是一个不可分割的工作单位,所有操作要么全部执行,要么都不执行
1.原子性: 指的是事物是一个不可分割的部分,要么都发生。要么都不发生
2.隔离性: 多个并发事物之间数据要相互隔离
3.一致性: 事物处理前后数据的完整性必须保持一致
4.持久性: 一个事物被提交之后。它对数据库中数据的改变是持久的
Spring事务管理接口
PlatformTransationManager:事务管理器
TransactionDefinition:事务定义信息(隔离、传播、超时、只读)
TransactionStatus:事务具体运行状态
PlatformTransactionManager
spring为了不同的持久化框架提供了不同的PlatformTransactionManagerPlatgorfTransactionManager的实现类
org.springframework.jdbc.datasource.DataSourceTransactionManager:使用Spring JDBC或iBatis进行持久化数据时
org.springframework.orm.hibernate3.HibernateTransactionManager:使用Hibernate3.0版本进行持久化数据时
org.springframework.orm.jpa.JpaTransactionManager:使用JPA进行持久化时
org.springframework.orm.jdo.JdoTransactionManager:当持久化机制是Jdo时
org.springframework.transaction.jta.JtaTransactionManager:使用一个JTA来管理事务,在一个事务跨越越多个资源时必须使用
七种事务传播路径
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--该方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果在没有事务的环境下被调用,容器抛出例外。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
事务隔离级别:
脏读:一个事务读取了另一个事务改写但未提交的数据,如果这些数据回滚则读到的数据是无效的。
不可重复读:一个事务读取了另一个事务提交的更新数据
幻读:一个事务读取了另一个事务插入的数据
Spring事务的隔离级别
TransactionDefinition接口的常量中ISOLATION_开头的表示事物的隔离级别
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别. 另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。 这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 除了防止脏读,不可重复读外,还避免了幻像读。
MySQL默认事务隔离级别:REPATABLE_READ(可能出现幻读)
Oracle默认:READ_COMMITTED(可能出现不可重复读和幻读)
Spring编程式事务管理
(1)在AccountService中使用TransactionTemplate
(2)TransactionTemplate依赖DataSourceTransactionManager
(3)DataSourceTransactionManager依赖DataSource构造