一、目录结构(AOP原理)
二、代码
1、AccountDao
1 package cn.bijian.dao; 2 3 import cn.bijian.model.Account; 4 5 import java.util.List; 6 7 public interface AccountDao { 8 void saveAccount(Account account); 9 10 void deleteAccount(Integer id); 11 12 void updateAccount(Account account); 13 14 Account findById(Integer id); 15 16 List<Account> findAll(); 17 18 Account findByName(String name); 19 }
2、AccountDaoImpl
1 package cn.bijian.dao.impl; 2 3 import cn.bijian.dao.AccountDao; 4 import cn.bijian.model.Account; 5 import cn.bijian.utils.ConnectionUtils; 6 import org.apache.commons.dbutils.QueryRunner; 7 import org.apache.commons.dbutils.handlers.BeanHandler; 8 import org.apache.commons.dbutils.handlers.BeanListHandler; 9 10 import java.util.List; 11 12 public class AccountDaoImpl implements AccountDao { 13 private QueryRunner runner; 14 private ConnectionUtils connectionUtils; 15 16 public void setRunner(QueryRunner runner) { 17 this.runner = runner; 18 } 19 20 public void setConnectionUtils(ConnectionUtils connectionUtils) { 21 this.connectionUtils = connectionUtils; 22 } 23 24 @Override 25 public void saveAccount(Account account) { 26 try{ 27 runner.update(connectionUtils.getThreadConnection(),"insert into account(name,money) values (?,?)",account.getName(),account.getMoney()); 28 }catch (Exception e){ 29 throw new RuntimeException(e); 30 } 31 } 32 33 @Override 34 public void deleteAccount(Integer id) { 35 try{ 36 runner.update(connectionUtils.getThreadConnection(),"delete from account where id = ?",id); 37 }catch (Exception e){ 38 throw new RuntimeException(e); 39 } 40 } 41 42 @Override 43 public void updateAccount(Account account) { 44 try{ 45 runner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId()); 46 }catch (Exception e){ 47 throw new RuntimeException(e); 48 } 49 } 50 51 @Override 52 public Account findById(Integer id) { 53 try{ 54 return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ?",new BeanHandler<Account>(Account.class),id); 55 }catch (Exception e){ 56 throw new RuntimeException(e); 57 } 58 } 59 60 @Override 61 public List<Account> findAll() { 62 try{ 63 return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class)); 64 }catch (Exception e){ 65 throw new RuntimeException(e); 66 } 67 } 68 69 @Override 70 public Account findByName(String name) { 71 try{ 72 List<Account> accounts = runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanListHandler<Account>(Account.class),name); 73 if (accounts == null || accounts.size()==0){ 74 return null; 75 } 76 if (accounts.size()>1){ 77 throw new RuntimeException("结果集不唯一,数据有问题!"); 78 } 79 return accounts.get(0); 80 }catch (Exception e){ 81 throw new RuntimeException(e); 82 } 83 } 84 }
3、BeanFactory
1 package cn.bijian.factory; 2 3 4 5 import cn.bijian.service.AccountService; 6 import cn.bijian.utils.TransactionManager; 7 8 import java.lang.reflect.InvocationHandler; 9 import java.lang.reflect.Method; 10 import java.lang.reflect.Proxy; 11 12 /* 13 用于创建Service的代理对象的工厂 14 */ 15 public class BeanFactory { 16 private AccountService accountService; 17 private TransactionManager transactionManager; 18 19 public final void setAccountService(AccountService accountService) { 20 this.accountService = accountService; 21 } 22 23 public void setTransactionManager(TransactionManager transactionManager) { 24 this.transactionManager = transactionManager; 25 } 26 27 public AccountService getAccountService(){ 28 AccountService proxyAccountService = (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { 29 @Override 30 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 31 Object rtValue = null; 32 try{ 33 transactionManager.beginTransaction(); 34 //执行操作 35 rtValue = method.invoke(accountService,args); 36 transactionManager.commit(); 37 }catch (Exception e){ 38 transactionManager.rollback(); 39 e.printStackTrace(); 40 }finally { 41 transactionManager.release(); 42 } 43 return rtValue; 44 } 45 }); 46 return proxyAccountService; 47 }
4、Account
1 package cn.bijian.model; 2 3 public class Account { 4 private Integer id; 5 private String name; 6 private Double money; 7 8 public Integer getId() { 9 return id; 10 } 11 12 public void setId(Integer id) { 13 this.id = id; 14 } 15 16 public String getName() { 17 return name; 18 } 19 20 public void setName(String name) { 21 this.name = name; 22 } 23 24 public Double getMoney() { 25 return money; 26 } 27 28 public void setMoney(Double money) { 29 this.money = money; 30 } 31 32 @Override 33 public String toString() { 34 return "Account{" + 35 "id=" + id + 36 ", name='" + name + '\'' + 37 ", money=" + money + 38 '}'; 39 } 40 }
5、AccountService
1 package cn.bijian.service; 2 3 import cn.bijian.model.Account; 4 5 import java.util.List; 6 7 public interface AccountService { 8 void saveAccount(Account account); 9 10 void deleteAccount(Integer id); 11 12 void updateAccount(Account account); 13 14 Account findById(Integer id); 15 16 List<Account> findAll(); 17 18 void transfer(String sourceName,String targetName,Double money); 19 }
6、AccountServiceImpl
1 package cn.bijian.service.impl; 2 3 import cn.bijian.dao.AccountDao; 4 import cn.bijian.model.Account; 5 import cn.bijian.service.AccountService; 6 7 import java.util.List; 8 9 public class AccountServiceImpl implements AccountService { 10 private AccountDao accountDao; 11 12 public void setAccountDao(AccountDao accountDao) { 13 this.accountDao = accountDao; 14 } 15 16 @Override 17 public List<Account> findAll() { 18 return accountDao.findAll(); 19 } 20 21 @Override 22 public Account findById(Integer id) { 23 return accountDao.findById(id); 24 } 25 26 @Override 27 public void saveAccount(Account account) { 28 accountDao.saveAccount(account); 29 } 30 31 @Override 32 public void deleteAccount(Integer id) { 33 accountDao.deleteAccount(id); 34 } 35 36 @Override 37 public void updateAccount(Account account) { 38 accountDao.updateAccount(account); 39 } 40 41 @Override 42 public void transfer(String sourceName, String targetName, Double money) { 43 System.out.println("transfer开始执行!"); 44 Account source = accountDao.findByName(sourceName); 45 Account target = accountDao.findByName(targetName); 46 source.setMoney(source.getMoney() - money); 47 target.setMoney(target.getMoney() + money); 48 accountDao.updateAccount(source); 49 // int i = 1/0; 50 accountDao.updateAccount(target); 51 } 52 }
7、AccountDaoImpl_OLD
1 package cn.bijian.service.impl; 2 3 import cn.bijian.dao.AccountDao; 4 import cn.bijian.model.Account; 5 import cn.bijian.service.AccountService; 6 import cn.bijian.utils.TransactionManager; 7 8 import java.util.List; 9 10 public class AccountServiceImpl_OLD implements AccountService { 11 private AccountDao accountDao; 12 private TransactionManager transactionManager; 13 14 public void setAccountDao(AccountDao accountDao) { 15 this.accountDao = accountDao; 16 } 17 18 public void setTransactionManager(TransactionManager transactionManager) { 19 this.transactionManager = transactionManager; 20 } 21 22 @Override 23 public List<Account> findAll() { 24 List<Account> accounts = null; 25 try{ 26 transactionManager.beginTransaction(); 27 accounts = accountDao.findAll(); 28 transactionManager.commit(); 29 return accounts; 30 }catch (Exception e){ 31 transactionManager.rollback(); 32 e.printStackTrace(); 33 }finally { 34 transactionManager.release(); 35 } 36 return null; 37 } 38 39 @Override 40 public Account findById(Integer id) { 41 try{ 42 transactionManager.beginTransaction(); 43 Account account = accountDao.findById(id); 44 transactionManager.commit(); 45 return account; 46 }catch (Exception e){ 47 transactionManager.rollback(); 48 e.printStackTrace(); 49 }finally { 50 transactionManager.release(); 51 } 52 return null; 53 } 54 55 @Override 56 public void saveAccount(Account account) { 57 try{ 58 transactionManager.beginTransaction(); 59 accountDao.saveAccount(account); 60 transactionManager.commit(); 61 }catch (Exception e){ 62 transactionManager.rollback(); 63 e.printStackTrace(); 64 }finally { 65 transactionManager.release(); 66 } 67 } 68 69 @Override 70 public void deleteAccount(Integer id) { 71 try{ 72 transactionManager.beginTransaction(); 73 accountDao.deleteAccount(id); 74 transactionManager.commit(); 75 }catch (Exception e){ 76 transactionManager.rollback(); 77 e.printStackTrace(); 78 }finally { 79 transactionManager.release(); 80 } 81 } 82 83 @Override 84 public void updateAccount(Account account) { 85 try{ 86 transactionManager.beginTransaction(); 87 accountDao.updateAccount(account); 88 transactionManager.commit(); 89 }catch (Exception e){ 90 transactionManager.rollback(); 91 e.printStackTrace(); 92 }finally { 93 transactionManager.release(); 94 } 95 } 96 97 @Override 98 public void transfer(String sourceName, String targetName, Double money) { 99 try{ 100 transactionManager.beginTransaction(); 101 Account source = accountDao.findByName(sourceName); 102 Account target = accountDao.findByName(targetName); 103 source.setMoney(source.getMoney() - money); 104 target.setMoney(target.getMoney() + money); 105 accountDao.updateAccount(source); 106 int i = 1/0; 107 accountDao.updateAccount(target); 108 transactionManager.commit(); 109 }catch (Exception e){ 110 transactionManager.rollback(); 111 e.printStackTrace(); 112 }finally { 113 transactionManager.release(); 114 } 115 } 116 }
8、ConnectionUtils
1 package cn.bijian.utils; 2 3 import javax.sql.DataSource; 4 import java.sql.Connection; 5 6 public class ConnectionUtils { 7 private ThreadLocal<Connection> t = new ThreadLocal<Connection>(); 8 private DataSource dataSource; 9 10 public void setDataSource(DataSource dataSource) { 11 this.dataSource = dataSource; 12 } 13 14 public void setT(ThreadLocal<Connection> t) { 15 this.t = t; 16 } 17 18 //获取当前线程连接 19 public Connection getThreadConnection(){ 20 try{ 21 Connection conn = t.get(); 22 if (conn == null){ 23 conn = dataSource.getConnection(); 24 t.set(conn); 25 } 26 return conn; 27 }catch (Exception e){ 28 throw new RuntimeException(e); 29 } 30 } 31 //把连接和线程解绑 32 public void removeConnection(){ 33 t.remove(); 34 } 35 }
9、TransactionManager
1 package cn.bijian.utils; 2 3 public class TransactionManager { 4 private ConnectionUtils connectionUtils; 5 6 public void setConnectionUtils(ConnectionUtils connectionUtils) { 7 this.connectionUtils = connectionUtils; 8 } 9 10 public void beginTransaction(){ 11 try{ 12 connectionUtils.getThreadConnection().setAutoCommit(false); 13 }catch (Exception e){ 14 e.printStackTrace(); 15 } 16 } 17 18 public void commit(){ 19 try{ 20 connectionUtils.getThreadConnection().commit(); 21 }catch (Exception e){ 22 e.printStackTrace(); 23 } 24 } 25 26 public void rollback(){ 27 try{ 28 connectionUtils.getThreadConnection().rollback(); 29 }catch (Exception e){ 30 e.printStackTrace(); 31 } 32 } 33 34 public void release(){ 35 try{ 36 connectionUtils.getThreadConnection().close(); //只是还回池中,并没有关闭连接 37 connectionUtils.removeConnection(); 38 }catch (Exception e){ 39 e.printStackTrace(); 40 } 41 } 42 }
10、bean.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <bean id="accountDao" class="cn.bijian.dao.impl.AccountDaoImpl"> 8 <property name="runner" ref="runner"></property> 9 <property name="connectionUtils" ref="connectionUtils"></property> 10 </bean> 11 12 13 <!-- AccountServiceImpl_OLD --> 14 <!-- <bean id="accountService" class="cn.bijian.service.impl.AccountServiceImpl_OLD">--> 15 <!-- <property name="accountDao" ref="accountDao"></property>--> 16 <!-- <property name="transactionManager" ref="transactionManager"></property>--> 17 <!-- </bean>--> 18 19 20 <!-- AccountServiceImpl --> 21 <bean id="accountService" class="cn.bijian.service.impl.AccountServiceImpl"> 22 <property name="accountDao" ref="accountDao"></property> 23 </bean> 24 <!--配置代理的service--> 25 <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean> 26 <!--配置beanFactory--> 27 <bean id="beanFactory" class="cn.bijian.factory.BeanFactory"> 28 <property name="accountService" ref="accountService"></property> 29 <property name="transactionManager" ref="transactionManager"></property> 30 </bean> 31 32 <!--配置QueryRunner--> 33 <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean> 34 35 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 36 <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/> 37 <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?serverTimezone=UTC"/> 38 <property name="user" value="root"/> 39 <property name="password" value="123456"/> 40 </bean> 41 42 <!-- 配置Connection的工具类 ConnectionUtils --> 43 <bean id="connectionUtils" class="cn.bijian.utils.ConnectionUtils"> 44 <!-- 注入数据源--> 45 <property name="dataSource" ref="dataSource"></property> 46 </bean> 47 48 <!-- 配置事务管理器--> 49 <bean id="transactionManager" class="cn.bijian.utils.TransactionManager"> 50 <property name="connectionUtils" ref="connectionUtils"></property> 51 </bean> 52 53 </beans>
11、AccountServiceTest
1 package cn.bijian.test; 2 3 import cn.bijian.service.AccountService; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.test.context.ContextConfiguration; 8 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 10 @RunWith(SpringJUnit4ClassRunner.class) 11 @ContextConfiguration(locations = "classpath:bean.xml") 12 public class AccountServiceTest { 13 @Autowired 14 private AccountService accountService; 15 16 @Test 17 public void testTransfer(){ 18 accountService.transfer("aaa","bbb",100d); 19 } 20 }
12、AccountServiceTest2
1 package cn.bijian.test; 2 3 import cn.bijian.service.AccountService; 4 import org.junit.Test; 5 import org.junit.runner.RunWith; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Qualifier; 8 import org.springframework.test.context.ContextConfiguration; 9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 10 11 @RunWith(SpringJUnit4ClassRunner.class) 12 @ContextConfiguration(locations = "classpath:bean.xml") 13 public class AccountServiceTest2 { 14 @Autowired 15 @Qualifier("proxyAccountService") 16 private AccountService accountService; 17 18 @Test 19 public void testTransfer(){ 20 accountService.transfer("aaa","bbb",100d); 21 } 22 }