1. 程式人生 > >理解Mybatis的設計思想。動手實現迷你Mybatis

理解Mybatis的設計思想。動手實現迷你Mybatis

參考: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 final 
String 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);
}
}

    輸出為


成功了