Mybatis: 接口编程的实现

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

// 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;
    }

}
复制代码

测试

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() + " | ");
        }

    }
复制代码

转载于:https://juejin.im/post/5ce40676e51d45599e019d08

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值