2014-07-16 Java Web的学习(13)-----DBUtil&基于DBUtil的事务处理(动态代理AOP)

一、数据库元数据信息
   具体来说指的是数据库,表等定义信息(DDL信息).
   1.数据库的元数据:
     DatabaseMetaData metaData = Connection.getMetaData();
     这个对象表示该Connection对象所连接的数据库的元数据,元数据包括关于数据库的表、受支持的SQL 语法、存储过程、此连接功能等等的信息.至于对象方法,就自己查看JDK API.其中里面大部分都是Get方法.
   2. ParameterMetaData metaData=stmt.getParameterMetaData();
     一个 ParameterMetaData 对象,它包含有关此 PreparedStatement 对象的每个参数标记的编号、类型和属性的信息.
   3. ResultSetMetaData rsmd = rs.getMetaData();
     可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
 
二、编写自己的JDBC框架
    数据库元数据有什么作用?就是让我们用来简单封装JDBC.在JDBC中一系列的操作中,都有很多相同的步骤,不同只是SQL语句和参数.而DQL语句可能存在结果.而数据库的操作语言都是执行stmt.executeUpdate.
而查询语言就要稍微复杂一点.分为返回结果ResultSet res无非封装Bean或者是List<Bean>中.封装时使用ResultSetHandle接口处理器.而不同结果集实现处理器是不同.BeanHandle实现ResultSetHandle接口用来处理封装一条记录.BeanListHandle实现ResultHandle用来封装多条记录.这就是所谓的策略模式.最后上代码:
     /**
      * 封装JDBC中的update,insert,delete方法.
      * @param sql
      * @param params
      */
     public void update(String sql ,Object...params){
          try {
              Connection conn = dataSource .getConnection();
              PreparedStatement stmt = conn.prepareStatement( sql );
              ParameterMetaData metaData = stmt.getParameterMetaData();
              int paramCount=metaData.getParameterCount();
              if (paramCount>0){
                   if (params== null || params. length <=0){
                        throw new IllegalArgumentException( "参数不匹配." );
                   }
                   if (paramCount!=params. length ){
                        throw new IllegalArgumentException( "参数不匹配." );
                   }
                   for ( int i=0;i<paramCount;i++){
                        //设置参数
                        stmt.setObject(i+1, params[i]);
                   }
              }
              stmt.executeUpdate();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
     }
    /**
      * 封装JDBC中的Query方法
      */
     public Object query(String sql,ResultSetHandler rsh,Object...params){
          try {
              Connection conn = dataSource .getConnection();
              PreparedStatement stmt = conn.prepareStatement(sql);
              ParameterMetaData metaData = stmt.getParameterMetaData();
              int paramCount=metaData.getParameterCount();
              if (paramCount>0){
                   if (params== null || params. length <=0){
                        throw new IllegalArgumentException( "参数不匹配." );
                   }
                   if (paramCount!=params. length ){
                        throw new IllegalArgumentException( "参数不匹配." );
                   }
                   for ( int i=0;i<paramCount;i++){
                        stmt.setObject(i+1, params[i]);
                   }
              }
              ResultSet rs=stmt.executeQuery();
              //怎么讲结果集封装到JavaBean中.
              Object result = rsh.handle(rs);
              return result;
          } catch (SQLException e) {
              throw new RuntimeException(e);
          }
     }
     public interface ResultSetHandler {
          Object handle(ResultSet rs);
     }
     两种处理器:
     f70fce368cbba86df95f1662a7effc9217ec78a4a1e6c82b1a4b428d0f7322d0
无标题1
    PS: 列名和字段必须要求一致.目前还做不到自定义字段名和字段名的映射关系.
    策略模式:图示 场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是亮哥给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜
06a4b9d7-a392-3a49-a1ff-6b1c2342acdb
 
 
三、开源框架DBUtil(简单封装JDBC)
   了解DBUtil框架,主要熟悉它的不同处理器Handle.具体就不介绍啦,自己查看文档吧.
     ArrayHandler
     ArrayListHandler
     *BeanHandler
     *BeanListHandler
     ColumnListHandler
     KeyedHandler
     MapHandler
     MapListHandler
     * ScalarHandler
    QueryRunner qr = new QueryRunner(数据源);
    QueryRunner qr = new QueryRunner(); //与事务控制相关.
 
四、BDUtil在实际开发中事务的控制(已转账为案例)

1.Dao层对于事物的控制(一般不使用,只负责增删改查,不关注业务逻辑)
  
     /**
      * 在DButils中使用控制事务,使用同一Connection对象连接.
      */
     private QueryRunner qr = new QueryRunner();
     @Override
     public void transfer(String sourceName, String destName, float money) {
          Connection conn = null ;
          try {
              conn = DBCPUtil. getConnection ();
              conn .setAutoCommit( false );
              qr .update( conn , "update account set money=money-? where name=?" , new Object[] {
                        money, sourceName });
              int a = 1/0;   //抛出异常
              qr .update( conn , "update account set money=money+? where name=?" , new Object[] {
                        money, destName });
              conn .commit();
          } catch (Exception e) {
              throw new RuntimeException(e);
          } finally {
              if ( conn != null ){
                   try {
                        /*放回数据库连接池*/
                        conn .close();
                   } catch (SQLException e) {
                        throw new RuntimeException(e);
                   }
                   conn = null ;
              }
          }
     }
2.Service层对于事物的处理(Service中抛出SQLException,如果Dao换成Hibernate实现的话.就会出现问题)
  Dao层的设计Connection对象注入进来:
  70acc6b8c1e6a4e14edc1a3a1cf2b1e8
   public void transfer(String sourceName, String destName, float money){
          Connection conn = null ;
          try {
              conn = DBCPUtil. getConnection ();
              conn.setAutoCommit( false );
              AccountDao dao = new AccountDaoImpl(conn);
              Account source = dao.findAccountByName(sourceName);
              Account dest = dao.findAccountByName(destName);
              source.setMoney(source.getMoney()-money);
              dest.setMoney(dest.getMoney()+money);
              dao.updateAccount(source);
              int a =1/0;
              dao.updateAccount(dest);
              conn.commit();
          } catch (SQLException e) {
              throw new RuntimeException(e);
          } finally {
              if (conn!= null ){
                   try {
                        conn.close();
                   } catch (SQLException e) {
                        e.printStackTrace();
                   }
              }
          }
     }
3.通过ThreadLocal解决上面问题的事务处理
   ThreadLocal,直译为“线程本地”或“本地线程”,如果你真的这么认为,那就错了!其实,它就是一个容器,用于存放线程的局部变量,我认为应该叫做 ThreadLocalVariable(线程局部变量)才对.

//模拟ThreadLocal

public class ThreadLocal{

private Map<Runnable,Object> map = new HashMap<Runnable,Object>();

public void set(Object obj){

map.put(Thread.currentThread(),obj);

}

pulbic void remove(){

map.remove(Thread.currentThread());

}

public Object get(){

return map.get(Thread.currentThread());

}

}

以线程为Key,将某个变量实例存放在ThreadLocal中.ThreadLocal中实际上就是一个Map集合.所以称作线程局部变量.

    编写一个控制事务的类:TransactionManager
    9084191c9d106ec0fb9bb8483fe7e381
无标题
   public void transfer(String sourceName, String destName, float money) {
         TransactionManager. startTransaction ();
          AccountDao dao = new AccountDaoImpl(TransactionManager. getConnection ());
          Account source = dao.findAccountByName(sourceName);
          Account dest = dao.findAccountByName(destName);
          source.setMoney(source.getMoney() - money);
          dest.setMoney(dest.getMoney() + money);
          dao.updateAccount(source);
          int a = 1 / 0;
          dao.updateAccount(dest);
          TransactionManager. commitTransaction ();
          TransactionManager. release ();
     }
 
4.通过动态代理更加细粒度的控制事务
  94ca1d4eab54e0c5eba2423b5d3ca2a0
  
BeanFactory.java
package com.itheima.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.ithiema.service.AccountService;
import com.ithiema.service.impl.AccountServiceImpl;
public class BeanFactory {
     /**
     * 解耦.拦截
     * @return AccountService
     */
     public static AccountService getAccountServiceImpl(){
          final AccountService service = new AccountServiceImpl();
          AccountService proxy = (AccountService) Proxy.newProxyInstance(AccountService.class.getClassLoader()
                    , service.getClass().getInterfaces(), new InvocationHandler() {
                         @Override
                         public Object invoke(Object proxy, Method method, Object[] args)
                                   throws Throwable {
                              if("transfer".equals(method.getName())){
                                   try {
                                        TransactionManager.startTransaction();
                                        Object objValue = method.invoke(service, args);
                                        TransactionManager.commitTransaction();
                                        return objValue;
                                   } catch (Exception e) {
                                        TransactionManager.rollBackTransaction();
                                        throw new RuntimeException(e);
                                   } finally{
                                        TransactionManager.release();
                                   }
                              }else{
                                   return method.invoke(service, args);
                              }
                         }
                    });
          return proxy;
     }
}

你可能感兴趣的:(2014-07-16 Java Web的学习(13)-----DBUtil&基于DBUtil的事务处理(动态代理AOP))