理解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);
    }
}

    输出为


成功了

猜你喜欢

转载自blog.csdn.net/yanghan1222/article/details/80423309