Spring声明式事务配置,实现模拟转账过程 (AspectJ)
编程式事务要修改service层的代码,很少用,相比之下,AspectJ增强事务管理器,在xml中配置切面切点(AOP),而service代码不用做修改。
1.新建数据表
DROP TABLE IF EXISTS `account`; CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `money` double unsigned zerofill DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; INSERT INTO `account` VALUES ('1', 'aa', '1000'); INSERT INTO `account` VALUES ('2', 'bb', '1000'); INSERT INTO `account` VALUES ('3', 'cc', '1000');
2.新建项目,引入jar包
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.2.1.RELEASE</version> </dependency> <!-- spring end --> <!-- c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency>
3.log4.properties
#console log log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n #all log log4j.appender.DAILY_ALL=org.apache.log4j.DailyRollingFileAppender log4j.appender.DAILY_ALL.layout=org.apache.log4j.PatternLayout log4j.appender.DAILY_ALL.layout.ConversionPattern="%p %d{yyyy-MM-dd HH:mm:ss} %-50.50c(%L) - %m%n log4j.appender.DAILY_ALL.File=d:/myjaval.log log4j.appender.DAILY_ALL.DatePattern='.'yyyy-MM-dd #logger #log4j.logger.org.springframework=INFO,CONSOLE #log4j.logger.org.hibernate=INFO,CONSOLE #log4j.logger.org.apache=INFO,CONSOLE log4j.rootLogger=INFO,CONSOLE,DAILY_ALL
jdbc_driverClassName=com.mysql.jdbc.Driver jdbc_url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8 jdbc_username=root jdbc_password=root
5.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:tx="http://www.springframework.org/schema/tx" 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/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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "> <!-- 声明式事务管理 --> <!-- 引入外部属性文件 --> <!-- <context:property-placeholder location="classpath:jdbc.properties"/> --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:jdbc.properties</value> </list> </property> </bean> <!-- c3p0连接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc_driverClassName}" /> <property name="jdbcUrl" value="${jdbc_url}" /> <property name="user" value="${jdbc_username}" /> <property name="password" value="${jdbc_password}" /> </bean> <!-- 配置业务层 --> <!-- 开启annotation --> <context:annotation-config/> <context:component-scan base-package="cn.dx.spring.transaction2.service" /> <context:component-scan base-package="cn.dx.spring.transaction2.dao" /> <!-- JDBC模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 配置事务管理器: --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 开启AOP监听 只对当前配置文件有效 --> <aop:aspectj-autoproxy expose-proxy="true"/> <!-- 开启注解事务 只对当前配置文件有效 --> <tx:annotation-driven transaction-manager="txManager"/> <!-- 配置事务的通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- transfre方法 ( *代表所有 )--> <tx:method name="transfer" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <!-- 配置事务的切点,并把事务切点和事务属性不关联起来 --> <aop:config expose-proxy="true"> <!-- 切点 只对业务逻辑层实施事务 --> <aop:pointcut id="txPointcut" expression="execution(* cn.dx.spring..service..*.*(..))" /> <!-- 切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config> </beans>
6.DAO以及实现
package cn.dx.spring.transaction2.dao; public interface AccountDao { /** * @param out 转出账户 * @param money 转出金额 */ void outMoney(String out,Double money); /** * @param in :传入账号 * @param money :转入金额 */ void inMoney(String in,Double money); }
package cn.dx.spring.transaction2.dao.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import cn.dx.spring.transaction2.dao.AccountDao; @Component("AccountDao") public class AccountDaoImpl implements AccountDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void outMoney(String out, Double money) { String sql = "update account set money = money - ? where name = ?"; this.jdbcTemplate.update(sql,money,out); } @Override public void inMoney(String in, Double money) { String sql = "update account set money = money + ? where name = ?"; this.jdbcTemplate.update(sql,money,in); } }
7.service以及实现
package cn.dx.spring.transaction2.service; /** * 转账Service * @author 大雄 * */ public interface AccountService { /** * * @param out:转出账户 * @param in:转入账户 * @param money:转账金额 */ void transfer(String out,String in,Double money); }
package cn.dx.spring.transaction2.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import cn.dx.spring.transaction2.dao.AccountDao; import cn.dx.spring.transaction2.service.AccountService; @Service("AccountService") public class AccountServiceImpl implements AccountService { @Autowired @Qualifier("AccountDao") private AccountDao accountDao; @Override public void transfer(final String out,final String in,final Double money) { accountDao.outMoney(out, money); int i = 1/0; accountDao.inMoney(in, money); } }
8.测试
package cn.dx.myjava.spring.transaction; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import cn.dx.spring.transaction.service.AccountService; /** * 编程式事务管理 * 转账测试 * @author 大雄 * */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class Transtraction { //测试业务层的类 @Autowired @Qualifier("AccountService") private AccountService accountService; @Test public void transaction(){ this.accountService.transfer("aa", "bb", 200d); } }