zoukankan      html  css  js  c++  java
  • mybatis入门-mapper代理原理

      原始dao层开发

        在我们用mybatis开发了第一个小程序后,相信大家对于dao层的开发其实已经有了一个大概的思路了。其他的配置不用变,将原来的test方法,该为dao的方法,将原来的返回值,直接在dao层进行一下接收就可以了。依然是老一套,先是大框架,然后写配置文件及UserMapper.xml文件这一系列的操作。如果不明白的,请参考本人博客《入门第一个程序》。

        我们需要做的就是,首先建立一个会话工厂(SqlSessionFactory),然后用会话工厂创建会话(SqlSession)。然后通过读取配置文件得到sql语句,执行,然后返回数据给dao层的对象。具体操作如下

        首先,在原来的基础上创建一个dao层的接口。

        

        然后写一个dao层接口的实现类

     1 public class UserDaoImpl implements UserDao {
     2  
     3 // 需要向dao实现类中注入SqlSessionFactory
     4 // 这里通过构造方法注入
     5 private SqlSessionFactory sqlSessionFactory;
     6  
     7 public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
     8 this.sqlSessionFactory = sqlSessionFactory;
     9 }
    10  
    11 @Override
    12 public User findUserById(int id) throws Exception {
    13 SqlSession sqlSession = sqlSessionFactory.openSession();
    14  
    15 User user = sqlSession.selectOne("test.findUserById", id);
    16  
    17 // 释放资源
    18 sqlSession.close();
    19  
    20 return user;
    21  
    22 }
    23  
    24 @Override
    25 public void insertUser(User user) throws Exception {
    26 SqlSession sqlSession = sqlSessionFactory.openSession();
    27  
    28 //执行插入操作
    29 sqlSession.insert("test.insertUser", user);
    30  
    31 // 提交事务
    32 sqlSession.commit();
    33  
    34 // 释放资源
    35 sqlSession.close();
    36  
    37 }
    38  
    39 @Override
    40 public void deleteUser(int id) throws Exception {
    41 SqlSession sqlSession = sqlSessionFactory.openSession();
    42  
    43 //执行插入操作
    44 sqlSession.delete("test.deleteUser", id);
    45  
    46 // 提交事务
    47 sqlSession.commit();
    48  
    49 // 释放资源
    50 sqlSession.close();
    51  
    52 }
    53  
    54 }

    然后就是对我们写的代码的测试

        这样开发的话有一些问题:

        1.dao接口的实现类中存在大量的重复代码,这些代码会增加程序员的工作量。

        2.在实现类中,SqlSession的方法在调用映射文件中的sql语句时将statement的id(其中的"test.findUserById"便是statment的id)硬编码了。

        

        3.调用SqlSession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入的不是Dao方法中的参数类型,在编译的时候也不会报错,不利于程序的开发。

        

        为了解决这些问题,我们通过满足一些规范就将实体层的实现类的开发省去,由mybatis框架提供的代理实现类替我们去动态的调用我们的映射文件,然后去执行类中的方法。

      mapper代理方法的原理

        这之前,先声明一下,使用mapper代理的时候,命名和之前的不太一样。这里的接口命名由原来的** 改为**Mapper,比如说原来的User接口,现改为UserMapper。其内容和本质没有变,只是换了一个命名规范。除了接口外映射文件也是由User.xml改为UserMapper.xml其内容不变。

        mapper代理方法的思路是,程序员接着写持久层的接口。

        

        和对应每个接口的配置文件。

        

       在我们的原来的方法中需要再写一个接口的实现类,用来构建会话工厂(SqlSessionFactory)和对应的会话(SqlSession)然后通过会话去读取映射文件中的sql语句(这里不准确,不过可以这么理解)。那么我么就可以在这个实体类上做点文章了:

        1.我们可以创建一个代理类,在我们相应的接口被调用的时候,代理类就会创建这个对象,创建会话工厂和会话并不难。

        2.还有就是我们的sqlSession对象调用的方法名称,这个很好理解,对应的是我们映射文件的标签。

        3.那么接下来就是传入参数和接收返回值的问题了:

        3.1 传入参数:我们总共需要传入两个参数,一个是映射文件的statement的id的字符串,另外一个是执行需要的参数。 比较困难的是,这个字符串的生成问题。我们的每个方法到底对应的是哪个映射文件的statement的id。对于这个问题,mybatis给出了我们的解决方法:我们的实体层对象读到的字符串是这样的:test.insertUser

        可以将这个id分为两部分,其中的test是我们的映射文件中的namespace的值,这个值让它和持久层接口的地址一致,这样就使得代理对象可以通过接口的地址动态的生成id的前半部分,也就是test的这一部分;而后半部分则是让映射文件中的Statement的id和接口的方法一致。

        也就是说,用户在调用接口的某一个方法的时候,mybatis可以根据接口地址和对应的方法名生成sqlsession对象的方法传入的字符串。这样就解决了传入参数中的字符串的问题了。

        还有就是第二个问题:我们的传入具体参数,mybatis规定,传入参数类型必须和接口的传入参数类型一致。这样,我们的传入参数类型就搞定了。

        3.2传入参数搞定了以后,返回值也就搞定了,跟传入参数的规定一样,返回值的类型要求和接口返回值一致,这样就可以在代理类中将返回值传出了。

        这些搞定了,我们就可以使用代理对象代替我们的实体层具体实现类了。

        至此,这些问题就差不多都解决了,不过还有一个问题:我们的select方法返回值问题,代理对象到底是用selectont方法去查询数据库呢还是使用selectlist方法呢?这个跟我们的接口(mapper)的返回值类型有关——如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库;如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。

      mapper代理方法

        原理讲完了,使用其实就基本上没啥要说的了。

        首先我们要创建一个接口。

        

        然后写对应接口的xml文件(截取部分,namespace处就不截图了)。

         

        最后别忘了在SqlMapConfig.xml文件中加载UserMapper.xml。

        

        测试,这里有必要说一下,我们的代理对象是通过SqlSession.getMapper(接口字节码文件)获取的。:

        

        至此,我们的mybatis的实体层的实体层实现类就可以省略不写了。不过这样做的坏处是加强了代码的耦合性,每个接口和每个映射文件必须对应。不过还是感觉通过遵守一定的规范而使得代码量大大减少更爽呢。

  • 相关阅读:
    前端iframe跨域传值笔记
    css 将第1/n行文本超出部分替换成省略号
    第一章:1-08、计算机网络中的主干网和本地接入网各有何特点?
    第一章:1-07、 计算机网络可从哪几个方面进行分类?
    第一章:1-06、 试将TCP/IP和OSI的体系结构进行比较。讨论其异同之处?
    第一章:1-05、试讨论在广播式网络中对网络层的处理方法。讨论是否需要这一层?
    第一章:1-04、为什么说因特网是自由印刷术以来人类通信方面最大的变革?
    第一章:1-03、试从多个方面比较电路交换、报文交换和分组交换的主要优缺点。
    第一章:1-02、试简述分组交换的要点。
    第一章:1-01、计算机网络的发展可划分为几个阶段?每个阶段各有何特点?
  • 原文地址:https://www.cnblogs.com/liyasong/p/6387825.html
Copyright © 2011-2022 走看看