Spring 编程式事物练习,声明式事物的练习,注解事物的练习
Spring 编程式事物的练习,声明式事物的练习,注解事物的练习
上个博客中有建数据库,这里我就不再建了。
一,编程式事物的练习:
导入jar包
<dependencies> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.11</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> <scope>runtime</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-spec</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-impl</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.41</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument</artifactId> <version>5.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jms --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>5.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-messaging --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-oxm --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.25</version> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.3</version> </dependency> </dependencies>
创建Userinfo实体类---与表字段类型一致
package entity; import java.util.Date; public class Userinfo { private Integer id; private String username; private Date birthday; private String sex; private String address; private Integer money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex == null ? null : sex.trim(); } public String getAddress() { return address; } public void setAddress(String address) { this.address = address == null ? null : address.trim(); } public Integer getMoney() { return money; } public void setMoney(Integer money) { this.money = money; } @Override public String toString() { return "Userinfo{" + "id=" + id + ", username='" + username + '\'' + ", birthday=" + birthday + ", sex='" + sex + '\'' + ", address='" + address + '\'' + ", money=" + money + '}'; } }
创建转账接口
package change; public interface ChangeMoney { boolean giveMoney(int on, int to, int money); }
使用generator.xml创建接口的数据库语句
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="testTables" targetRuntime="MyBatis3"> <commentGenerator> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true" /> </commentGenerator> <!--数据库连接的信息:驱动类、连接地址、用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/t142" userId="root" password="123456"> </jdbcConnection> <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" userId="yycg" password="yycg"> </jdbcConnection> --> <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetProject:生成PO类的位置 --> <javaModelGenerator targetPackage="main" targetProject=".\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- targetProject:mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="main" targetProject=".\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage:mapper接口生成的位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="main" targetProject=".\src"> <!-- enableSubPackages:是否让schema作为包的后缀 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!--指定数据库表--> <table tableName="userinfo" domainObjectName="Userinfo" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"></table> <!--<table tableName="test" domainObjectName="Test" enableCountByExample="false" enableDeleteByExample="false"--> <!--enableSelectByExample="false" enableUpdateByExample="false"></table>--> </context> </generatorConfiguration>
创建运行generator.xml的Generator
import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.config.Configuration; import org.mybatis.generator.config.xml.ConfigurationParser; import org.mybatis.generator.internal.DefaultShellCallback; import java.io.File; import java.util.ArrayList; import java.util.List; public class Generator { /** * @param args */ public static void main(String[] args) throws Exception{ List<String> warnings = new ArrayList<String>(); boolean overwrite = true; File configFile = new File("D:\\IDe\\SpringPmtx\\src\\main\\resources\\generator.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); } }
将创建的UserinfoMapper.xml放在resources/mapper里,将里面的pojo替换成entity
创建impl实现接口方法
package change; import entity.Userinfo; import mapper.UserinfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; @Component public class ChangeMoneyImpl_Pmtx implements ChangeMoney { @Autowired private UserinfoMapper mapper; @Autowired private TransactionTemplate transactionTemplate; class Result{ boolean result; } @Override public boolean giveMoney(int on, int to, int money) { final Result result =new Result() ; transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { try { giveMoneyOption(on, to, money); System.out.println("=======事务提交了====="); //事务回滚 result.result = true; }catch (Exception e){ System.out.println("=======事务回滚了====="); //事务回滚 transactionStatus.setRollbackOnly(); result.result = false; } } }); return result.result; } public void giveMoneyOption(int on, int to, int money) throws Exception { Userinfo userinfo =mapper .selectByPrimaryKey(on); int i=0; if (userinfo!=null){ //设置转钱人的余额 userinfo.setMoney(userinfo.getMoney()-money); //受影响的行数 i = mapper.updateByPrimaryKey(userinfo); } //被转钱人的信息 Userinfo userinfo2 =mapper .selectByPrimaryKey(to); int j=0; if (userinfo2!=null){ //设置转钱人的余额 userinfo2.setMoney(userinfo2.getMoney()+money); //受影响的行数 j = mapper.updateByPrimaryKey(userinfo2); } if (i>0&&j>0){ System.out.println("转账成功!!"); }else { //回滚事务 System.out.println("转账失败!!"); throw new Exception("转账失败的异常"); } } }
加入事物管理器
package proxy; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class Proxy_Pmtx implements MethodInterceptor { @Override public Object invoke(MethodInvocation method) throws Throwable { //调用目标方法 Object result = method.proceed(); return result; } }
加入beans_Pmtx.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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--1、加载数据库的配置信息 --> <context:property-placeholder location="database.properties" /> <!--2、datasource数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${uName}" /> <property name="password" value="${password}" /> </bean> <!-- 3、sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 别名 --> <property name="typeAliasesPackage" value="entity"/> <!-- mapper XML映射 --> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"></property> <!-- 数据源 --> <property name="dataSource" ref="dataSource"></property> </bean> <!--4、mapper接口的位置 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="mapper"></property> </bean> <!-- 1)、事务管理(增强/通知): --> <bean id="txManager" 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="txManager"/> </bean> </beans>
加入beans_proxy_Pmtx.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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd "> <!-- 1、启动注解扫描--> <!-- <context:annotation-config/> --> <context:component-scan base-package="change"/> <!-- 1)目标 --> <bean id="target" class="change.ChangeMoneyImpl_Pmtx"/> <!-- 2)黑客 --> <bean id="proxy_BC" class="proxy.Proxy_Pmtx"/> <!--3)代理 --> <bean id="changeMoney" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces" value="change.ChangeMoney"></property> <!-- 1)注入目标对象 --> <property name="target" ref="target"/> <!-- 2)黑客对象 --> <property name="interceptorNames"> <array> <value>proxy_BC</value> </array> </property> </bean> </beans>
加入database.properties
url=jdbc:mysql://localhost:3306/t142?useUnicode=true&&characterEncoding=utf-8 driver=com.mysql.jdbc.Driver uName=root password=123456
编写测试工具
import change.ChangeMoney; 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; //编程式事务 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:beans_proxy_Pmtx.xml", "classpath:beans_Pmtx.xml"}) //生成代理的 生成事务管理器(TransactionTemplate)的 public class SpringPmtxTest { //编程式事务,自己通过aop实现事务管理器 @Autowired @Qualifier("changeMoney") private ChangeMoney changeMoney; @Test public void test2(){ boolean result = changeMoney.giveMoney(1, 2, 300); System.out.println(result); } }
测试结果
转账成功!! =======事务提交了===== true Process finished with exit code 0
二:声明式事物:
创建impl实现接口方法
package change; import entity.Userinfo; import mapper.UserinfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ChangeMoneyImpl_Dlttx implements ChangeMoney { @Autowired private UserinfoMapper mapper; @Override public boolean giveMoney(int on, int to, int money) { boolean result=giveMoneyOption(on,to,money); return result; } public boolean giveMoneyOption(int on, int to, int money) { Userinfo userinfo =mapper .selectByPrimaryKey(on); int i=0; if (userinfo!=null){ //设置转钱人的余额 userinfo.setMoney(userinfo.getMoney()-money); //受影响的行数 i = mapper.updateByPrimaryKey(userinfo); } //被转钱人的信息 Userinfo userinfo2 =mapper .selectByPrimaryKey(to); int j=0; if (userinfo2!=null){ //设置转钱人的余额 userinfo2.setMoney(userinfo2.getMoney()+money); //受影响的行数 j = mapper.updateByPrimaryKey(userinfo2); } if (i>0&&j>0){ System.out.println("转账成功!!"); return true; }else { //回滚事务 System.out.println("转账失败!!"); throw new RuntimeException("转账失败的异常"); } } }
加入事物管理器
package proxy; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class Proxy_Dlttx implements MethodInterceptor { @Override public Object invoke(MethodInvocation method) throws Throwable { //调用目标方法 Object result = method.proceed(); return result; } }
加入beans_Dlttx.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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--1、加载数据库的配置信息 --> <context:property-placeholder location="database.properties" /> <!--2、datasource数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${uName}" /> <property name="password" value="${password}" /> </bean> <!-- 3、sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 别名 --> <property name="typeAliasesPackage" value="entity"/> <!-- mapper XML映射 --> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"></property> <!-- 数据源 --> <property name="dataSource" ref="dataSource"></property> </bean> <!--4、mapper接口的位置 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="mapper"></property> </bean> <!-- 1)、事务管理(增强/通知): --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 第1步:定义一个通知 advice --> <tx:advice id="gmAdvice" transaction-manager="txManager"> <tx:attributes> <!-- 这个方法才会使用事务管理器 --> <tx:method name="giveMoney*"/> <!-- 其他任何方法,使用只读事务 isolation="DEFAULT" 事务隔离级别 propagation="REQUIRED" 事务传播特性 timeout="-1" 事务的超时时间 no-rollback-for="" 指定某种运行时异常不回滚 rollback-for="" 指定某种运行时异常才回滚 --> </tx:attributes> </tx:advice> <!-- 第2步:将通知植入切点 public void giveMoney(int a){} public void change.ChangeMoneyImpl_SM.giveMoney(..) --> <aop:config> <!-- 1)切点--> <aop:pointcut id="pointCut" expression="execution(* change.ChangeMoneyImpl_Dlttx.*(..))" /> <!-- 2)植入 :将通知植入到切点中--> <aop:advisor advice-ref="gmAdvice" pointcut-ref="pointCut"/> </aop:config> </beans>
加入beans_proxy_Dlttx.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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1、启动注解扫描--> <context:annotation-config/> <context:component-scan base-package="change"/> <!-- 1)目标 --> <bean id="target_SM" class="change.ChangeMoneyImpl_Dlttx"/> <!-- 2)黑客 --> <bean id="proxy_SM" class="proxy.Proxy_Dlttx"/> <!--3)代理 --> <bean id="changeMoney_sm" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 接口--> <property name="proxyInterfaces" value="change.ChangeMoney"/> <!-- 1)注入目标对象 --> <property name="target" ref="target_SM"/> <!-- 2)黑客对象 --> <property name="interceptorNames"> <array> <value>proxy_SM</value> </array> </property> </bean> </beans>
加入database.properties
url=jdbc:mysql://localhost:3306/t142?useUnicode=true&&characterEncoding=utf-8 driver=com.mysql.jdbc.Driver uName=root password=123456
编写测试工具
import change.ChangeMoney; 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; //编程式事务 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:beans_proxy_Dlttx.xml", "classpath:beans_Dlttx.xml"}) //生成代理的 生成事务管理器(TransactionTemplate)的 public class SpringDlttxTest { //编程式事务,自己通过aop实现事务管理器 @Autowired @Qualifier("changeMoney_sm") private ChangeMoney changeMoney; @Test public void test2(){ boolean result = changeMoney.giveMoney(2, 1, 300); System.out.println(result); } }
测试结果
转账成功!! true Process finished with exit code 0
或
转账失败!! java.lang.RuntimeException: 转账失败的异常 at change.ChangeMoneyImpl_Dlttx.giveMoneyOption(ChangeMoneyImpl_Dlttx.java:45) at change.ChangeMoneyImpl_Dlttx.giveMoney(ChangeMoneyImpl_Dlttx.java:17) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498)
三:注解事物
创建impl实现接口方法
package change; import entity.Userinfo; import mapper.UserinfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @Component public class ChangeMoneyImpl_Attx implements ChangeMoney { @Autowired private UserinfoMapper mapper; @Override @Transactional() public boolean giveMoney(int on, int to, int money) { boolean result=giveMoneyOption(on,to,money); return result; } public boolean giveMoneyOption(int on, int to, int money) { Userinfo userinfo =mapper .selectByPrimaryKey(on); int i=0; if (userinfo!=null){ //设置转钱人的余额 userinfo.setMoney(userinfo.getMoney()-money); //受影响的行数 i = mapper.updateByPrimaryKey(userinfo); } //被转钱人的信息 Userinfo userinfo2 =mapper .selectByPrimaryKey(to); int j=0; if (userinfo2!=null){ //设置转钱人的余额 userinfo2.setMoney(userinfo2.getMoney()+money); //受影响的行数 j = mapper.updateByPrimaryKey(userinfo2); } if (i>0&&j>0){ System.out.println("转账成功!!"); return true; }else { //回滚事务 System.out.println("转账失败!!"); throw new RuntimeException("转账失败的异常"); } } }
加入事物管理器
package proxy; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class Proxy_Attx implements MethodInterceptor { @Override public Object invoke(MethodInvocation method) throws Throwable { //调用目标方法 Object result = method.proceed(); return result; } }
加入beans_Attx.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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--1、加载数据库的配置信息 --> <context:property-placeholder location="database.properties" /> <!--2、datasource数据源 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${uName}" /> <property name="password" value="${password}" /> </bean> <!-- 3、sqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 别名 --> <property name="typeAliasesPackage" value="entity"/> <!-- mapper XML映射 --> <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"></property> <!-- 数据源 --> <property name="dataSource" ref="dataSource"></property> </bean> <!--4、mapper接口的位置 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="mapper"></property> </bean> <!-- 1)、事务管理(增强/通知): --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 声明式事务注解方式:第1步:开启注解事务 proxy-target-class="true" 指定注解事务是使用cglib动态代理方式来实现 --> <tx:annotation-driven transaction-manager="txManager"/> </beans>
加入beans_proxy_Attx.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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1、启动注解扫描--> <context:annotation-config/> <context:component-scan base-package="change"/> <!-- 1)目标 --> <bean id="target_ZJSM" class="change.ChangeMoneyImpl_Attx"/> <!-- 2)黑客 --> <bean id="proxy_ZJSM" class="proxy.Proxy_Attx"/> <!--3)代理 --> <bean id="changeMoney_zjsm" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 接口--> <property name="proxyInterfaces" value="change.ChangeMoney"/> <!-- 1)注入目标对象 --> <property name="target" ref="target_ZJSM"/> <!-- 2)黑客对象 --> <property name="interceptorNames"> <array> <value>proxy_ZJSM</value> </array> </property> </bean> </beans>
加入database.properties
url=jdbc:mysql://localhost:3306/t142?useUnicode=true&&characterEncoding=utf-8 driver=com.mysql.jdbc.Driver uName=root password=123456
编写测试工具
import change.ChangeMoney; 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; //编程式事务 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:beans_proxy_Attx.xml", "classpath:beans_Attx.xml"}) //生成代理的 生成事务管理器(TransactionTemplate)的 public class SpringAttxTest { //编程式事务,自己通过aop实现事务管理器 @Autowired @Qualifier("changeMoney_zjsm") private ChangeMoney changeMoney; @Test public void test2(){ boolean result = changeMoney.giveMoney(1, 2, 300); System.out.println(result); } }
测试结果
转账成功!! true Process finished with exit code 0
或
转账失败!! java.lang.RuntimeException: 转账失败的异常 at change.ChangeMoneyImpl_Attx.giveMoneyOption(ChangeMoneyImpl_Attx.java:47) at change.ChangeMoneyImpl_Attx.giveMoney(ChangeMoneyImpl_Attx.java:19) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)