理解Mybatis的設計思想。動手實現迷你Mybatis
阿新 • • 發佈:2019-01-28
參考:https://www.jianshu.com/p/73ee8caddc68?open_source=weibo_search
Mybatis的架構圖:
我們要實現的迷你Mybatis的整體框架思路:
執行器MyExecutor:
public interface MyExecutor { public <T> T query(String statement); }
這裡為了方便,直接執行已經處理好的SQL語句
對執行器的實現MyBaseExecutor:
public class MyBaseExecutor implements MyExecutor{ private static finalString URL = "jdbc:mysql://localhost:3306/store"; private static final String USER = "root"; private static final String PASS = ""; @Override public <T> T query(String statement) { Connection connection = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null;try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection(URL,USER,PASS); String sql = statement; preparedStatement = connection.prepareStatement(sql); resultSet = preparedStatement.executeQuery(); Class<?> clazz = User.class; Object instance = null;if (resultSet.next()){ instance = clazz.newInstance(); //使用反射進行填充屬性 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields){ field.setAccessible(true); field.set(instance,resultSet.getObject(field.getName())); } } return (T) instance; }catch (Exception e){ e.printStackTrace(); return null; } } }
注意到,這裡程式碼我寫死了,所以寫的並不好,現在只是理解Mybatis的設計思想
定義mapper介面和mapper檔案(這裡為了簡單,使用類來代替)
public interface UserMapper { public User findUserById(String id); public void insertUser(User user); }
public class UserMapperXML{ //相當於xml的名稱空間 public static final String namespace = "mybatis.UserMapper"; //相當於select標籤 private static Map<String,String> mathodSqlMap = new HashMap<>(); static{ mathodSqlMap.put("findUserById","select * from user where uid = %s"); } public static String getMethodSql(String method){ return mathodSqlMap.get(method); } }
定義SqlSession,sqlSession可以查詢結果集,也可以返回mapper代理
public interface MySqlSession { <T> T selectOne(String param); <T> T getMapper(Class<T> clazz); }
實現SqlSession
public class MyDefaultSqlSession implements MySqlSession{ private MyExecutor myExecutor = new MyBaseExecutor(); @Override public <T> T selectOne(String param) { return myExecutor.query(param); } @Override public <T> T getMapper(Class<T> clazz) { return (T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},new MyMapperProxy(this)); } }
可以看到,sqlSession執行sql語句是用執行器Executor執行的。
獲取mapper程式碼,出現了JDK動態代理,接下來我們需要實現mapper
public class MyMapperProxy implements InvocationHandler{ private MySqlSession sqlSession; public MyMapperProxy(){} public MyMapperProxy(MySqlSession sqlSession){ this.sqlSession = sqlSession; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String mapperClass = method.getDeclaringClass().getName(); System.out.println("mapperClass"+mapperClass); if (UserMapperXML.namespace.equals(mapperClass)){ String methodName = method.getName(); String originsql = UserMapperXML.getMethodSql(methodName); String formatSql = String.format(originsql,String.valueOf(args[0])); return sqlSession.selectOne(formatSql); } return null; } }
首先根據名稱空間,找出與mapper介面方法名相同的sql語句,然後交給sqlSession來執行。
就這樣,一個迷你版的Mybatis就實現了。測試一下
public class Test { public static void main(String[] args) { MySqlSession sqlSession = new MyDefaultSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findUserById(1+""); System.out.println(user); } }
輸出為
成功了