Spring的编程式事务管理与声明式事务管理(十三)

搭建Spring事务管理的环境

要进行编程式事务管理或者是声明式事务管理开发,都需要先将开发环境搭建完毕。

构造环境所需要到Jar包,包括Spring环境的基本包和搭建事务所需要的Jar包:
Spring的编程式事务管理与声明式事务管理(十三)_第1张图片


我们模拟的是银行转账的事务环境,也就是转入转出金钱,还需要搭建一个数据库环境。

建立一个User表,内含id,name,money三个字段:

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
)

并且引入记录数据库连接信息的外部配置文件 jdbc.properties:

#定义连接参数
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/an?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=root

搭建好了数据库,就开始创建Service的接口和实现类,用来操作转账的业务。到时候事务也是要布置在这一层面上。

Service接口:AccountService

/*
* 转账的业务层接口
* */
public interface AccountService {
    public void transfer(String from, String to, double money);
}

Service接口的实现类:AccountServiceImpl

/*
* 转账的业务层的实现类
* */
public class AccountServiceImpl implements AccountService {

    //注入Dao
    @Resource(name="accountDao")
    private AccountDao accountDao;
    
    /*
    * from:转出账号
    * to:转入账号
    * money:转账金额
    * */
    @Override
    public void transfer(String from, String to, double money) {
        accountDao.outMoney(from, money);
        accountDao.inMoney(to,money);
    }
}

配置好了Service业务层,接下来要配置的是Dao层的接口和实现类。

Dao的接口:AccountDao

/*
 * 转账DAO的接口
 * */
public interface AccountDao {
    //转出金钱,减钱
    public void outMoney(String from, double money);

    //转入金钱,加钱
    public void inMoney(String to, double money);
}

Dao接口的实现类:AccountDaoImpl

在实现类中,通过继承JdbcDaoSupport 类的方式,简化了连接数据库的操作,无需再每次定义DataSource和jdbcTemplate对象,再进行数据库的操作。

通过对JdbcDaoSupport 类的dataSource的XML方式属性注入,调用setDataSource方法,set方法中书写了创建jdbcTemplate对象的操作,从而通过getJdbcTemplate方法获取模板操作的对象。

/*
* 转账DAO的实现类
*
* */
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
//    由于AccountDaoImpl类继承了JdbcDaoSupport类,类中有dataSource和jdbcTemplate成员属性
//    然后使用JdbcDaoSupport类中的setDataSource的方法
    //setDataSource方法中会使用注入的dataSource属性,创建jdbcTemplate模板对象,并将其赋值给jdbcTemplate成员
    //我们就可以直接使用jdbcTemplate模板对象了。

    /*
    * from:转出账号
    * money:转出金额
    * */
    @Override
    public void outMoney(String from, double money) {
        this.getJdbcTemplate().update("update account set money = money - ? where name = ?", money, from);
    }

    /*
    *转入账号:to
    * 转入金钱 :money
    * */
    @Override
    public void inMoney(String to, double money) {
        this.getJdbcTemplate().update("update account set money = money + ? where name = ?", money, to);
    }
}

当将Service层和Dao层创建完毕了,就应该进行applicationContext.xml配置文件的配置了,将Service层和Dao层交给Spring来管理

同时将C3PO的连接池对象也交给Spring管理,并且引入数据库连接配置文件,为C3PO类注入相关属性。

并且开启注解的组件扫描

为了减少编写事务的代码量,还需要配置平台事务管理器(DataSourceTransactionManager)和事务管理的模板(TransactionTemplate)

配置文件:tx.xml




    
    

    
    

    
    
    
    
        
    

    
    
    

    
    
        
        
        
        
    

	
    
    
        
    


    
    
    
    
        
    


最后编写一个测试类,基本的事务管理环境就搭建好了,就可以进行事务的开发测试了。

SpringTest:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:tx.xml")
public class SpringTest {

    @Resource(name = "accountService")
    private AccountService accountService;
    @Test
    public void test() {
        accountService.transfer("kk","kk2",50);
    }
}

编程式事务管理

环境搭建好后,需要在使用事务管理的地方添加一个事务管理的模板,也就是要在业务层的实现类 AccountServiceImpl 中添加一个成员,并且为其注入属性:

 @Resource(name = "transactionTemplate")
 private TransactionTemplate transactionTemplate;

然后在AccountServiceImpl书写事务操作:

public class AccountServiceImpl implements AccountService {

    //注入Dao
    @Resource(name="accountDao")
    private AccountDao accountDao;

    //注入事务模板

    @Resource(name = "transactionTemplate")
    private TransactionTemplate transactionTemplate;
    /*
    * from:转出账号
    * to:转入账号
    * money:转账金额
    * */
    @Override
    public void transfer(String from, String to, double money) {
        //采用匿名内部类的方式,创建一个事务,抛出异常将会回滚数据,
        // 采用的是PROPAGATION_REQUIRED传播行为(保证多个操作在同一个事务中)
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.outMoney(from, money);
                //设置一个bug,数据会回滚,则说明已经启动了事务
                int d = 1/0;
                accountDao.inMoney(to,money);
            }
        });
    }
}

声明式事务管理(通过配置完成)— AOP的思想

声明式事务管理应用的是Spring的AOP的思想

在操作前开启事务,操作完毕后关闭事务(环绕通知),在遇到异常情况的时候回滚数据。相当于是对业务操作进行增强,而且不涉及到源代码的修改。

同样的,声明式事务管理有两种配置方式,同时需要引入AOP的jar包:

  • XML方式

    首先,按照上面的环境配置,重新复制一份新的环境,恢复一下转账的环境。

    复制一份tx2.xml,并删除事务管理模板(TransactionTemplate)的bean。

    配置事务的增强(tx:advice),事务的增强是固定的一种通知,有特定的格式,是一种规则




    
        
        
        

        
        
        
        
        
    

然后进行AOP的配置,也就是要将增强配置到目标类:




    
    

当配置完成以后,就已经为目标方法设定好了事务,只要直接运行测试类,执行这个方法,就会自动的使用事务。

  • 注解方式

注解方式在开始搭建的基本开发环境上只需要做三件事

1.配置事务管理器




    

2.开启注解事务:

 
 

3.在目标类AccountServiceImpl上添加一个@Transactional 注解

//事务的各类属性,就在注解上配置即可,如传播行为,隔离级别,超时时间等等
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
	............
}

总结

对于上述三种Spring事务管理方式,有一个共同点,都是需要在xml配置文件中配置一个 事务管理器(DataSourceTransactionManager)




    

对于声明式事务来说,两个方式都具有各自的好处

XML方式的好处在于只需要在配置文件中配置完成,就不需要在去理业务层的逻辑,只用再配置文件中修改事务的规则即可,缺点就是配置麻烦。

而注解方式的好处就是在于便捷,极少的代码,只需要三步,配置事务管理器,开启注解事务,类上注解(@Transactional ),就可以为目标类开启事务了(事务的各项属性,都是在注解上配置)。缺点就是不够灵活,在每次书写业务层类的时候,都必须要记得在类上添加注解。

你可能感兴趣的:(Java,Spring)