2017-11-12 16:31:59

Spring的事务管理分为两种:

  • 编程式的事务管理:手动编写代码
  • 声明式的事务管理:只需要配置就可以

一、最初的环境搭建

public interface AccountDAO {public void out(String to,Double money);public void in(String from, Double money);
}public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {@Overridepublic void out(String from, Double money) {String sql =  "update account  set money = money - ? where name = ?";this.getJdbcTemplate().update(sql, money,from);}@Overridepublic void in(String to, Double money) {String sql = "update account  set money = money + ? where name = ?";this.getJdbcTemplate().update(sql, money , to);}
}public interface AccountService {public void transfer(String from, String to, Double money);
}public class AccountServiceImpl implements AccountService {@Resource(name = "accountDao")private AccountDAO accountDAO;@Overridepublic void transfer(String from, String to, Double money) {accountDAO.out(from,money);accountDAO.in(to,money);}
}// 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config4.xml")
public class TestDemo {@Resource(name = "accountservice")private AccountService accountService;@Testpublic void demo(){accountService.transfer("aaa","bbb",100d);}
}

二、手动式的事务管理

可以发现,在没有引入事务管理的时候,如果在转账的out和in之间出现了异常,那么就会导致转账的结果出错。所以我们需要引入事务管理技术。

Spring提供了事务管理的模板(工具类),可以方便我们对事务进行管理。

具体步骤:

  • 第一步:注册事务管理器
  • 第二步:注册事务模板类
  • 第三步:在业务层注入模板类
  • 第四步:在业务层代码上使用模板
public class AccountServiceImpl implements AccountService {@Resource(name = "accountDao")private AccountDAO accountDAO;@Resource(name = "transactionTemplate")private TransactionTemplate transactionTemplate;@Overridepublic void transfer(String from, String to, Double money) {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {accountDAO.out(from,money);accountDAO.in(to,money);}});}
}

XML的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--配置连接池--><!--<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">--><!--<property name="driverClassName" value="com.mysql.jdbc.Driver"/>--><!--<property name="url" value="jdbc:mysql://localhost:3306/testdb"/>--><!--<property name="username" value="host"/>--><!--<property name="password" value="hy1102"/>--><!--</bean>--><!-- 配置DBCP连接池 --><!--<bean id="datasource" class=" org.apache.commons.dbcp.BasicDataSource ">--><!--<property name="driverClassName" value="com.mysql.jdbc.Driver"/>--><!--<property name="url" value="jdbc:mysql://localhost:3306/testdb"/>--><!--<property name="username" value="host"/>--><!--<property name="password" value="hy1102"/>--><!--</bean>--><!-- 引入该属性文件 --><!--<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">--><!--<property name="location" value="classpath:jdbc.properties"/>--><!--</bean>--><!-- 使用 context 标签引入属性文件 --><context:property-placeholder location="classpath:jdbc.properties"/><!--  配置 c3p0 连接池 --><bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean><!-- 定义模板 --><bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="datasource"/></bean><bean id="userdao" class="spring3.UserDao"><property name="jdbcTemplate" ref="jdbctemplate"/></bean><!--业务层--><bean id="accountservice" class="spring4.AccountServiceImpl"/><!--持久层--><bean id="accountDao" class="spring4.AccountDAOImpl"><!--事实上可以直接注入连接池来创建模板--><property name="dataSource" ref="datasource"/></bean><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 需要注入连接池,通过连接池获得连接 --><property name="dataSource" ref="datasource"/></bean><!-- 事务管理的模板 --><bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"><property name="transactionManager" ref="transactionManager"/></bean></beans>

三、声明式的事务管理

手动编码方式类似于对transfer方法进行增强,所以考虑代理Service对象。

  • 基于原始的TransactionProxyFactoryBean
// 业务代码
public class AccountServiceImpl implements AccountService {@Resource(name = "accountDao")private AccountDAO accountDAO;@Overridepublic void transfer(String from, String to, Double money) {accountDAO.out(from,money);accountDAO.in(to,money);}
}// 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config4.xml")
public class TestDemo {@Resource(name = "accountServiceProxy")private AccountService accountService;@Testpublic void demo(){accountService.transfer("aaa","bbb",100d);}
}

XML的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--配置连接池--><!--<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">--><!--<property name="driverClassName" value="com.mysql.jdbc.Driver"/>--><!--<property name="url" value="jdbc:mysql://localhost:3306/testdb"/>--><!--<property name="username" value="host"/>--><!--<property name="password" value="hy1102"/>--><!--</bean>--><!-- 配置DBCP连接池 --><!--<bean id="datasource" class=" org.apache.commons.dbcp.BasicDataSource ">--><!--<property name="driverClassName" value="com.mysql.jdbc.Driver"/>--><!--<property name="url" value="jdbc:mysql://localhost:3306/testdb"/>--><!--<property name="username" value="host"/>--><!--<property name="password" value="hy1102"/>--><!--</bean>--><!-- 引入该属性文件 --><!--<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">--><!--<property name="location" value="classpath:jdbc.properties"/>--><!--</bean>--><!-- 使用 context 标签引入属性文件 --><context:property-placeholder location="classpath:jdbc.properties"/><!--  配置 c3p0 连接池 --><bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean><!-- 定义模板 --><bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="datasource"/></bean><bean id="userdao" class="spring3.UserDao"><property name="jdbcTemplate" ref="jdbctemplate"/></bean><!--业务层--><bean id="accountservice" class="spring4.AccountServiceImpl"/><!--持久层--><bean id="accountDao" class="spring4.AccountDAOImpl"><!--事实上可以直接注入连接池来创建模板--><property name="dataSource" ref="datasource"/></bean><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 需要注入连接池,通过连接池获得连接 --><property name="dataSource" ref="datasource"/></bean><!-- 事务管理的模板 --><bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"><property name="transactionManager" ref="transactionManager"/></bean><!--  配置生成代理对象 --><bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"><!--  目标对象 --><property name="target" ref="accountservice"/><!--  注入事务管理器 --><property name="transactionManager" ref="transactionManager"/><!--  事务的属性设置 --><property name="transactionAttributes"><props><prop key="transfer">PROPAGATION_REQUIRED</prop></props></property></bean></beans>

prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
* 顺序:传播行为、隔离级别、事务是否只读、发生哪些异常可以回滚事务(所有的异常都回滚)、发生了哪些异常不回

<prop key="transfer">PROPAGATION_REQUIRED,readonly</prop>
<prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>

  • 基于切面自动代理

上面的方法每次都要手动生成代理,显然是不太合适的,所以可以使用基于切面的自动代理。

public interface AccountDAO {public void out(String to,Double money);public void in(String from, Double money);
}public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {@Overridepublic void out(String from, Double money) {String sql =  "update account  set money = money - ? where name = ?";this.getJdbcTemplate().update(sql, money,from);}@Overridepublic void in(String to, Double money) {String sql = "update account  set money = money + ? where name = ?";this.getJdbcTemplate().update(sql, money , to);}
}public interface AccountService {public void transfer(String from, String to, Double money);
}public class AccountServiceImpl implements AccountService {@Resource(name = "accountDao")private AccountDAO accountDAO;@Overridepublic void transfer(String from, String to, Double money) {accountDAO.out(from,money);accountDAO.in(to,money);}
}//测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:config5.xml")
public class TestDemo {@Resource(name = "accountservice")private AccountService accountService;@Testpublic void demo(){accountService.transfer("aaa","bbb",100d);}
}

XML的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://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"><!-- 使用 context 标签引入属性文件 --><context:property-placeholder location="classpath:jdbc.properties"/><!--  配置 c3p0 连接池 --><bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean><!-- 定义模板 --><bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="datasource"/></bean><bean id="userdao" class="spring3.UserDao"><property name="jdbcTemplate" ref="jdbctemplate"/></bean><!--业务层--><bean id="accountservice" class="spring4.AccountServiceImpl"/><!--持久层--><bean id="accountDao" class="spring4.AccountDAOImpl"><!--事实上可以直接注入连接池来创建模板--><property name="dataSource" ref="datasource"/></bean><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 需要注入连接池,通过连接池获得连接 --><property name="dataSource" ref="datasource"/></bean><!-- 定义一个增强 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 增强(事务)的属性的配置 --><tx:attributes><!--isolation:DEFAULT :事务的隔离级别.propagation :事务的传播行为.read-only :false.不是只读timeout :-1no-rollback-for :发生哪些异常不回滚rollback-for :发生哪些异常回滚事务--><tx:method name="transfer" isolation="DEFAULT"/></tx:attributes></tx:advice><!-- aop配置定义切面和切点的信息 --><aop:config><!-- 定义切点:哪些类的哪些方法应用增强 --><aop:pointcut expression=" execution(* spring4.AccountService+.*(..)) " id="mypointcut"/><!-- 定义切面: --><aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/></aop:config></beans>

  • 基于注解的事务配置

具体步骤:

  • 第一步:事务管理器
  • 第二步:注解事务
  • 第三步:在Service上使用注解

* 注解中有属性值:

* isolation

* propagation

* readOnly

...

  • 第四步:测试
@Transactional
public class AccountServiceImpl implements AccountService {@Resource(name = "accountDao")private AccountDAO accountDAO;@Overridepublic void transfer(String from, String to, Double money) {accountDAO.out(from,money);// int i = 1/0;accountDAO.in(to,money);}
}

XML配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns="http://www.springframework.org/schema/beans"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://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"><!-- 使用 context 标签引入属性文件 --><context:property-placeholder location="classpath:jdbc.properties"/><!--  配置 c3p0 连接池 --><bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.driver}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/></bean><!-- 定义模板 --><bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="datasource"/></bean><bean id="userdao" class="spring3.UserDao"><property name="jdbcTemplate" ref="jdbctemplate"/></bean><!--业务层--><bean id="accountservice" class="spring4.AccountServiceImpl"/><!--持久层--><bean id="accountDao" class="spring4.AccountDAOImpl"><!--事实上可以直接注入连接池来创建模板--><property name="dataSource" ref="datasource"/></bean><!--配置事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 需要注入连接池,通过连接池获得连接 --><property name="dataSource" ref="datasource"/></bean><tx:annotation-driven transaction-manager="transactionManager"/></beans>

比较来看,最后的基于注解的方式是最容易,也是代码量最少的。

转载于:https://www.cnblogs.com/TIMHY/p/7822391.html

Java Spring-事务管理相关推荐

  1. JAVA Spring 事务管理事务不回滚问题

    Spring事务管理事务不回滚 dao层: @Repository public class UserDaoImpl implements UserDao { @Autowired private J ...

  2. java中事务实例,Java Spring 事务管理器入门例子教程(TranscationManager)

    注:阅读本文之前请务必有上文的基础 本文我们使用的事务管理器(TranscationManager)的作用是保证一组数据库操作的原子性.保证在操作时,如果出现异常,事务管理器会将状态恢复到进行本组操作 ...

  3. Java Spring 事务管理

    包spring-tx-xxx.jar xml配置 <!-- 配置通知,tx:attributes配置传播行为和隔离级别--> <tx:advice id="txAdvice ...

  4. Spring事务管理 与 SpringAOP

    1,Spring事务的核心接口 Spring事务管理的实现有许多细节,如果对整个接口框架有个大体了解会非常有利于我们理解事务,下面通过讲解Spring的事务接口来了解Spring实现事务的具体策略.  ...

  5. Spring 事务管理高级应用难点剖析

    Spring 事务管理高级应用难点剖析: 第 1 部分 http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts1/index.html htt ...

  6. Spring 事务管理高级应用难点剖析--转

    第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...

  7. Spring事务管理(详解+实例)

    写这篇博客之前我首先读了<Spring in action>,之后在网上看了一些关于Spring事务管理的文章,感觉都没有讲全,这里就将书上的和网上关于事务的知识总结一下,参考的文章如下: ...

  8. springaop事务逻辑原理_架构师:一篇文章掌握——Spring 事务管理

    对大多数Java开发者来说,Spring事务管理是Spring应用中最常用的功能,使用也比较简单.本文主要逐步介绍Spring事务管理的相关知识点及原理,作为Spring事务管理的学习总结. 一.关键 ...

  9. Spring事务管理详解_基本原理_事务管理方式

    Spring事务管理详解_基本原理_事务管理方式 1. 事务的基本原理 Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象 ...

  10. Spring jdbc Template和Spring 事务管理

    使用jdbcTemplate完成增删改查操作(重点) package com.it.jdbctemplate;import java.util.List;import org.junit.Test; ...

最新文章

  1. 地图收敛心得170405
  2. C++关键字static
  3. mybatis中使用XML配置文件方式实现CRUD模板流程
  4. SpringBoot 文件上传、下载、设置大小
  5. 《SuperMap GIS二次开发MVC实战训练---江海区慢性病防治院系统》项目研发阶段性总结
  6. css 相对定位与绝对定位
  7. vueCli3中使用代理,点击页面的刷新按钮时报错
  8. MySQL深度剖析之事务隔离级别和锁机制(2021)
  9. Android APK反编译详解
  10. [JDBC] MySQL中数据的增查删改(二)
  11. PAT(乙级)1016
  12. vue - 开发环境构建
  13. java编译系统找不到指定路径_为什么我在E盘安装了java,命令指示符输入后却提示系统找不到指定路径?...
  14. 各类编程开发软件及资源全版本下载地址合集
  15. python爬虫获取城市天气信息
  16. day18-正则表达式
  17. python显示gif图片报错_4种方法(plglet、tkinter、guizero、pygame)的GUI中显示gif
  18. mongodb ubuntu下安装以及开启远程访问
  19. matplotlib-04 xlabel设置x轴的标签
  20. 访问者模式(JAVA)

热门文章

  1. java 数字千分位_java实现数字千分位的显示
  2. php和数据库的永久链接,php – WordPress永久链接,包括名称和ID,但仅考虑ID
  3. pandas mysql insert_python – Pandas将数据插入MySQL
  4. 医疗知识图谱NLP项目,实体规模4.4万,实体关系规模30万
  5. python again语句_【python笔记 二 】python语句
  6. android hook 模拟点击_手把手讲解 Android Hook-实现无清单启动Activity
  7. python3生成随机数_python3实现随机数
  8. 照片浏览器_照片审核不通过!这可能是史上最亏的中级失败理由!
  9. 程序员如何掌握计算机英语
  10. python语法中的网络编程_(六)python语法之网络编程