在Mybatis3的源碼解析系列中,我們對其核心功能有了一定的了解,下面我們嘗試簡單寫一下Demo,讓其有簡單的Mybatis的一些核心功能,本篇是基礎功能的搭建
完整的工程已放到GitHub上:https://github.com/lw1243925457/MybatisDemo/tree/master/
本篇文章的代碼對應的Tag是: V1
本篇的目標是完成MapperProxy和運行不帶參數和無自定義返回類型的SQL
測試代碼如下:
public class SelfMybatisTest {@Testpublic void test() {try(SelfSqlSession session = buildSqlSessionFactory()) {PersonMapper personMapper = session.getMapper(PersonMapper.class);personMapper.createTable();personMapper.save();List<Object> personList = personMapper.list();for (Object person: personList) {System.out.println(person.toString());}}}public static SelfSqlSession buildSqlSessionFactory() {String JDBC_DRIVER = "org.h2.Driver";String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";String USER = "sa";String PASS = "";HikariConfig config = new HikariConfig();config.setJdbcUrl(DB_URL);config.setUsername(USER);config.setPassword(PASS);config.setDriverClassName(JDBC_DRIVER);config.addDataSourceProperty("cachePrepStmts", "true");config.addDataSourceProperty("prepStmtCacheSize", "250");config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");DataSource dataSource = new HikariDataSource(config);SelfConfiguration configuration = new SelfConfiguration(dataSource);
// configuration.getTypeHandlerRegistry().register(String[].class, JdbcType.VARCHAR, StringArrayTypeHandler.class);configuration.addMapper(PersonMapper.class);return new SelfSqlSession(configuration);}
}
編寫實現下列功能的程序段?如上所示,我們集成其他DataSource,這里使用HikariCP,然后初始化Mapper,生成表、插入、查詢
最終的結果如下:
初始化我們的PersonMapper,最后輸出查詢的結果
add sql source: mapper.mapper.PersonMapper.list
add sql source: mapper.mapper.PersonMapper.save
add sql source: mapper.mapper.PersonMapper.createTableexecutor
executor
executor[1, 1]
基本達到了要求,下面開始講解核心代碼:
我們的思路目前是:
SelfConfiguration 相關的代碼
public class SelfConfiguration {private final DataSource dataSource;private final Map<String, SqlSource> sqlCache = new HashMap<>();public SelfConfiguration(DataSource dataSource) {this.dataSource = dataSource;}/*** Mapper添加* 保存接口方法的SQL類型和方法* 方法路徑作為唯一的id* @param mapperClass mapper*/public void addMapper(Class<?> mapperClass) {final String classPath = mapperClass.getPackageName();final String className = mapperClass.getName();for (Method method: mapperClass.getMethods()) {final String id = StringUtils.joinWith("." ,classPath, className, method.getName());for (Annotation annotation: method.getAnnotations()) {if (annotation instanceof Select) {addSqlSource(id, ((Select) annotation).value(), SqlType.SELECT);continue;}if (annotation instanceof Insert) {addSqlSource(id, ((Insert) annotation).value(), SqlType.INSERT);}}}}private void addSqlSource(final String id, final String sql, final SqlType selectType) {System.out.println("add sql source: " + id);final SqlSource sqlSource = SqlSource.builder().type(selectType).sql(sql).build();sqlCache.put(id, sqlSource);}public DataSource getDataSource() {return dataSource;}public SqlSource getSqlSource(final String id) {if (sqlCache.containsKey(id)) {return sqlCache.get(id);}throw new RuntimeException("don't find mapper match: " + id);}
}
importjava,MapperProxy 從 SelfSqlSession 中進行獲取,MapperProxy中調用Executor的方法即可,比較簡單
SelfSqlSession 主要是返回MapperProxy
public class SelfSqlSession implements Closeable {private final SelfConfiguration config;public SelfSqlSession(SelfConfiguration configuration) {this.config = configuration;}@Overridepublic void close() {}public <T> T getMapper(Class<?> mapperClass) {final MapperProxy<T> proxy = new MapperProxy(config);return (T) Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[] {mapperClass}, proxy);}
}
MapperProxy 簡單調用下 Executor
public class MapperProxy<T> implements InvocationHandler {private final SelfConfiguration config;public MapperProxy(final SelfConfiguration configuration) {this.config = configuration;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return Executor.executor(config, proxy, method, args);}
}
主要邏輯如下:
Executor 代碼如下,獲取數據庫連接,StatementHandler執行,ResultHandler處理結果返回
public class Executor {private static final StatementHandler statementHandler = new StatementHandler();private static final ResultHandler resultHandler = new ResultHandler();public static Object executor(SelfConfiguration config, Object proxy, Method method, Object[] args) throws SQLException {System.out.println("executor");try (Connection conn = config.getDataSource().getConnection()) {ResultSet resultSet = statementHandler.prepare(conn, proxy, method, args, config);return resultHandler.parse(resultSet);}}
}
StetementHandler主要是從Config從獲取需要執行的SQL信息
編寫一個?目前比較簡單,根據SQL類型,直接執行即可
public class StatementHandler {public ResultSet prepare(Connection conn, Object proxy, Method method, Object[] args, SelfConfiguration config) throws SQLException {final String classPath = method.getDeclaringClass().getPackageName();final String className = method.getDeclaringClass().getName();final String methodName = method.getName();final String id = StringUtils.joinWith(".", classPath, className, methodName);final SqlSource sqlSource = config.getSqlSource(id);if (sqlSource.getType().equals(SqlType.SELECT)) {return select(conn, sqlSource);}if (sqlSource.getType().equals(SqlType.INSERT)) {return insert(conn, sqlSource);}throw new RuntimeException("don't support this sql type");}private ResultSet insert(Connection conn, SqlSource sqlSource) throws SQLException {final Statement statement = conn.createStatement();statement.execute(sqlSource.getSql());return null;}private ResultSet select(Connection conn, SqlSource sqlSource) throws SQLException {final Statement statement = conn.createStatement();return statement.executeQuery(sqlSource.getSql());}
}
ResultHandler 目前就是循環讀取結果,然后返回
public class ResultHandler {public List<Object> parse(ResultSet res) throws SQLException {if (res == null) {return null;}final List<Object> list = new ArrayList<>(res.getFetchSize());final ResultSetMetaData metaData = res.getMetaData();while (res.next()) {final int count =metaData.getColumnCount();final List<Object> val = new ArrayList<>(count);for (int i=1; i <= count; i++) {final String name = metaData.getColumnName(i);final Object value = res.getObject(name);val.add(value);}list.add(val);}return list;}
}
本篇中搭建了MyBatis Demo的基礎部分,除了結果返回有點不好看,其他有了點日常MyBatis的味道了,結果處理后面也會完善上去
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态