spring事务管理

建maven项目,建立数据库表和初始化数据:

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');

 

1,pom.xml,引入需要的jar包(spring-test和junit版本要兼容,不然会报多种错误)

<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>com.aluo</groupId>
    <artifactId>HelloSpring</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build />
    <dependencies>
        <!-- Spring Core -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <!-- Spring Context -->
        <!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.1.4.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.15</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
        <!-- <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> 
            <version>1.2.2</version> </dependency> -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <!-- 表示开发的时候引入,发布的时候不会加载此包 -->
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.0.2.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.1.4.Release</version>
        </dependency>
        <dependency>
            <groupId> org.aspectj</groupId>
            <artifactId> aspectjweaver</artifactId>
            <version> 1.8.7</version>
        </dependency>
    </dependencies>
</project>

2,新建接口AccountService

package com.aluo.spring.transaction;

public interface AccountService {
    /**
     * 
     * @param out
     *            :转出账号
     * @param in
     *            :转入账号
     * @param moneya
     *            :转账金额
     */

    public void transfer(String out, String in, Double money);

}

实现类AccountServiceImpl:

package com.aluo.spring.transaction;

public class AccountServiceImpl implements AccountService {
    // 注入DAO类
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String out, String in, Double money) {
        accountDao.outMoney(out, money);      
        accountDao.inMoney(in, money);

    }

}

3,新建接口AccountDao:

package com.aluo.spring.transaction;

public interface AccountDao {
    /**
     * @param out
     *            :转出账号
     * @param money
     *            :转出金额
     */
    public void outMoney(String out, Double money);

    /**
     * @param in
     *            :转入账号
     * @param money
     *            :转入金额
     */
    public void inMoney(String in, Double money);

}

实现类AccountDaoImpl:

package com.aluo.spring.transaction;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

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);
    }

}

4,beans.xml:

<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"
    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" />

    <!-- 配置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.aluo.spring.transaction.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>

    <!-- 配置DAO层,注入连接池就可以得到jdbc模板 -->
    <bean id="accountDao" class="com.aluo.spring.transaction.AccountDaoImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>

</beans>

5,jdbc.properties:

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/luo
jdbc.username=root
jdbc.password=123456

6,测试类SpringTransactionTest:

package com.aluo.spring.transaction;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans3.xml")
public class SpringTransactionTest {
    @Resource(name = "accountService")
    private AccountService accountService;

    @Test
    public void demo1() {
        System.out.println("begin");
        accountService.transfer("aaa", "bbb", 300d);
        System.out.println("over");
    }

}

运行后:

假如出错,在AccountServiceImpl添加出错代码:

public void transfer(String out, String in, Double money) {
        accountDao.outMoney(out, money);
        int a = 12/0;
        accountDao.inMoney(in, money);

    }

再运行,如图:

aaa账户余额减少,但是bbb账号余额并没有增加。

所以,这个时候需要事务管理。有两种:1,编程式管理;2,声明式管理。

二,声明式管理

第一种:基于AspectJ的XML方式

bean.xml加入以下:

<!-- 配置事务管理器 -->
    <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="transfer" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <!-- 配置切面 -->
    <aop:config>
        <!-- 配置切点 -->
        <aop:pointcut
            expression="execution(* com.aluo.spring.transaction.AccountService+.*(..))"
            id="pointcut1" />
        <!-- 配置切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1" />
    </aop:config>

pom.xml引入相关jar包。

此时,再运行SpringTransactionTest,结果如图:

和上图一样,说明事务起作用了。抛错之后,事务回滚了。

第二种:基于TransactionProxyFactoryBean的方式

配置事务管理器和业务层代理,在pom.xml加上:

<!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </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>

SpringTransactionTest改为如下:(引用代理类accountServiceProxy)

package com.aluo.spring.transaction;


import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:beans3.xml")
public class SpringTransactionTest {
     @Resource(name = "accountServiceProxy")
        private AccountService accountService;

        @Test
        public void demo1() {
            System.out.println("begin");
            accountService.transfer("aaa", "bbb", 300d);
            System.out.println("over");
        }
}

运行,出错,事务有回滚。

第三种,基于注解

开启注解事务:

<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"
    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" />

    <!-- 配置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.aluo.spring.transaction.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>

    <!-- 配置DAO层,注入连接池就可以得到jdbc模板 -->
    <bean id="accountDao" class="com.aluo.spring.transaction.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>

业务层加上注解@Transactional:

package com.aluo.spring.transaction;

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class AccountServiceImpl implements AccountService {

    // 注入DAO类
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String out, String in, Double money) {
        accountDao.outMoney(out, money);
        int a = 12 / 0;
        accountDao.inMoney(in, money);

    }
}

运行,出错,事务有回滚。

Spring 的事务管理,是 AOP 的应用,将事务作为切面织入到了 Service 层的业务方法中。

参考:https://www.cnblogs.com/zhaozihan/p/6219776.html

 

posted @ 2018-09-25 22:50  阿罗luo  阅读(102)  评论(0编辑  收藏  举报