Spring事物管理--编程式
以简单的转账金额为例:
1、数据库(建表、插入数据)
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 VALUE('1','aaa',1000); INSERT INTO account VALUE('2','bbb',1000); INSERT INTO account VALUE('3','ccc',1000);
2、引入jar包
3、创建jdbc.properties文件(设置连接数据库参数)
jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///xl jdbc.username=root jdbc.password=123456
4、创建Dao持久层
(1)、创建AccountDao接口
//转账案例持久层接口 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); }
(2)创建AccountDaoImpl实现类
继承JdbcDaoSupport类,从而获取jdbc模板,以便对数据库进行各种操作
//转账案例持久层实现类 public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { /** * @param out :转出账号 * @param money :转账金额 */ @Override public void outMoney(String out, Double money) { String sql = "update account set money = money - ? where name = ?"; this.getJdbcTemplate().update(sql,money,out); } /** * @param in :转入账号 * @param money :转账金额 */ @Override public void inMoney(String in, Double money) { String sql = "update account set money = money + ? where name = ?"; this.getJdbcTemplate().update(sql,money,in); } }
5、创建Service业务层
(1)、创建AccountService接口
//转账案例业务层接口 public interface AccountService { /** * @param out :转出账号 * @param in :转入账号 * @param money :转账金额 */ public void transfer(String out,String in,Double money); }
(2)、创建AccountServiceImpl实现类(用Dao持久层的转出、转入的方法)
//转账案例业务层实现类 public class AccountServiceImpl implements AccountService { //注入转账的Dao @Resource private AccountDao accountDao; /** * @param out :转出账号 * @param in :转入账号 * @param money :转账金额 */ @Override public void transfer(final String out, final String in, final Double money) { accountDao.outMoney(out, money); accountDao.inMoney(in, money); } }); } }
6、配置applicationContext.xml文件
引入jdbc.properties文件,在c3p0连接池中引用jdbc中的数据库连接参数,并将连接池设为持久层实现类的属性
<?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:context="http://www.springframework.org/schema/context" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.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> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 配置业务层类 --> <bean id="accountService" class="cn.xl.spring.demo1.AccountServiceImpl"> </bean> <!-- 配置持久层类 --> <bean id="accountDao" class="cn.xl.spring.demo1.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
7、测试类
//转账测试类 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 { @Resource(name="accountService") private AccountService accountService; @Test public void demo1(){ accountService.transfer("bbb", "aaa", 200d); } }
注:以上可以步骤可实现基本的数据业务操作,但存在一定的风险性,即钱转出了,对方却没有收到,这就坑爹了,
所以要使用事物管理,即:将转出与转入两个操作放到一个事物管理中,那么转出和转入要么一起成功,要么一起失败,
不会存在一个成功,另一个失败的情况!
8、在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:context="http://www.springframework.org/schema/context" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.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> <property name="jdbcUrl" value="${jdbc.url}"></property> <property name="user" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- 配置业务层类 --> <bean id="accountService" class="cn.xl.spring.demo1.AccountServiceImpl"> </bean> <!-- 配置持久层类 --> <bean id="accountDao" class="cn.xl.spring.demo1.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事物管理 器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置事物管理的模板:sping为了简化事物管理的代码而提供的类 --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>
此处把事物管理器设为事物管理模板的属性,因为事务管理模板使用更加方便、简洁
9、在AccountServiceImpl类中的两个持久层操作之间加入一个异常,以达到在不使用事物管理的情况下,两个数据业务操作不能够同步
即:添加 int i = 1/0;
还要注入事物管理模板类TransactionTemplate,调用execute方法,该方法有一个参数:TransactionCallback<T>事物回滚接口,而抽象类TransactionCallbackWithoutResult实现了TransactionCallback接口,并且自定义了doInTransactionWithoutResult方法,
最后把我们要执行的操作都放到doInTransactionWithoutResult中,即:被同一个事物管理
//转账案例业务层实现类 public class AccountServiceImpl implements AccountService { //注入转账的Dao @Resource private AccountDao accountDao; //注解式注入事物管理模板 @Resource private TransactionTemplate transactionTemplate; /** * @param out :转出账号 * @param in :转入账号 * @param money :转账金额 */ @Override public void transfer(final String out, final String in, final Double money) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { //把业务操作放入内部类中----在一个事物里面(同成功,同失败) accountDao.outMoney(out, money); int i = 1/0; accountDao.inMoney(in, money); } }); } }