第一:
package com.itheima.utils; import java.sql.Connection; import java.sql.SQLException; /** * 处理事务 的专门类 * 也就是将这个事务处理的方面分离出来,形成一个独立的类 * * 就是后面要说的方面代码 * @author wangli * */ public class TransactionManager { private static ThreadLocal<Connection> tL = new ThreadLocal<Connection>();//线程局部变量,用于放入Connection /** * 得到连接 * @return */ public static Connection getConnection(){ Connection con = tL.get();//从线程局部变量取出一个Connection ----第一次没有值 if(con==null){ //-第一次没有值 con = C3P0Util.getConneciton();//从连接池中取出一个连接 tL.set(con);//放入一个连接到线程局部变量中 } return con; } /** * 开启事务 * @throws Exception */ public static void startTransaction() throws Exception{ Connection con = getConnection(); con.setAutoCommit(false); } /** * 提交事务 * @throws Exception */ public static void commit() throws Exception{ Connection con = getConnection(); con.commit(); } /** * 回滚事务 * @throws Exception */ public static void rollback() throws Exception{ Connection con = getConnection(); con.rollback(); } }
第二:
package com.itheima.utils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0Util { private static DataSource ds =new ComboPooledDataSource(); /** * 用于得到数据源 * @return */ public static DataSource getDataSource(){ return ds; } /** * 用于从池中获取连接 * @return */ public static synchronized Connection getConneciton(){ try { return ds.getConnection(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } //关闭资源 public static void release(ResultSet rs,Statement st,Connection con ){ try { if(rs!=null){ rs.close(); rs=null;//目的是让回收器立即进行垃圾回收 } } catch (SQLException e) { e.printStackTrace(); } try { if(st!=null){ st.close(); st=null; } } catch (SQLException e) { e.printStackTrace(); } try { if(con!=null){ con.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
第三:
package com.itheima.utils; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.itheima.service.AccountService; import com.itheima.service.impl.AccountServiceImpl; public class BeanFactory { /** * 用于生成一个功能强磊的AccountService对象 * @return */ public static AccountService getBean(){ final AccountService as = new AccountServiceImpl(); //动态代理 AccountService asProxy = (AccountService)Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(),new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("transfor".equals(method.getName())){ try { //横向加入代码 TransactionManager.startTransaction();//开事务 前置通知 //保证原有文法能执行 Object obj= method.invoke(as, args); TransactionManager.commit();//后置通知 //环绕通知:(前置通知 +后置通知) return obj; } catch (Exception e) { e.printStackTrace(); try { TransactionManager.rollback();//异常通知 } catch (Exception e1) { e1.printStackTrace(); } } //finally中加入的代码:称为最终通知 } return null; } }); return asProxy; } }
第四:service
package com.itheima.service.impl; import com.itheima.dao.AccountDao; import com.itheima.dao.impl.AccountDaoImpl; import com.itheima.domain.Account; import com.itheima.service.AccountService; import com.itheima.utils.TransactionManager; /** AOP:Aspect Object Program (面向切面编程 面向方面编程) 名词介绍: 就是将事物的某个方面功能代码抽取出去集中做实现,在需要系统需要用的时候,就将方面代码织入(加入)到系统中,从而实现功能扩展 它打破了原有纵向继承体系结构(代码复用),可以在关键时候横向织入方面代码(代码复用) 实现原理: 动态代理模式 适合场景:事务控制 ,日志控制,权限管理,积分功能 * @author wangli * */ public class AccountServiceImpl implements AccountService { @Override public void transfor(String sourceAcc, String targetAcc, float money) { AccountDao dao = new AccountDaoImpl(); //1.根据源账户名,得到一个账户对象 Account srcAcc = dao.getAccountByName(sourceAcc);//非常关键,目的是确保dao中用的是同一个Connection对象 //2.目标对象名,得到一 个目标账户 Account tarAcc = dao.getAccountByName(targetAcc); //3.更新余额 srcAcc.setMoney(srcAcc.getMoney()-money);//源账户减 tarAcc.setMoney(tarAcc.getMoney()+money);//目标账户加 //4.写入到表中 dao.updateAccount(srcAcc); int i=1/0; dao.updateAccount(tarAcc); } }
第五dao层
package com.itheima.dao.impl; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import com.itheima.dao.AccountDao; import com.itheima.domain.Account; import com.itheima.utils.TransactionManager; /** * */ public class AccountDaoImpl implements AccountDao { private QueryRunner qr = new QueryRunner(); @Override public Account getAccountByName(String accountName) { try { Account acc = qr.query(TransactionManager.getConnection(),"select * from account where name=?", new BeanHandler<Account>(Account.class),accountName); return acc; } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } @Override public void updateAccount(Account acc) { try { qr.update(TransactionManager.getConnection(),"update account set money=? where name=?", acc.getMoney(),acc.getName()); } catch (SQLException e) { e.printStackTrace(); } } }
第六:测试
package com.itheima.test; import java.util.ArrayList; import java.util.List; import com.itheima.dao.AccountDao; import com.itheima.dao.impl.AccountDaoImpl; import com.itheima.domain.Account; import com.itheima.service.AccountService; import com.itheima.service.impl.AccountServiceImpl; import com.itheima.utils.BeanFactory; public class Client { /** * @param args */ public static void main(String[] args) { /*AccountDao dao = new AccountDaoImpl(); dao.transfor("aaa", "bbb",100);*/ //2. /*AccountService as = new AccountServiceImpl(); as.transfor("aaa", "bbb",100);*/ //3 AccountService as = BeanFactory.getBean();通过工厂创建对象,工厂里植入代理 as.transfor("aaa", "bbb",100); } }