[Spring] programmatic and declarative transaction Affairs

I. Overview

Spring's transaction management into two categories:

  1. Programmatic transaction management (manually write the code to complete the transaction management)
  2. Declarative transaction management (no need to manually write the code, you need to configure)

Second, prepare for work

1. Create a table

 CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `money` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB

2. Create a project and dependent on the introduction of Maven

  Create a project and introduce the following Maven dependent on:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>   
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
    
    <!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
    
    
    <!-- Spring 整合测试的包 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>
    

Directory structure as follows:

3. Write the entity class

public class Account {
    private Integer id;
    private String name;
    private Integer money;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getMoney() {
        return money;
    }
    public void setMoney(Integer money) {
        this.money = money;
    }
    @Override
    public String toString() {
        return "Account [id=" + id + ", name=" + name + ", money=" + money + "]";
    }
}

Dao layer 4. Preparation of

Write Interface


/**
 * 银行账户的相关操作 此处用了@see注释,在实现类可以继承接口中方法的注释内容
 * 
 * @author hao
 * @see AccountDaoImpl
 * 
 */
public interface IAccountDao {

    /**
     * 添加账户
     * 
     * @param account 要添加的账户
     */
    public void add(Account account);

    /**
     * 转出的方法
     * 
     * @param from  :转出的账户,打出钱
     * @param money :要转账金额
     */
    public void out(Account from, Integer money);
    
    /**
     * 转出的方法
     * 
     * @param to    转入的账户,收到钱
     * @param money 要转账金额
     */
    public void in(Account to, Integer money);
    
    /**
     * 通过名字查询账户
     * @param name 账户名
     * @return
     */
    public Account selectOneByName(String name);
    
}

Implementation class

public class AccountDaoImpl implements IAccountDao{

    
    @Autowired
    @Qualifier("jdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    
    @Override
    public void add(Account account) {
        String sql = "insert into account values(null,?,?)";
        jdbcTemplate.update(sql,account.getName(),account.getMoney());
    }
    
    
    @Override
    public Account selectOneByName(String name) {
        String sql = "select * from account where name = ?";
        Account account = null;
        try {//这里需要捕获结果集为空时的异常
            account = jdbcTemplate.queryForObject(sql, new RowMapper<Account>() {

                @Override
                public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Account account = new Account();
                    account.setId(rs.getInt("id"));
                    account.setName(rs.getString("name"));
                    account.setMoney(rs.getInt("money"));
                    return account;
                }
                
            }, name);
        } catch (EmptyResultDataAccessException e) {
            e.printStackTrace();
            return null;
        }
        
        return account;
    }
    
    
    public void out(Account from, Integer money) {
        String sql = "update account set money = money-? where name =? ";
        jdbcTemplate.update(sql, money,from.getName());
    }

    public void in(Account to, Integer money) {
        String sql ="update account set money = money+? where name =?";
        jdbcTemplate.update(sql,money,to.getName());
    }
    
}

The business layer

interface

/**
 * 
 * @author hao
 * @see AccountServiceImpl
 */
public interface IAccountService {

    /**
     * 向数据库中添加用户
     * 
     * @param account 要添加的用户对象
     */
    public void addAccount(Account account);

    /**
     * 转账的方法
     * 
     * @param from  转出的账户
     * @param to    转入的账户
     * @param money 转账金额
     */
    public void transfer(Account from, Account to, Integer money);
    
    /**
     * 
     * @param name 需要查询的账户名
     * @return
     */
    public Account findAccountByName(String name);
}

Implementation class

/**
 * 没有添加事务
 * @author hao
 *
 */
public class AccountServiceImpl implements IAccountService {
    // 注入 accountDao 利用setter方法注入属性
    private IAccountDao accountDao;

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

    @Override
    public void addAccount(Account account) {
        accountDao.add(account);
    }
    
    @Override
    public Account findAccountByName(String name) {
        Account account = accountDao.selectOneByName(name);
        return account;
    }


    @Override
    public void transfer(Account from, Account to, Integer money) {
        accountDao.out(from, money);// 转出钱
        int i= 1/0 //出现异常时
        accountDao.in(to, money);// 收入钱
    }
}

6. XML configuration

<?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"
       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">
    
    <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"></property>
    </bean>
    
    <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式  -->  
    <bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean>
    
    
    <!-- 此处声明业务层类,用setter的方式注入了accountDao -->
    <bean id="accountService" class="com.hao.tx.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
    </bean>

</beans>

7. Test

@Test
    public void test02() {
        System.out.println("转账之前....");
        Account a = accountService.findAccountByName("a");
        if(a != null) {
            System.out.println(a);
        }
        
        Account b = accountService.findAccountByName("b");
        if(b!=null) {
            System.out.println(b);
        }
        
        try {//这里捕获转账时出现的异常
            System.out.println("开始转账.....");
            accountService.transfer(a, b, 100);
        }catch(ArithmeticException e) {
            e.printStackTrace();
        }finally {
            System.out.println("转账之后....");
            Account a_trans = accountService.findAccountByName("a");
            if(a != null) {
                System.out.println(a_trans);
            }
            Account b_trans = accountService.findAccountByName("b");
            if(b!=null) {
                System.out.println(b_trans);
            }
        }
    }

Result Analysis:
  run the test class after test02 will find, if there is no transaction, even if an exception occurs, will change the data in the database
  as follows:
  
  

  
  

Third, programmatic transaction

  The above program does not add the transaction , following a complete transaction management manual coding method requires the transaction manager to actually manage the transaction object, Spring provides templates (tools) transaction management
  on the platform transaction manager, you can access [Spring] affairs

1. Using the template on the business layer transaction codes

  Create a business class and use programmatic transaction to transaction management, Spring provides templates for Management

/**
 * 编程式事务
 * 
 * @author hao
 *
 */
public class AccountServiceImpl_Program implements IAccountService {

    // 注入 accountDao 利用setter方法注入属性
    private IAccountDao accountDao;

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

    // 注入 transactionTemplate 利用setter方法注入属性
    private TransactionTemplate transactionTemplate;

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    @Override
    public void addAccount(Account account) {
        accountDao.add(account);
    }
    @Override
    public Account findAccountByName(String name) {
        Account account = accountDao.selectOneByName(name);
        return account;
    }

    @Override
    public void transfer(Account from, Account to, Integer money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                accountDao.out(from, money);
                int d = 1 / 0;
                accountDao.in(to, money);
            }
        });
    }

}

2. Make the configuration in 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:context="http://www.springframework.org/schema/context"
    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">

    <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>
    
    <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
    <bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean>

    <!-- (三)、在业务层注入模板类管理事务 -->
    <!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
    <bean id="accountService" class="com.hao.tx.service.impl.AccountServiceImpl_Program">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>
    
    
    <!-- (一)、注册事务管理器: -->
    
    <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
    <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>

3. Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext1.xml")
public class TxAcTest001 {

    @Autowired
    @Qualifier("accountService") 
    private IAccountService accountService;

    @Test
    public void test01() {
        System.out.println("转账之前....");
        Account a = accountService.findAccountByName("txa");
        if (a != null) {
            System.out.println(a);
        }

        Account b = accountService.findAccountByName("txb");
        if (b != null) {
            System.out.println(b);
        }
        
        try {// 这里捕获转账时出现的异常
            System.out.println("开始转账.....");
            accountService.transfer(a, b, 100); //会出现异常
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("转账之后....");
            Account a_trans = accountService.findAccountByName("txa");
            if (a != null) {
                System.out.println(a_trans);
            }
            Account b_trans = accountService.findAccountByName("txb");
            if (b != null) {
                System.out.println(b_trans);
            }
        }
    }
}

The results are as follows:

4. Manually coding disadvantages:

  Increasing the amount of code, the code intrusive.

Fourth, declarative transaction

Declarative transaction management :( original way)

Based TransactionProxyFactoryBean.

1. Business Class

  Creating AccountServiceImpl_DeclaProxyF class, here to test the use of learning, in fact, without changing any logical business class, you can copy the direct preparation of business class.
  

2. XML to configure

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

    <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>
    
    <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
    <bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
    <bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean>

    <!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
    <bean id="accountService"
        class="com.hao.tx.service.impl.AccountServiceImpl_DeclaProxyF">
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    

    <!-- (一)、注册事务管理器: -->

    <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
    <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> <!-- key值表示要进行事务管理的方法 -->
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

</beans>

3. Test

  Note that in the test is to be injected into the proxy object

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class TxAcTest002 {

    @Autowired
    @Qualifier("accountServiceProxy") // 这里注入的代理对象
    private IAccountService accountService;

    @Test
    public void test01() {
        System.out.println("转账之前....");
        Account a = accountService.findAccountByName("txa");
        if (a != null) {
            System.out.println(a);
        }

        Account b = accountService.findAccountByName("txb");
        if (b != null) {
            System.out.println(b);
        }
        
        try {// 这里捕获转账时出现的异常
            System.out.println("开始转账.....");
            accountService.transfer(a, b, 100); //会出现异常
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("转账之后....");
            Account a_trans = accountService.findAccountByName("txa");
            if (a != null) {
                System.out.println(a_trans);
            }
            Account b_trans = accountService.findAccountByName("txb");
            if (b != null) {
                System.out.println(b_trans);
            }
        }
    }
}

4. Notes and disadvantages

注意事项:配置代理对象时:prop格式:PROPAGATION , ISOLATION , readOnly, -Exception, +Exception 依次是:传播行为、隔离级别、事务是否只读、发生哪些异常可以回滚事务(所有的异常都回滚)、发生了哪些异常不回滚。

缺点:就是需要为每一个管理事务的类生成代理.需要为每个类都需要进行配置。

声明值事务-基于AspectJ XML方式

1. 业务类

  创建AccountServiceImpl_DeclaAspecJ类,这里是为了学习时测试使用,其实无需改变业务类的任何逻辑,可以直接copy准备中的业务类。
  

2. 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.driver}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
    <bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
    <bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean>

    <!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
    <bean id="accountService"
        class="com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJ">
        <property name="accountDao" ref="accountDao"></property>
    </bean>


    <!-- (一)、注册事务管理器: -->

    <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
    <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:-1 
                no-rollback-for:发生哪些异常不回滚 
                rollback-for:发生哪些异常回滚事务 
            -->
            <tx:method name="transfer" isolation="DEFAULT"  propagation="REQUIRED"/>
        
        </tx:attributes>
    </tx:advice>

    
    <!-- (三)、定义aop的配置(切点和通知的组合) -->
    <!-- aop配置定义切面和切点的信息 -->
    <aop:config>
        <!-- 定义切点:哪些类的哪些方法应用增强 -->
        <aop:pointcut
            expression="execution(* com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJ+.*(..))"
            id="mypointcut" />
        <!-- 定义切面: -->
        <aop:advisor advice-ref="txAdvice"  pointcut-ref="mypointcut" />
    </aop:config>
</beans>

3. 测试

  这里无需注入代理对象

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class TxAcTest003 {

    @Autowired
    @Qualifier("accountService") //  注入Service对象,不需要注入代理对象(生成这个类的时候,已经是代理对象.)
    private IAccountService accountService;

    @Test
    public void test01() {
        System.out.println("转账之前....");
        Account a = accountService.findAccountByName("txa");
        if (a != null) {
            System.out.println(a);
        }

        Account b = accountService.findAccountByName("txb");
        if (b != null) {
            System.out.println(b);
        }
        
        try {// 这里捕获转账时出现的异常
            System.out.println("开始转账.....");
            accountService.transfer(a, b, 100); //会出现异常
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("转账之后....");
            Account a_trans = accountService.findAccountByName("txa");
            if (a != null) {
                System.out.println(a_trans);
            }
            Account b_trans = accountService.findAccountByName("txb");
            if (b != null) {
                System.out.println(b_trans);
            }
        }
    }
}

声明值事务-基于AspectJ 注解方式

1. 业务类

  • 在Service上使用注解@Transactional,此注解可以标注在方法上,还可以标注在类上:
    • 注解中有属性值:
    • isolation
    • propagation
    • readOnly
      ...
/**
 * 声明式事务-基于AspectJ 注解方式
 * 
 * @author hao
 *
 */
public class AccountServiceImpl_DeclaAspecJAnno implements IAccountService {
    // 注入 accountDao 利用setter方法注入属性
    private IAccountDao accountDao;

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

    @Override
    public void addAccount(Account account) {
        accountDao.add(account);
    }
    
    @Override
    public Account findAccountByName(String name) {
        
        Account account = accountDao.selectOneByName(name);
        return account;
    }
    
    
    @Override
    @Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
    public void transfer(Account from, Account to, Integer money) {
        accountDao.out(from, money);// 转出钱
        int i =1/0;   // 中间出现异常
        accountDao.in(to, money);// 收入钱
    }
    
}

2. 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.driver}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 在容器中声明jdbc模版,这里需要注入数据源 -->
    <bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 此处声明Dao层类,用注解的方式将jdbcTemplate注入到了accountDao中,也可用其他方式 -->
    <bean id="accountDao" class="com.hao.tx.dao.impl.AccountDaoImpl"></bean>

    <!-- 此处声明业务层类,用setter的方式注入了accountDao 和 管理事务的模版 -->
    <bean id="accountService"
        class="com.hao.tx.service.impl.AccountServiceImpl_DeclaAspecJAnno">
        <property name="accountDao" ref="accountDao"></property>
    </bean>


    <!-- (一)、注册事务管理器: -->

    <!-- 配置事务管理器 这里DataSourceXXX...可以用做Spring自己的或者MyBatis的事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 需要注入连接池,通过连接池获得连接 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- (二)、开启注解的事务管理 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
</beans>

3. 测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext4.xml")
public class TxAcTest004 {

    @Autowired
    @Qualifier("accountService") //  注入Service对象,不需要注入代理对象(生成这个类的时候,已经是代理对象.)
    private IAccountService accountService;

    @Test
    public void test01() {
        System.out.println("转账之前....");
        Account a = accountService.findAccountByName("txa");
        if (a != null) {
            System.out.println(a);
        }

        Account b = accountService.findAccountByName("txb");
        if (b != null) {
            System.out.println(b);
        }
        
        try {// 这里捕获转账时出现的异常
            System.out.println("开始转账.....");
            accountService.transfer(a, b, 100); //会出现异常
        } catch (ArithmeticException e) {
            e.printStackTrace();
        } finally {
            System.out.println("转账之后....");
            Account a_trans = accountService.findAccountByName("txa");
            if (a != null) {
                System.out.println(a_trans);
            }
            Account b_trans = accountService.findAccountByName("txb");
            if (b != null) {
                System.out.println(b_trans);
            }
        }
    }
}

Guess you like

Origin www.cnblogs.com/haoworld/p/spring-bian-cheng-shi-shi-wu-he-sheng-ming-shi-shi.html