Batis的返回值参数类型也有种:resultMap与resultClass

  收藏代码
  1. Batis的返回值参数类型也有种:resultMap与resultClass  
  2.    
  3. 这两种类型的选择可以用两句话说明之:  
  4.    
  5. 一:当结果集列名和类的属性名完全相对应的时候,则可直接用resultClass直接指定查询结果类型。  
  6.        
  7.  二:当查询结果集与属性名对应不上的时候,就可以采用resultMap指定列名与对象属性名之间的对应关系,否则对应不上的属性将为null0.  
  8.    
  9.     resultMap映射结果的目的就是要将查询的结果集绑定到映射对象的属性上。其实对于这种情况用resultClass也是可以解决的,  
  10.      就是直接在Sql语句中采用as重命名的方式将结果集中与对象属性名不相同的字段用as重命名。  
  11.    
  12. 对于resultMap和resultClass有个很有趣的例子:  
  13.    
  14. iBatis的查询方法中有这样一个查询方法:  
  15.    
  16. 暂且不说这个方法是什么,假使我们有这样的需求,数据库中很多条数据,有一个字段假使是name,每一条数据映射我们一个实体对象  
  17.    
  18. 我们的需求是将所有的数据查询出来,根据不同的name属性值要做不同的处理。  
  19.    
  20. 首先想到的肯定是先将所有的数据查询出来而不是根据不同的name重复查询多次,将所有的数据查询出来也有两种方式,  
  21.    
  22. 第一种我们常用的List<?>集合的形式,另一种Map<?,?>的形式。  
  23.    
  24. 就这个需求而言显然是直接查询出Map<?,?>比较还一点,这样我们就可以直接在程序中根据已知的name找到对应的对象,而不必循环遍历。  
  25.    
  26. 这样的需求可能不多,这儿就就事论事一回吧。  
  27.    
  28. 第一个方法:  
  29.  public java.util.Map queryForMap(java.lang.String id,  
  30.                                   java.lang.Object parameterObject,  
  31.                                   java.lang.String keyProp)throws java.sql.SQLException  
  32.    
  33. 该方法有三个参数,第一个是statement,第二个是查询入参,第三个是返回的Map集合的key属性。  
  34.    
  35.     public Map<String, User> getUserMap2() throws SQLException  
  36.      {  
  37.          return sqlMapClient.queryForMap("User.queryForMap2"null"userID");  
  38.      }  
  39.    
  40. Dao里面有这样两个方法,第一个作用就是查询出所有的User对象,以User对象的userID为key存放到Map集合中返回。  
  41.    
  42.    
  43.    
  44. xml映射文件:  
  45.  <select id="queryForMap2" resultClass="java.util.HashMap">//注意此处不能写java.util.Map,必须是具体的实现类,否则iBatis无法实例化  
  46.    select * from t_user  
  47.  </select>  
  48.    
  49. 测试代码:  
  50.  Map<String, User> user = dao.getUserMap2();  
  51.  System.out.println(user);  
  52.    
  53. 查询Map结果:  
  54.  {null={AGE=28, USERID=6, USERNAME=zhangbo}}//输出结果十分诡异,数据库里面有六条数据,为什么只查询出来最后一条,而且key还是null  
  55.    
  56. 而且value并不是一个User对象,User对象的里面没有USERNAME的属性,{AGE=28, USERID=6, USERNAME=zhangbo}只是数据库里面的一条数据而已。  
  57.   Map<String, User> user = dao.getUserMap2();  
  58.   System.out.println(user);  
  59.    
  60.  User user2 = user.get(null);  
  61.   //尝试从Map中获取key为null的User对象,抛类型转换异常,即Map里面的根本不是User对象,因为User对象根本没有username的属性。  
  62.   System.out.println(user2.getName());  
  63.    
  64.   设置将Map<String, User>中的User写成任何类型都没有问题。即:  
  65.   Map<String, String> user = dao.getUserMap2();  
  66.   System.out.println(user);  
  67.   执行输出结果和是一样的。  
  68.     
  69.   为什么?其实iBatis底层的确是不知道我有个User类型的对象,那么它是怎么将数据库数据映射的呢?  
  70.   其实关于key为null可不可以这样理解:  
  71.   我在Dao里面这样写的 return sqlMapClient.queryForMap("User.queryForMap2"null"userID");  
  72.   指定Map集合的key的名称为“userID”,我想的是拿User对象的“userID”作为key,但是iBatis根本就不知道User对象是个什么东西,映射文件  
  73.   里面根本就没有哪儿出现过User对象,因为映射文件指定的resultClass是java.util.HashMap,哪儿有userID的属性。  
  74.   关于查询出来的数据只有最后一条数可以这样理解的:  
  75.   iBatis的queryForMap()方法,其实也是先根据条件查询出一个List集合,然后遍历List集合,将对象以Key,Value的形式存入Map中返回。  
  76.   其实List集合确实查询了数据库满足条件的6条数据,只是这6条数据指定的key都为null。遍历的时候先将List中的第一条以key为null的形式  
  77.   存入Map中,然后又将第二条再以key为null放入Map中,显而易见,key相同,相当于替换了第一条,以此类推,Map中始终只能只有最后一条数据了。  
  78.    
  79.  至于key为什么是null,一时我说不上来。有待研究!肯定一个根本的原因就是使用了resultClass,而HashMap又没有“userID”属性???  
  80.     
  81.   那么我们不妨来试一下使用一下resultMap,并给HashMap指定属性:  
  82.   <resultMap class="java.util.HashMap" id="resultMap-UserMap2">  
  83.    <result property="userID" column="userID"/>  
  84.    <result property="username" column="username"/>  
  85.    <result property="userage" column="age"/>  
  86.   </resultMap>  
  87.   <select id="queryForMap2" parameterClass="java.lang.String" resultMap="resultMap-UserMap2">  
  88.    select * from t_user  
  89.   </select>  
  90.     
  91.    public Map<String, User> getUserMap2() throws SQLException  
  92.    {  
  93.        return sqlMapClient.queryForMap("User.queryForMap2"null"userID");  
  94.    }  
  95.   这样一来,我们就指定了数据库字段与实体对象之间的映射,先来看一下执行结果:  
  96.   {  
  97.   3={userID=3, username=zhangbo, userage=25},  
  98.    
  99.  5={userID=5, username=zhangbo, userage=27},   
  100.   2={userID=2, username=zhangbo, userage=24},   
  101.   4={userID=4, username=zhangbo, userage=26},   
  102.   6={userID=6, username=zhangbo, userage=28},   
  103.   1={userID=1, username=zhangbo, userage=23}  
  104.   }  
  105.   输出结果似乎是正确的,有两个疑问,为什么顺序是乱的?value真的是Map<String, User>中的User对象?  
  106.    Map<String, User> user = dao.getUserMap2();  
  107.    System.out.println(user);  
  108.    User user2 = user.get("3");//抛类型转换异常,即Map里面的根本不是User对象,因为User对象根本没有username的属性。  
  109.    System.out.println(user2.getName());  
  110.      
  111.    那么是不是如果我们的resultMap的xml中如果我们将数据库的字段映射成User的三个属性就不会再有类型转化异常了呢?  
  112.    试一试:  
  113.     <resultMap class="java.util.HashMap" id="resultMap-UserMap2">  
  114.    
  115.  <result property="userID" column="userID"/>  
  116.    <result property="name" column="username"/>  
  117.    <result property="age" column="age"/>  
  118.    </resultMap>  
  119.    <select id="queryForMap2" parameterClass="java.lang.String" resultMap="resultMap-UserMap2">  
  120.    select * from t_user  
  121.    </select>  
  122.     
  123.    public Map<String, User> getUserMap2() throws SQLException  
  124.    {  
  125.        return sqlMapClient.queryForMap("User.queryForMap2"null"userID");  
  126.    }  
  127.      
  128.    注:User对象的三个属性,userID, name, age。  
  129.      
  130.    好的,以上xml映射文件中将数据库字段映射到User对象的三个属性上,而且返回resultClass依然是java.util.HashMap。  
  131.    我们的目的是将数据库中的数据查询出来封装成具体的User对象,然后以userID为Key,该User对象为Value存放到Map中,  
  132.    试想能不能实现?似乎能,  
  133.    1.我们似乎在queryForMap中已经指定了Map的key为“userID”(sqlMapClient.queryForMap("User.queryForMap2"null"userID");)。  
  134.    2.我们似乎已经告诉iBatis我们需要在Map中存放User对象,因为我们方法的返回值为<String, User>写的清清楚楚。  
  135.    
  136.  好,再试一下:  
  137.    Map<String, User> user = dao.getUserMap2();  
  138.    System.out.println(user);  
  139.    User user2 = user.get("3");//还是抛类型转换异常。  
  140.    尝试将iBatis给我们的Map<Object, Object>集合中的Object转化成User失败,那么iBatis返回的Map中的Object  
  141.    为什么不是User对象?  
  142.    究竟是什么玩意?  
  143.    揭开其神秘的面纱:  
  144.    既然我们不知道Map中的Object究竟是什么玩意,我们不妨这样来,将Dao方法的返回值改成Map<Object, Object>,再一下结果  
  145.    Map<Object, Object> map = dao.getUserMap2();  
  146.    System.out.println(map.getClass().getName());//这个肯定是一个java.util.HashMap类型  
  147.      
  148.    System.out.println(map.get("1").getClass().getName());//这个居然也是java.util.HashMap类型,  
  149.    以上结果表明,查询结果是Map中放了一个我们指定的"userID"为key,一个HashMap为value的HashMap集合。  
  150.    怎么解释?  
  151.    从头至尾总觉得有点不对劲的地方,因为我们一直没有告诉iBatis我们要返回User对象,因为我们的resultClass是java.util.HashMap  
  152.    虽然我们的方法返回值是Map<String, User>, 但是它实际的返回值是Map<Object, Object>,所以我们  
  153.    的方法返回值返回任何类型的Map集合都能编译通过,java中任何类型都是Object的子类型,这只是一个假象而已。  
  154.    User user2 = user.get("3");到了我们真正想将Object类型转化成User类型的时候,报错了,HashMap到User的转化,显而易见。  
  155.    
  156.  从这一点上来看iBatis还是比较灵活的,我们可以通过queryForMap指定我们放在Map中的key,   
  157.    return sqlMapClient.queryForMap("User.queryForMap2"null"xxx");  
  158.    如果我们想返回Map<Object, Map<>>形式,这里不是必须写成"userID",它只是一个形式参数,只要和映射文件中的resultMap中的某个  
  159.    property属性相同即可,当然这个属性对应的数据库字段值就将被当成key。  
  160.     <resultMap class="java.util.HashMap" id="resultMap-UserMap2">  
  161.    <result property="xxx" column="userID"/>  
  162.    <result property="name" column="username"/>  
  163.    <result property="age" column="age"/>  
  164.    </resultMap>  
  165.    如果我们指定的key在数据库中由重复怎么办?例如:  
  166.    <resultMap class="java.util.HashMap" id="resultMap-UserMap2">  
  167.    <result property="xxx" column="userID"/>  
  168.    <result property="ooo" column="username"/>  
  169.    <result property="age" column="age"/>  
  170.    </resultMap>  
  171.    return sqlMapClient.queryForMap("User.queryForMap2"null"ooo");//将数据库username字段值作为key  
  172.    不出我们所料,结果:  
  173.    {zhangbo={age=28, xxx=6, ooo=zhangbo}},至于为什么只有一条记录而且是最后一条,不再累述。可见我们写在  
  174.    resultMap映射文件中的“property”便是我们Map<Object, Map<>>中,里面个Map的key值。  
  175.    
  176.  这样一来iBatis就很灵活了,对应一张数据库表,我想用iBatis进行增删该查,特别是查,我们不是非得要有需要一个对象与  
  177.    表结果对应,我们可以没有一个对象对应这张表,依然可以将表中的数据查询出来封装到Map中供我们很方便的使用。  
  178.      
  179.    那么按照我们的初衷,将一个对象放到Map中,以这个对象的某个属性为key,这个对象为value放到Map中返回是不是也可以实现了,  
  180.    答案非常肯定,可以,稍作修改:  
  181.      
  182.    完整的映射文件:  
  183.     <resultMap class="com.ibatis.entity.User" id="resultMap-UserMap2">  
  184.    <result property="userID" column="userID"/>//指定User的每个属性和数据库字段的映射关系  
  185.    <result property="name" column="username"/>  
  186.    <result property="age" column="age"/>  
  187.   </resultMap>  
  188.   <select id="queryForMap2" parameterClass="java.lang.String" resultMap="resultMap-UserMap2">  
  189.    select * from t_user  
  190.   </select>  
  191.    完整的Dao代码:  
  192.     @SuppressWarnings("unchecked")  
  193.      public Map<String, User> getUserMap2() throws SQLException  
  194.      {  
  195.    
  196.    
  197.    
  198.        return sqlMapClient.queryForMap("User.queryForMap2"null"userID");//这里指定的key的名称应该是User的某个属性名称  
  199.      }  
  200.    完整的测试代码:  
  201.      Map<String, User> user = dao.getUserMap2();  
  202.    
  203.     System.out.println(user);  
  204.      System.out.println(user.get("1").getName());  
  205.    完整的输出结果:  
  206.    {  
  207.     3=User: age=25 &userID=3 &name=zhangbo ,   
  208.     5=User: age=27 &userID=5 &name=zhangbo ,   
  209.     2=User: age=24 &userID=2 &name=zhangbo ,   
  210.     4=User: age=26 &userID=4 &name=zhangbo ,   
  211.     6=User: age=28 &userID=6 &name=zhangbo ,   
  212.     1=User: age=23 &userID=1 &name=zhangbo   
  213.    }  
  214.     zhangbo  
  215.       
  216.    所以想要达到这种效果,我们的resultMap中的resultClass应该是具体的对象,而不是我们想当然的java.util.HashMap  
  217.    
  218.  还有一个queryForMap方法的重写方法  
  219.    public java.util.Map queryForMap(java.lang.String id,  
  220.                                   java.lang.Object parameterObject,  
  221.                                   java.lang.String keyProp,  
  222.                                   java.lang.String valueProp)  
  223.       
  224.     这个方法不但指定了我们返回的Map中的key, 而且也指定了Map中的value。通过这个方法我们就可以查询一个表中的特定的两个字段值  
  225.     一个字段的值作为key,一个字段的值作为value。  
  226.     举个例子:  
  227.       
  228.     完整的Dao代码:  
  229.      @SuppressWarnings("unchecked")  
  230.      public Map<String, String> getUserMap3(String userID) throws SQLException  
  231.      {  
  232.       //同样,“xxx”, “ooo”只是形参,任意字符串  
  233.          return sqlMapClient.queryForMap("User.queryForMap3", userID, "xxx","ooo");//查询指定userID的一条数据,至于哪个字段是key,哪个字段是value,只有resultMap映射字段能控制。  
  234.      }  
  235.     
  236.   resultMap映射文件:  
  237.   <resultMap class="java.util.HashMap" id="resultMap-UserMap3">  
  238.    
  239.   <result property="xxx" column="username"/>//指明xxx, ooo 对应的数据库字段名称,到底是数据库的哪个字段值作为key,哪个作为value。  
  240.    <result property="ooo" column="age"/>  
  241.   </resultMap>  
  242.   <select id="queryForMap3" parameterClass="java.lang.String" resultMap="resultMap-UserMap3">  
  243.    select * from t_user where userID=#aaa# //"aaa"也是一个形式参数,任意字符串  
  244.   </select>  
  245.     
  246.   测试代码:  
  247.   Map<String, String> map = dao.getUserMap3("3");  
  248.      System.out.println(map);  
  249.     
  250.   输出结果:  
  251.   {zhangbo=25}  
  252.     
  253.   有一个地方值得注意:  
  254.   <select id="queryForMap3" parameterClass="java.lang.String" resultClass="java.util.HashMap">//这里直接写成HashMap可以吗?  
  255.    select * from t_user where userID=#aaa#   
  256.   </select>  
  257.   return sqlMapClient.queryForMap("User.queryForMap3", userID, "xxx","ooo");//假设"xxx", "ooo"就是数据库两个字段的名称  
  258.    
  259.  因为我们知道,当我们的对象属性名称和数据字段相同的情况下,我们是直接写resultClass="xxx.xxx.xxx"即可的,只有当我们数据库的  
  260.   字段名称与对象的属性不同的情况下我们才需要一个resultMap将数据库字段与对象属性名称对应起来。  
  261.     
  262.   即使这样,以上的假设是不可以的,这样的情况必须是resultMap来指定数据库字段对应HashMap的key和value, 其实也挺好理解的,  
  263.   1.如果直接指定成resultClass="java.util.HashMap", 那么HashMap没有一个叫"xxx""ooo"的属性,所以iBatis无法跟一般的对象  
  264.   一样将数据库字段自动映射到对象相同名称的属性上。  
  265.   2.此处的resultMap不是指定数据库哪个字段对应对象哪个属性,而是指定数据库的哪个字段作为key,哪个字段作为value。那么到底哪个  
  266.   作为key,哪个作为value是在我们调用queryForMap的方法时候指定的。   
  267.    
  268.   总结:  
  269.   针对第一个只指定key的queryForMap方法:  
  270.   如果resultMap中依然设定resultClass="java.util.HashMap".iBatis的处理方式就是  
  271.   将数据库指定的key值作为key,再将所有的字段封装成HashMap作为返回Map的value。将所有字段封转成HashMap的时候,以resultMap  
  272.   中我们指定的名称作为key,数据库对应字段值作为value的。  
  273.   如果设定resultClass="具体对象",那么iBatis就会将数据库字段值设置到该对象的指定属性上作为Value,Key依然是指定的该对象的一个  
  274.   属性。  
  275.   针对第二个指定key,value的queryForMap方法:  
  276.   就是查询数据库的任意两个字段值,一个作为返回Map的key,一个作为返回Map的value,至于哪个作为key,哪个作为value,由查询方法  
  277.   和resultMap一起决定,resultMap中的resultClass=“java.util.HashMap”。  
  278.     
  279.   从这两个方法看iBatis的resultclass和resultMap还是非常的灵活和有用的,尽管queryForMap方法在具体的工作中可能用的不是很多,  
  280.   但是有这两个方法的存在,iBatis显得更加的强大了,对数据库的操作不一定非要与某个我们的对象模型关联了,用java的HashMap就  
  281.   可以搞定。从这一点来看,HashMap和一个pojo对象有惊人的相似点,自己体会去吧。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值