19.Spring中使用AOP进行事务的增强(XML)
1.结构图
2.实体类Account:
package com.itheima.domin; public class Account { private Integer id; private String name; private Float money; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Float getMoney() { return money; } public void setMoney(Float money) { this.money = money; } @Override public String toString() { return "Account{" + "id=" + id + ", name='" + name + '\'' + ", money=" + money + '}'; } }
3.业务层接口IAccountService:
package com.itheima.service; import com.itheima.domin.Account; import java.util.List; //业务层接口 public interface IAccountService { //查询所有 List<Account> findAccountAll(); //查询一个 Account findAccountBuyId(Integer accountId); //保存 void saveAccount(Account account); //更新 void updateAccount(Account account); //删除 void deleteAccount(Integer accountId); //转账 void transfer(String sourceName , String targetName , Float money); }
4.事务层接口AccountServiceImpl:
package com.itheima.service.ipm; import com.itheima.dao.IAccountDao; import com.itheima.domin.Account; import com.itheima.service.IAccountService; import com.itheima.utils.TransactionManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; private TransactionManager txManager; public void setAccountDao(IAccountDao accountDao) { this.accountDao = accountDao; } public void setTxManager(TransactionManager txManager) { this.txManager = txManager; } @Override public List<Account> findAccountAll() { return accountDao.findAccountAll(); } @Override public Account findAccountBuyId(Integer accountId) { return accountDao.findAccountById(accountId); } @Override public void saveAccount(Account account) { accountDao.saveAccount(account); } @Override public void updateAccount(Account account) { accountDao.updateAccount(account); } @Override public void deleteAccount(Integer accountId) { accountDao.deleteAccount(accountId); } @Override public void transfer(String sourceName, String targetName, Float money) { //1.根据名称查询账户 Account source = accountDao.findAccountByName(sourceName); //2.根据名称查询转入账户 Account target = accountDao.findAccountByName(targetName); //3.转出账户减钱 source.setMoney(source.getMoney()-money); //4.转出账户加钱 target.setMoney(target.getMoney()+money); //int i=1/0; //5.更新转出账户 accountDao.updateAccount(source); //6.更新转入账户 accountDao.updateAccount(target); } }
5.IAccountDao持久层接口
package com.itheima.dao; import com.itheima.domin.Account; import java.util.List; public interface IAccountDao { //查询所有 List<Account> findAccountAll(); //查询一个 Account findAccountById(Integer accountId); //保存 void saveAccount(Account account); //更新 void updateAccount(Account account); //删除 void deleteAccount(Integer accountId); //转帐 Account findAccountByName(String accountName); }
6.持久层实现类AccountDaoImpl:
package com.itheima.dao.ipm; import com.itheima.dao.IAccountDao; import com.itheima.domin.Account; import com.itheima.utils.ConnectionUtils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.List; public class AccountDaoImpl implements IAccountDao { //让spring容器提供的set方法* //使用runner对象 private QueryRunner runner; private ConnectionUtils connectionUtils; public void setRunner(QueryRunner runner) { this.runner = runner; } public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } @Override public List<Account> findAccountAll() { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class)); }catch (Exception e){ throw new RuntimeException(e); } } @Override public Account findAccountById(Integer accountId) { try{ return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ?",new BeanHandler<Account>(Account.class),accountId); }catch (Exception e){ throw new RuntimeException(e); } } @Override public void saveAccount(Account account) { try{ runner.update(connectionUtils.getThreadConnection(),"insert into account(name,money)value(?,?)",account.getName(),account.getMoney()); }catch (Exception e){ throw new RuntimeException(e); } } @Override public void updateAccount(Account account) { try{ runner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); }catch (Exception e){ throw new RuntimeException(e); } } @Override public void deleteAccount(Integer accountId) { try{ runner.update(connectionUtils.getThreadConnection(),"delete from account where id=?",accountId); }catch (Exception e){ throw new RuntimeException(e); } } @Override public Account findAccountByName(String accountName) { try{ List<Account> accounts = runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanListHandler<Account>(Account.class),accountName); if (accounts == null || accounts.size() == 0){ return null; } if (accounts.size()>1){ throw new RuntimeException("结果集不唯一,数据有问题"); } return accounts.get(0); }catch (Exception e){ throw new RuntimeException(e); } } }
7.ConnectionUtils连接:
package com.itheima.utils; import javax.sql.DataSource; import java.sql.Connection; public class ConnectionUtils { private ThreadLocal<Connection> ts = new ThreadLocal<Connection>(); private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public Connection getThreadConnection(){ try { //1.先从ThreadLocal上获取 Connection conn = ts.get(); //2.判断是否当前线程上有连接 if (conn == null) { //3.从数据源中获取一个连接,并且存入ThreadLocal中(也就是绑定线程) conn = dataSource.getConnection(); /*conn.setAutoCommit(false);*/ } //4.返回当前线程上的连接 return conn; }catch (Exception e){ throw new RuntimeException(e); } } /*连接之后不用了,就进行线程的解绑,线程还回池中*/ public void removeConnection(){ ts.remove(); } }
8.事务管理ransactionManager:
package com.itheima.utils; public class TransactionManager { private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } //开启事务 public void beginTransaction(){ /*之前的事务在这里:开启aop之后就不用自己写事务配置*/ /*try{ connectionUtils.getThreadConnection().setAutoCommit(false); }catch (Exception e){ e.printStackTrace();//在命令行打印异常信息在程序中出错的位置及原因 }*/ } //提交事务 public void commit(){ } //回滚事务 public void rollback(){ } //释放连接事务 public void release(){ } }
9.bean.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" 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"> <!--配置IAccountService的实例对象:入口通常都是这个--> <bean id="accountService" class="com.itheima.service.ipm.AccountServiceImpl"> <!--注入的实例来使用:就要使用property来声明--> <property name="accountDao" ref="accountDao"></property> <property name="txManager" ref="txManager"></property> </bean> <!--配置accountDao的实例对象:方便注入 --> <bean id="accountDao" class="com.itheima.dao.ipm.AccountDaoImpl"> <!--注入的实例来使用:就要使用property来声明--> <property name="connectionUtils" ref="connectionUtils"></property> <property name="runner" ref="runner"></property> </bean> <bean id="connectionUtils" class="com.itheima.utils.ConnectionUtils"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean> <!--配置数据源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/eesy"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean> <bean id="txManager" class="com.itheima.utils.TransactionManager"> <property name="connectionUtils" ref="connectionUtils"></property> </bean> <!--第三天末尾练习:重点--> <aop:config> <aop:pointcut id="pt1" expression="execution(* com.itheima.service.ipm.*.*(..))"/> <aop:aspect id="txAdvice" ref="txManager"> <aop:before method="beginTransaction" pointcut-ref="pt1"></aop:before> <aop:after-returning method="commit" pointcut-ref="pt1"></aop:after-returning> <aop:after-throwing method="rollback" pointcut-ref="pt1"></aop:after-throwing> <aop:after method="release" pointcut-ref="pt1"></aop:after> </aop:aspect> </aop:config> </beans>
10. TestCode
package com.itheima; import com.itheima.service.IAccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) /*说明位置*/ @ContextConfiguration(locations ="classpath:bean.xml") /*pom.xml加上spring-test依赖*/ public class TestCode { @Autowired private IAccountService as; @Test public void testTransfer(){ as.transfer("test","zhou",100f); } }
11.pom文件
<!--spring环境--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--sql语句操作--> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.4</version> </dependency> <!-- mysql配置--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <!-- c3p0--> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- aop的--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>