zoukankan      html  css  js  c++  java
  • Spring基于XML声明式事务控制

    1.基于XML的声明式事务控制

    1.1 什么是声明式事务控制

     Spring的声明式事务顾名思义就是采用声明的方式来处理事务。这里所说的声明,就是指在配置文件中声明,用在Spring配置文件中声明式的处理事务来代替代码式的处理事务

    1.2 声明式事务处理的作用

    (1)事务管理不侵入开发的组件(即,业务代码和事务控制通过配置的方式松耦合,代码运行时候,业务逻辑又能完成对应的事务控制,这是AOP思想,事务控制是增强方法,业务代码是被增强)。具体来说,业务逻辑对象就不会意识到正在事务管理中,事实上也应该如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策划的话,也只需要在定义文件中重新配置即可。

    (2)不需要事务管理的时候,只要在设定文件上修改一下,即可移去事务管理服务,无需改变代码的重新编译,这样维护起来极其方便。只需要在配置文件中,删掉那个事务控制就可以了。

    转账案例:

     AccountController.java

    package com.company.controller;
    
    import com.company.service.AccountService;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class AccountController {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            AccountService accountService = applicationContext.getBean(AccountService.class);
            accountService.transfer("tom", "lisi", 200);
        }
    }
    

      AccountDao.java

    package com.company.dao;
    
    public interface AccountDao {
        void out(String outMan, double money);
        void in(String inMan, double money);
    }
    

      AccountDaoImpl.java

    package com.company.dao.impl;
    
    import com.company.dao.AccountDao;
    
    import org.springframework.jdbc.core.JdbcTemplate;
    
    public class AccountDaoImpl implements AccountDao {
        private JdbcTemplate jdbcTemplate;
    
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        public void out(String outMan, double money) {
            jdbcTemplate.update("update account set money=money-? where name=? ", money, outMan);
        }
    
        public void in(String inMan, double money) {
            jdbcTemplate.update("update account set money=money+? where name=?",money, inMan);
        }
    }
    

      Account.java

    package com.company.domain;
    
    public class Account {
        private String name;
        private double money;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    }
    

      AccountService.java

    package com.company.service;
    
    public interface AccountService {
        void transfer(String outMan, String inMan, double money);
    }
    

      AccountServiceImpl.java

    package com.company.service.impl;
    
    import com.company.dao.AccountDao;
    import com.company.service.AccountService;
    
    public class AccountServiceImpl implements AccountService {
        private AccountDao accountDao;
    
        public void setAccountDao(AccountDao accountDao) {
            this.accountDao = accountDao;
        }
    
        public void transfer(String outMan, String inMan, double money) {
            accountDao.out(outMan, money);
            accountDao.in(inMan, money);
        }
    }
    

      applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
            <property name="user" value="root"/>
            <property name="password" value="123456"/>
        </bean>
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="accountDao" class="com.company.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"/>
        </bean>
    
        <bean id="accountService" class="com.company.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"/>
        </bean>
    </beans>

    上面的案例存在一个问题

     如果出现上面的问题,out已经执行了,但是in没有执行,导致账户不对。

    因此需要事务来保证原子性

    案例解决方案:使用基于xml声明式事务控制

    1.3 声明式事务控制的实现

    声明式事务控制明确事项:

    谁是切点?被增强的方法,这里的是业务方法,就是transfer

    谁是通知?就是事务控制,事务的增强

    配置切面?切点和通知进行配置

    主要是在核心配置文件applicationContext.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:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
           http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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
    ">
    
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>
            <property name="user" value="root"/>
            <property name="password" value="123456"/>
        </bean>
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <bean id="accountDao" class="com.company.dao.impl.AccountDaoImpl">
            <property name="jdbcTemplate" ref="jdbcTemplate"/>
        </bean>
    
        <!--目标对象,内部的方法就是切点-->
        <bean id="accountService" class="com.company.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"/>
        </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>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>
    
        <!-- 配置AOP事务织入-->
        <aop:config>
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.company.service.impl.*.*(..))"></aop:advisor>
        </aop:config>
    
    </beans>

     下面重点介绍下设置事务的属性信息,也就是事务控制的三大对象中TransactionDefinition

     如果要指定方法,可以这样配置:

        <!--通知,事务的增强-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
                <tx:method name="*"/>
            </tx:attributes>
        </tx:advice>

     pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>spring_tx</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.6</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.2.9.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.4</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.44</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
  • 相关阅读:
    聊聊WS-Federation
    用双十一的故事串起碎片的网络协议(上)
    责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析
    最小化局部边际的合并聚类算法(中篇)
    最小化局部边际的合并聚类算法(上篇)
    UVaLive 7371 Triangle (水题,判矩形)
    UVaLive 7372 Excellence (水题,贪心)
    POJ 3312 Mahershalalhashbaz, Nebuchadnezzar, and Billy Bob Benjamin Go to the Regionals (水题,贪心)
    UVa 1252 Twenty Questions (状压DP+记忆化搜索)
    UVa 10817 Headmaster's Headache (状压DP+记忆化搜索)
  • 原文地址:https://www.cnblogs.com/GumpYan/p/14202295.html
Copyright © 2011-2022 走看看