SSM源码分析之Mybatis05-MyBatisV2.0设计过程

Mybatis源码分析05-MyBatisV2.0设计过程

前言

上节我们手写MyBatisV1.0,虽然可以简单的实现了ORM,但是存在的问题很多:

  • 硬编码
  • Executor耦合度过高
  • 提示不友好

针对于以上三点,我们来一次改造

MyBatisV2.0实现

  • 硬编码
    通过ExecutorFactory改造Executor的多种实现
    ExecutorFactory:
public class ExecutorFactory {

   private static final String SIMPLE = "SIMPLE";
   private static final String CACHING = "CACHING";


   public static Executor DEFAULT(GpConfiguration configuration) {
       return get(SIMPLE, configuration);
   }

   public static Executor get(String key, GpConfiguration configuration) {
       if (SIMPLE.equalsIgnoreCase(key)) {
           return new SimpleExecutor(configuration);
       }
       if (CACHING.equalsIgnoreCase(key)) {
           return new CachingExecutor(new SimpleExecutor(configuration));
       }
       throw new RuntimeException("no executor found");
   }


   public enum ExecutorType {
       /**
        * 普通
        */
       SIMPLE,
       /**
        * 缓存
        */
       CACHING
   }

SimpleExecutor :

public class SimpleExecutor implements Executor {
   private GpConfiguration configuration;

   public SimpleExecutor(GpConfiguration configuration) {
       this.configuration = configuration;
   }

   public GpConfiguration getConfiguration() {
       return configuration;
   }

   public void setConfiguration(GpConfiguration configuration) {
       this.configuration = configuration;
   }

   @Override
   public <E> E query(MapperRegistory.MapperData mapperData, Object parameter)
           throws Exception {
       //初始化StatementHandler --> ParameterHandler --> ResultSetHandler
       StatementHandler handler = new StatementHandler(configuration);
       return (E) handler.query(mapperData, parameter);
   }
}

CachingExecutor:

public class CachingExecutor implements Executor {
   private GpConfiguration configuration;

   private SimpleExecutor delegate;

   private Map<String,Object> localCache = new HashMap();

   public CachingExecutor(SimpleExecutor delegate) {
       this.delegate = delegate;
   }

   public CachingExecutor(GpConfiguration configuration) {
       this.configuration = configuration;
   }

   @Override
   public <E> E query(MapperRegistory.MapperData mapperData, Object parameter)
           throws Exception {
       //初始化StatementHandler --> ParameterHandler --> ResultSetHandler
       StatementHandler handler = new StatementHandler(configuration);
       Object result = localCache.get(mapperData.getSql());
       if( null != result){
           System.out.println("缓存命中");
           return (E)result;
       }
       result =  (E) delegate.query(mapperData,parameter);
       localCache.put(mapperData.getSql(),result);
       return (E)result;
   }
}
  • 提示不友好
@Data
public class GpConfiguration {

   private String scanPath;

   private MapperRegistory mapperRegistory = new MapperRegistory();

   public GpConfiguration scanPath(String scanPath) {
       this.scanPath = scanPath;
       return this;
   }

   public void build() throws IOException {
       if (null == scanPath || scanPath.length() < 1) {
           throw new RuntimeException("scan path is required .");
       }
   }

   public static void main(String[] args) throws IOException {
       new GpConfiguration().scanPath("com/xxx/mybatis/gp/config/mappers").build();
   }
}
  • Executor改造

Executor主要的功能是query
V1.0我们将jdbc过程全部耦合在一起,这次我们仿照mybatis源码将其分离

  1. 执行拿到结果 StatementHandler
public <E> E query(MapperRegistory.MapperData mapperData, Object parameter) throws Exception {
        try {
            //JDBC
            Connection conn = getConnection();
            //TODO ParamenterHandler
            PreparedStatement pstmt = conn.prepareStatement(String.format(mapperData.getSql(), Integer.parseInt(String.valueOf(parameter))));
            pstmt.execute();
            //ResultSetHandler
            return (E)resultSetHandler.handle(pstmt.getResultSet(),mapperData.getType());
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }


    public Connection getConnection() throws SQLException {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/gp?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC";
        String username = "root";
        String password = "123456";
        Connection conn = null;
        try {
            //classLoader,加载对应驱动
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
  1. 结果映射 ResultSetHandler
 public <E> E handle(ResultSet rs,Class type) throws SQLException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Object resultObj = new DefaultObjectFactory().create(type);
        if (rs.next()) {
            int i = 0;
            for (Field field : resultObj.getClass().getDeclaredFields()) {
                setValue(resultObj, field, rs ,i);
            }
        }
        return (E) resultObj;
    }

    private void setValue(Object resultObj, Field field, ResultSet rs, int i) throws NoSuchMethodException, SQLException, InvocationTargetException, IllegalAccessException {
        Method setMethod = resultObj.getClass().getMethod("set" + upperCapital(field.getName()), field.getType());
        setMethod.invoke(resultObj, getResult(field,rs));
    }

    private Object getResult(Field field, ResultSet rs) throws SQLException {
        //TODO type handles
        //bean属性的名字必须要和数据库column的名字一样
        Class<?> type = field.getType();
        if(Integer.class == type){
            return rs.getInt(field.getName());
        }
        if(String.class == type){
            return rs.getString(field.getName());
        }
        return rs.getString(field.getName());
    }

    private String upperCapital(String name) {
        String first = name.substring(0, 1);
        String tail = name.substring(1);
        return first.toUpperCase() + tail;
    }

后记

完整代码github地址:MyBatisV2.0(在/gp/文件夹下)

发布了47 篇原创文章 · 获赞 5 · 访问量 1873

猜你喜欢

转载自blog.csdn.net/qq_34361283/article/details/103403960