一、创建数据库并插入数据
create database spring_transaction; use spring_transaction; create table account( id int primary key auto_increment, username varchar(50), money int ); insert into account(username,money) values('jack',1000); insert into account(username,money) values('rose',1000);
二、无事务下操作数据
1、项目结构及引用的相应jar包
2、创建接口AccountDao及其实现类AccountDaoImpl(实现类继承自JdbcDaoSupport,可以直接获得jdbc模板对象)
package com.hujp.dao; /** * Created by JiaPeng on 2015/11/4. */ public interface AccountDao { /** * 收款(入) * @param inUser * @param money */ public void in(String inUser,int money); /** * 汇款(出) * @param outUser * @param money */ public void out(String outUser,int money); }
package com.hujp.dao.impl; import com.hujp.dao.AccountDao; import org.springframework.jdbc.core.support.JdbcDaoSupport; /** * Created by JiaPeng on 2015/11/4. */ public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { @Override public void in(String inUser, int money) { this.getJdbcTemplate().update("UPDATE account SET money=money+? WHERE username=?",money,inUser); } @Override public void out(String outUser, int money) { this.getJdbcTemplate().update("UPDATE account SET money=money-? WHERE username=?", money, outUser); } }
3、创建接口AccountService及其实现类AccountServiceImpl(实现类里需要有AccountDao字段,在spring配置中注入)
package com.hujp.service; /** * Created by JiaPeng on 2015/11/4. */ public interface AccountService { public void transfer(String outUser,String inUser,int money); }
package com.hujp.service.impl; import com.hujp.dao.AccountDao; import com.hujp.service.AccountService; /** * Created by JiaPeng on 2015/11/4. */ public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transfer(String outUser, String inUser, int money) { this.accountDao.out(outUser, money); //模拟断电 //int m=2/0; this.accountDao.in(inUser, money); } }
4、配置文件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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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"> <!--配置数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property> <property name="user" value="root"></property> <property name="password" value="hjp123"></property> </bean> <!--配置Dao--> <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置Service--> <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> </beans>
package com.hujp; import com.hujp.service.AccountService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by JiaPeng on 2015/11/4. */ public class TestApp { @Test public void demo1() { String xmlPath = "applicationContext.xml"; ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); AccountService accountService= (AccountService) applicationContext.getBean("accountService"); accountService.transfer("jack","rose",100); } }
5、代码结构图
二、手动操作事务管理数据库
事务管理主要在service层,所以需要改动两个文件即可,一个是application配置文件,另一个是AccountServiceImpl实现类
在实现类中,事务模板对象执行execute方法,重写事务返回无结果集抽象类TransactionCallbackWithoutResult的抽象方法doInTransactionWithoutResult达到事务管理目的
package com.hujp.service.impl; import com.hujp.dao.AccountDao; import com.hujp.service.AccountService; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; /** * Created by JiaPeng on 2015/11/4. */ public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } //事务操作一般在service层进行操作 private TransactionTemplate transactionTemplate; public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transfer(final String outUser,final String inUser, final int money) { //无结果集操作 this.transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { accountDao.out(outUser, money); //模拟断电 //int m=2/0; accountDao.in(inUser, money); } }); } }
<?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" xmlns:aop="http://www.springframework.org/schema/aop" 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"> <!--配置数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property> <property name="user" value="root"></property> <property name="password" value="hjp123"></property> </bean> <!--配置Dao--> <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置Service--> <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> <!--一般事务操作在service层进行,所以在service层注入模板--> <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <!--事务管理要提供事务管理器,事务是从数据库连接中获得的,而数据库连接是从连接池中获得的--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--提供事务模板,事务模板要在平台上进行事务操作--> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>
三、使用工厂bean创建代理管理事务
继续使用无事务下操作数据库的工程,测试类中accountService对象由代理类创建,并在配置文件配置工厂bean内配置事务
主要改两个文件,一个是测试类,其中获得service对象通过工厂bean获得;另一个是在applicationContext.xml文件中配置工厂bean和事务操作
package com.hujp; import com.hujp.service.AccountService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by JiaPeng on 2015/11/4. */ public class TestApp { @Test public void demo1() { String xmlPath = "applicationContext.xml"; ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); AccountService accountService= (AccountService) applicationContext.getBean("proxyService"); accountService.transfer("jack","rose",100); } }
<?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" xmlns:aop="http://www.springframework.org/schema/aop" 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"> <!--配置数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql:///spring_transaction"></property> <property name="user" value="root"></property> <property name="password" value="hjp123"></property> </bean> <!--配置Dao--> <bean id="accountDao" class="com.hujp.dao.impl.AccountDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置Service(目标类)--> <bean id="accountService" class="com.hujp.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <!--创建service代理对象之后使用的是代理对象--> <bean id="proxyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--确定事务管理器--> <property name="transactionManager" ref="transactionManager"></property> <!--确定接口--> <property name="proxyInterfaces" value="com.hujp.service.AccountService"></property> <!--确定目标类--> <property name="target" ref="accountService"></property> <!--配置事务属性(事务详情)--> <property name="transactionAttributes"> <!-- prop.key 表示事务详情名称,用于指定哪些方法使用设置的详情 比如目标类中的transfer方法 如果是add*,表示以add开头的方法;如果是*表示任意方法 prop.text 表示当前方法使用具体详情设置 格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception 传播行为 隔离级别 是否只读 异常回滚 异常提交 例如:PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ表示默认的传播行为和隔离级别 PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,readOnly表示只读 java.lang.ArithmeticException此异常是在断电程序中出现的 PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,+java.lang.ArithmeticException表示异常提交 --> <props> <!--<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop> <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,readOnly</prop>--> <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,+java.lang.ArithmeticException</prop> </props> </property> </bean> <!--管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> </beans>