一、基于 xml 配置声明式事务

1、xml配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd
  10. http://www.springframework.org/schema/tx
  11. https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
  12. <!--从classpath的根路径去加载db.properties文件-->
  13. <!--<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>-->
  14. <context:property-placeholder location="classpath:db.properties"/>
  15. <!--配置一个druid的连接池-->
  16. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
  17. init-method="init" destroy-method="close">
  18. <property name="driverClassName" value="${jdbc.driverClassName}"/>
  19. <property name="url" value="${jdbc.url}"/>
  20. <property name="username" value="${jdbc.username}"/>
  21. <property name="password" value="${jdbc.password}"/>
  22. <property name="initialSize" value="${jdbc.initialSize}"/>
  23. </bean>
  24. <!--配置dao-->
  25. <bean id = "accountDao" class="com.sunny.dao.impl.AccountDaoImpl">
  26. <property name="dataSource" ref="dataSource"/>
  27. </bean>
  28. <!--配置service-->
  29. <bean id="accountService" class="com.sunny.service.impl.AccountServiceImpl">
  30. <property name="dao" ref="accountDao"/>
  31. </bean>
  32. <!-- ====================================================================== -->
  33. <!-- 1: 配置JDBC事务管理器 WHAT:做什么增强(这里做事务增强)-->
  34. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  35. <property name="dataSource" ref="dataSource"/>
  36. </bean>
  37. <!-- 2: 配置事务管理器增强 WHEN-->
  38. <tx:advice id="txAdvice" transaction-manager="txManager">
  39. <tx:attributes>
  40. <tx:method name="trans"/>
  41. </tx:attributes>
  42. </tx:advice>
  43. <!-- 3: 配置切面 WHERE-->
  44. <aop:config>
  45. <aop:pointcut id="txPointcut" expression="execution(* com.sunny.service.*Service.*(..))"/>
  46. <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
  47. </aop:config>
  48. <!-- ====================================================================== -->
  49. </beans>

测试
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图1
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图2
成功!

2、事务方法 tx:method 属性配置

<tx:method/>元素的属性

  • 事务配置

    1. <tx:advice>
  • 通知标签(增强)

    • 属性id:自定义唯一表示
    • transaction-manager属性:事务管理类,配置事务管理类的id属性值
  • 事务属性配置

    1. <tx:attributes>
  • 子标签

    1. <tx:method>
    • 事务方法标签
      • 属性name:方法名
      • 属性read-only:是否只读事务,查询都是只读,其他是非只读
      • 属性propagation:事务的传播行为,默认配置REQUIRED或者SUPPORTS
      • 属性isolation:事务隔离级别,默认配置DEFAULT
      • 属性timeout:事务超时时间,配置-1
      • 属性no-rollback-for:遇到什么异常不回滚,配置异常类名,多个类逗号分开
      • 属性rollback-for:遇到什么异常回滚
        • 以上回滚属性不配置,遇到异常就回滚
  • aop切面配置

    1. <aop:config>
  • 标签

    1. <aop:advisor>
    • 子标签
      • 属性advice-ref:引用通知,配置tx:advice标签的属性值
      • 属性pointcut:切点配置

Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图3
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图4
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图5

3、CRUD通用事务配置

  1. <!--配置一个CRUD的通用事务的配置-->
  2. <tx:advice id="crudAdvice" transaction-manager="txManager">
  3. <tx:attributes>
  4. <!--service中的查询方法-->
  5. <tx:method name="get*" read-only="true" propagation="REQUIRED"/>
  6. <tx:method name="list*" read-only="true" propagation="REQUIRED"/>
  7. <tx:method name="query*" read-only="true" propagation="REQUIRED"/>
  8. <!--service中其他方法(非查询)-->
  9. <tx:method name="*" propagation="REQUIRED"/>
  10. </tx:attributes>
  11. </tx:advice>
  12. 1234567891011

二、基于 注解 配置声明式事务

基于注解配置事务:在Service中,使用 @Transactional注解

@Transactional 注解的属性
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图6

  • @Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类中的所有 public方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义(比如在查询方法上单独设置@Transactional(readOnly=true)。
    Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图7
  • @Transactional 注解可以作用于接口、 接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

Java代码

  1. @Repository
  2. public class AccountDaoImpl implements AccountDao {
  3. private JdbcTemplate jdbcTemplate;
  4. @Autowired
  5. public void setDataSource(DataSource ds){
  6. this.jdbcTemplate = new JdbcTemplate(ds);
  7. }
  8. public void transOut(Long outId, int money) {
  9. String sql = "UPDATE account SET balance = balance - ? WHERE id = ?";
  10. jdbcTemplate.update(sql, money, outId);
  11. }
  12. public void transIn(Long inId, int money) {
  13. String sql = "UPDATE account SET balance = balance + ? WHERE id = ?";
  14. jdbcTemplate.update(sql, money, inId);
  15. }
  16. }
  17. @Service
  18. @Transactional
  19. public class AccountServiceImpl implements AccountService {
  20. @Autowired
  21. private AccountDao dao;
  22. public void trans(Long outId, Long inId, int money) {
  23. dao.transOut(outId, money);
  24. int a = 1 / 0; // 抛出异常
  25. dao.transIn(inId, money);
  26. }
  27. @Transactional(readOnly = true)
  28. public void queryAll(){
  29. //TODO
  30. }
  31. }

xml配置: 必须要配置 TX注解解析器!

  1. <!--配置DI注解解析器-->
  2. <context:annotation-config/>
  3. <!--配置IoC注解解析器-->
  4. <context:component-scan base-package="com.sunny"/>
  5. <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  6. <property name="dataSource" ref="dataSource"/>
  7. </bean>
  8. <!--配置TX注解解析器-->
  9. <tx:annotation-driven transaction-manager="txManager"/>
  10. <context:property-placeholder location="classpath:db.properties"/>
  11. <!--配置一个druid的连接池-->
  12. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
  13. init-method="init" destroy-method="close">
  14. <property name="driverClassName" value="${jdbc.driverClassName}"/>
  15. <property name="url" value="${jdbc.url}"/>
  16. <property name="username" value="${jdbc.username}"/>
  17. <property name="password" value="${jdbc.password}"/>
  18. <property name="initialSize" value="${jdbc.initialSize}"/>
  19. </bean>

对比
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图8

三、基于 纯注解(JavaConfig) 配置声明式事务

跳转到目录

  • @Configuration标识当前类是Spring的一个配置类
  • @ComponentScan替代xml中的<context:component-scan/>
  • @Import引入其他配置类,被引入的配置类可以不加@Configuration注解
  • @PropertySource:引入外部properties文件,注意加classpath:
  • @Value对成员变量赋值
  • @Bean将一个方法的返回值对象加入到Spring的容器当中管理
  • @Qualifier可以使用在方法上,表明对应的形参引入/注入的对象类型

直接删除xml的配置文件,取而代之的是一个Config类
@Transactional注解,取代tx标签
@EnableTransactionManagement注解,开启事务注解

  • @Configuration 标识当前类为一个配置类, 当前项目的配置类,好比是applicationContext.xml
  • @Import(Xxx.class) 在主配置类中包含Xxx的配置类
  • @PropertySource("classpath:db.properties") 读取配置文件
  • @Bean("Xxx") 相当于 <bean id="Xxx" class="">, Bean()中不写参数,默认就是该方法创建的对象; 该对象就被Spring容器所管理了
    Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图9
  1. 该类是一个配置类,它的作用和bean.xml是一样的
  2. spring中的新注解
  3. Configuration
  4. 作用:指定当前类是一个配置类
  5. 细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。
  6. ComponentScan
  7. 作用:用于通过注解指定spring在创建容器时要扫描的包
  8. 属性:
  9. value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
  10. 我们使用此注解就等同于在xml中配置了:
  11. <context:component-scan base-package="com.sunny"></context:component-scan>
  12. Bean
  13. 作用:用于把当前方法的返回值作为bean对象存入springioc容器中
  14. 属性:
  15. name:用于指定beanid。当不写时,默认值是当前方法的名称
  16. 细节:
  17. 当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
  18. 查找的方式和Autowired注解的作用是一样的
  19. Import
  20. 作用:用于导入其他的配置类
  21. 属性:
  22. value:用于指定其他配置类的字节码。
  23. 当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类
  24. PropertySource
  25. 作用:用于指定properties文件的位置
  26. 属性:
  27. value:指定文件的名称和路径。
  28. 关键字:classpath,表示类路径下

Java代码

  1. //@Repository("accountDaoImpl")
  2. @Repository // 默认是 accountDaoImpl,相当于类名首字母小写,相当于<bean id="accountDaoImpl" class=""/>
  3. public class AccountDaoImpl implements AccountDao {
  4. private JdbcTemplate jdbcTemplate;
  5. @Autowired
  6. public void setDataSource(DataSource ds){
  7. this.jdbcTemplate = new JdbcTemplate(ds);
  8. }
  9. public void transOut(Long outId, int money) {
  10. String sql = "UPDATE account SET balance = balance - ? WHERE id = ?";
  11. jdbcTemplate.update(sql, money, outId);
  12. }
  13. public void transIn(Long inId, int money) {
  14. String sql = "UPDATE account SET balance = balance + ? WHERE id = ?";
  15. jdbcTemplate.update(sql, money, inId);
  16. }
  17. }
  18. @Service
  19. @Transactional
  20. public class AccountServiceImpl implements AccountService {
  21. @Autowired
  22. private AccountDao dao;
  23. public void trans(Long outId, Long inId, int money) {
  24. dao.transOut(outId, money);
  25. //int a = 1 / 0; // 抛出异常
  26. dao.transIn(inId, money);
  27. }
  28. }

Java配置类

  1. //当前项目的配置类,好比是applicationContext.xml
  2. @Configuration //标识当前类为一个配置类
  3. @Import(DataSourceConfig.class) //包含其他的配置类
  4. @ComponentScan("com.sunny") //IoC注解解析器
  5. @EnableTransactionManagement//事务注解解析器
  6. public class JavaConfig {
  7. //创建事务管理的Bean
  8. @Bean
  9. public DataSourceTransactionManager txManager(DataSource ds) {
  10. return new DataSourceTransactionManager(ds);
  11. }
  12. }
  13. // 当前项目的连接池的配置类
  14. @Configuration
  15. @PropertySource("classpath:db.properties")
  16. public class DataSourceConfig {
  17. // 将properties的内容注入到这些变量中
  18. @Value("${jdbc.driverClassName}")
  19. private String driverClassName;
  20. @Value("${jdbc.url}")
  21. private String url;
  22. @Value("${jdbc.username}")
  23. private String username;
  24. @Value("${jdbc.password}")
  25. private String password;
  26. @Value("${jdbc.initialSize}")
  27. private int initialSize;
  28. //创建连接池的Bean
  29. @Bean("dataSource")
  30. public DataSource dataSource() {
  31. DruidDataSource ds = new DruidDataSource();
  32. ds.setDriverClassName(driverClassName);
  33. ds.setUrl(url);
  34. ds.setUsername(username);
  35. ds.setPassword(password);
  36. ds.setInitialSize(initialSize);
  37. return ds;
  38. }
  39. }

测试类

  1. @RunWith(SpringJUnit4ClassRunner.class)
  2. @ContextConfiguration(classes=JavaConfig.class)
  3. public class SpringTxTest {
  4. @Autowired
  5. private AccountService service;
  6. @Test
  7. public void test1(){
  8. service.trans(10086L, 10010L, 1000);
  9. }
  10. }

成功!

使用纯注解和半注解和XML的对比图:
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图10
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图11
Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图12

四、选择开发方式

Spring-XML配置事务、注解 XML、纯注解的配置方式 - 图13