Mybatis: 接口编程的实现

实现基于接口编程的关键在于DAO是一个代理类, 所以DAO 不该该由用户进行实例化, 应该由框架提供统一的工厂类用来获取DAO. 工厂类中根据DAO类型生成对应的动态代理类返回用户.sql

// Mapper工厂类(负责生成DAO的动态代理对象)
public class MapperFactory {

    // SQL会话工厂类
    private SqlSessionFactory sqlSessionFactory;

    // 经过SQL会话工厂类实例化
    public MapperFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    // 根据DAO类型获取DAO的动态代理类
    public <T> T getMapper(Class<T> clazz) {
        SqlSession session = this.sqlSessionFactory.getSession();
        return new MapperProxy(session).getMapper(clazz);
    }
    
}
复制代码

在获取DAO时经过工厂类获取, 此时获取的是DAO的代理类.数据库

UserDAO userDAO = new MapperFactory(sf).getMapper(UserDAO.class);
复制代码

当调用DAO中的接口时, 会自动执行动态代理类中的invoke方法. 在invoke方法中执行数据库操做便可.编程

// Mapper动态代理类
public class MapperProxy implements InvocationHandler {

    // SQL会话
    private SqlSession sqlSession;

    // 经过SQL会话实例化
    public MapperProxy(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    // 获取动态代理类
    @SuppressWarnings("unchecked")
    public <T> T getMapper(Class<T> clazz) {
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, this);
    }

    // 执行接口时进入该方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // 接口中方法名称和SQL节点ID相同
        String statementId = method.getName();
        // 根据方法名称便可获取对应的SQL节点信息
        MappedStatement ms = sqlSession.getConfig().getMappedStatement(statementId);

        if (ms == null) {
            throw new RuntimeException("无对应的SQL, id:" + statementId);
        }

        String type = ms.getStatementType();
        Object param = (args != null) ? args[0] : null;

        // 根据SQL类型执行对应的数据库操做方法
        if ("insert".equals(type)) {
            return sqlSession.insert(statementId, param);
        } else if ("update".equals(type)) {
            return sqlSession.update(statementId, param);
        } else if ("delete".equals(type)) {
            return sqlSession.delete(statementId, param);
        } else if ("select".equals(type)) {
            return sqlSession.selectList(statementId, param);
        }

        return null;
    }

}
复制代码

测试bash

public static void main(String[] args) {

        // 建立SQL会话工厂
        SqlSessionFactory sf = new SqlSessionFactoryBean("*_mapper.xml").build();
        MapperFactory factory = new MapperFactory(sf);

        // 经过工厂类获取DAO
        UserDAO userDAO = factory.getMapper(UserDAO.class);

        // 调用DAO中方法
        int count = userDAO.insertUser(new User(1L, "zhangsan", 20, "sssss", "ok"));
        List<User> userList = userDAO.selectUser();

        // 输出查询结果
        System.out.println(count);

        for (User u : userList) {
            System.out.println("| " + u.getId() + " | " + u.getUname() + " | ");
        }

    }
复制代码
相关文章
相关标签/搜索