zoukankan      html  css  js  c++  java
  • 聊聊、手写Mybatis XML配置方式

    导航:  

    聊聊、Mybatis API  

    聊聊、Mybatis XML 

    聊聊、Mybatis集成Spring XML 方式

    聊聊、Mybatis集成Spring 注解方式 

    聊聊、手写Mybatis 注解配置方式 

    聊聊、手写Mybatis SpringBoot Starter

    首先,提出一个问题,怎么通过 mapperInterface 就能拿到数据的呢? 

    AccountMapper.java


     public interface AccountMapper {
      @Select("select * from account")
      public List<Map<String,Object>> queryAll();
    }

    在 main 方法中只要 AccountMapper mapper = (AccountMapper) getMapper(AccountMapper.class);mapper.queryAll();

    这里的 mapper 如果是个接口类,怎么去调用方法?怎么实例化?所以这里的 mapper 一定是个代理类。

    我们先来了解动态代理,实现动态代理的方式有很多种,例如:cglib、jdk动态代理,javassist。具体可以参考《聊聊、动态代理》。

    我们来看看,Mybatis 中怎么用动态代理的,我们用 JDK动态代理 实现 mapper 代理类。

    AccountInvokers.java 


    public class AccountInvokers implements InvocationHandler {

    public AccountInvokers() {
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      //通过 Method 拿到 @Select 注解的 value,也就是 @Select("select * from account") 中的 SQL 语句 

      Select select = method.getAnnotation(Select.class);

      //这里的 sql = select * from account

      String sql = select.value()[0]; 

      // 通过 sql 语句,查询数据库,没错,下面就是我们很熟悉的 JDBC 操作
      Class.forName("com.mysql.jdbc.Driver");
      Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?useSSL=false", "root", "root");
      Statement st = con.createStatement();
      ResultSet rs = st.executeQuery(sql);

     //封装成返回的对象类型

      List<Map<String,Object>> list = new ArrayList<>();
      while (rs.next()){
          Map<String,Object> map = new HashMap<>();
          int id = rs.getInt("id");
         String name = rs.getString("NAME");
         map.put("id",id);
         map.put("name",name);
         list.add(map);
      }
      st.close();
      con.close();
      return list;
    }
    } 

    好了,代理逻辑就是上面的代码,我们来调用看看。 

    Main方法 


    public class ManualMain {

    public static void main(String[] args) {
      AccountMapper mapper = (AccountMapper) getMapper(AccountMapper.class);
      System.out.println(mapper.queryAll());
    }

    public static Object getMapper(Class clazz){
      Object instance = Proxy.newProxyInstance(ManualMain.class.getClassLoader(), new Class[]{clazz}, new AccountInvokers());
      return instance;
    }
    }

    在 AccountInvokers 中,其实是有数据库连接操作逻辑的,所以我们调用 mapper.queryAll() 就能拿到数据。但这里代码还不够完善,因为并没有集成 Spring。

    这里只是解决了动态代理,还没有交给 Spring 管理。如果要交给 Spring 管理,我们实现自己的 AccountMapperFactoryBean,类似 MapperFactoryBean。

    AccountMapperFactoryBean 


    package org.rockcode.factory;

    import org.rockcode.invokers.AccountInvokers;
    import org.rockcode.mappers.AccountMapper;
    import org.springframework.beans.factory.FactoryBean;
    import java.lang.reflect.Proxy;
    import org.springframework.stereotype.Component; 

    @Component
    public class AccountMapperFactoryBean implements FactoryBean {

    @Override
    public Object getObject() {
      return getMapper(AccountMapper.class);
    }

    private Object getMapper(Class clazz){
      Object instance = Proxy.newProxyInstance(AccountFactoryBean.class.getClassLoader(), new Class[]{clazz}, new AccountInvokers());
      return instance;
    }

    @Override
    public Class<?> getObjectType() {
      return AccountMapper.class;
    }
    }

    AccountConfig 


    package org.rockcode.config;

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;

    @Configuration
    @ComponentScan({"org.rockcode.factory"})
    public class AccountConfig {
    }

      

    Main方法 


    public class ManualMain {

    public static void main(String[] args) {  

      AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AccountConfig.class);
      AccountMapperFactoryBean accountFactoryBean = ac.getBean(AccountFactoryBean.class);
      AccountMapper accountMapper = (AccountMapper) accountFactoryBean.getObject();
      System.out.println(accountMapper.queryAll());

    }
    } 

     

    上面的 AccountMapperFactoryBean 实现了 FactoryBean,这个扩展点在于 Spring 从 getObject() 方法中获得 Bean 实体。但相比 MapperFactoryBean,还少了 mapperInterface  和 sqlSessionFactory 两个属性。

    继续优化 AccountMapperFactoryBean 

    AccountMapperFactoryBean 


    package org.rockcode.factory;


    import org.apache.ibatis.session.Configuration;
    import org.mybatis.spring.support.SqlSessionDaoSupport;
    import org.springframework.beans.factory.FactoryBean;
    import static org.springframework.util.Assert.notNull;

    public class AccountMapperFactoryBean extends SqlSessionDaoSupport implements FactoryBean {

    private Class mapperInterface;

    public void setMapperInterface(Class mapperInterface) {
      this.mapperInterface = mapperInterface;
    }

    @Override
    protected void checkDaoConfig() {
      super.checkDaoConfig();
      notNull(this.mapperInterface, "Property 'mapperInterface' is required");
      Configuration configuration = getSqlSession().getConfiguration();
      configuration.addMapper(this.mapperInterface);
    }

    @Override
    public Object getObject() throws Exception {
      return getSqlSession().getMapper(this.mapperInterface);
    }

    @Override
    public Class<?> getObjectType() {
      return this.mapperInterface;
    }
    }

    spring.xml 


    <bean id="accountMapper" class="org.rockcode.factory.AccountMapperFactoryBean">
      <property name="mapperInterface" value="org.rockcode.mappers.AccountMapper"/>
      <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

      

    AccountController


    @Controller

    @RequestMapping
    public class AccountController { 

    @Autowired
    private AccountMapper accountMapper; 

    @RequestMapping("/getAllAccount")
    @ResponseBody
    public String getAllAccount(){
      accountMapper.queryAll();
      return "getAllAccount";
    } 

    }

    上面的实现用到了 FactoryBean,也用到了 SqlSessionDaoSupport,而 SqlSessionDaoSupport 中恰好用到了 InitializingBean 扩展点。

    就是在 InitializingBean  的 afterPropertiesSet() 方法中,调用了 checkDaoConfig() 方法。

    好了,到这里,手写 Mybatis 已经完成了一大半,实现了自己的 AccountMapperFactoryBean ,但是这个 AccountMapperFactoryBean 需要 XML 配置。如果是注解方式来实现手写 Mybatis,那有该怎么做呢?

  • 相关阅读:
    编程命名规范
    python 字符串编解码介绍
    django之sqlite3常见错误
    asp.net请求过程文章推荐
    python 多线程的文章
    工作中处理文本的python代码片段
    memcached一些知识
    咱计算机专业的人,能不能不那么特别地彰显对语文的无知?——再谈面向对象...
    你真的了解分层架构吗?——写给被PetShop"毒害"的朋友们...
    混蛋的面试题——《大话设计模式》读后感
  • 原文地址:https://www.cnblogs.com/xums/p/12625256.html
Copyright © 2011-2022 走看看