zoukankan      html  css  js  c++  java
  • Spring+Mybatis实现动态SQL查询

    Spring+Mybatis实现动态SQL查询

    在报表类应用中,通常需要根据不同的维度去组合复杂的查询条件,然后构造SQL去执行查询。如果只是通过在程序中简单地拼接SQL语句,工作量会非常大,而且代码可能也非常难以维护。Mybatis支持动态SQL查询功能,可以通过配置动态的SQL来简化程序代码中复杂性,不过,这个颇有点XML编程的韵味,通过XML来处理复杂的数据判断、循环的功能,其实也很好理解。

    准备工作

    下面,我们首先创建一个MySQL示例表,如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    CREATE TABLE `traffic_info` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `domain` varchar(64) NOT NULL,
      `traffic_host` varchar(64) NOT NULL,
      `month` varchar(8) NOT NULL,
      `monthly_traffic` int(11) DEFAULT '0',
      `global_traffic_rank` int(11) DEFAULT '0',
      `native_traffic_rank` int(11) DEFAULT '0',
      `rank_in_country` varchar(64) DEFAULT NULL,
      `address` varchar(200) DEFAULT NULL,
      `email` varchar(50) DEFAULT NULL,
      `traffic_type` int(2) DEFAULT '-1',
      `status` int(2) DEFAULT '0',
      `created_at` date DEFAULT NULL,
      `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      `f1` varchar(255) DEFAULT NULL,
      `f2` varchar(255) DEFAULT NULL,
      `f3` varchar(255) DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `idx_traffic` (`domain`,`month`,`traffic_type`)
    ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

    这个表用来存储域名的流量信息,流量信息我们从互联网上像Alexa、Compete、Quantcast等提供商获取,通过Crawler抓取的方式实现。我们先从简单的查询做起,只是根据某个字段进行查询,说明如何配置使用Mybatis,这里面也包含如何与Spring进行集成。

    配置实践

    下面是用到的一些资源的定义:

    • org.shirdrn.mybatis.TrafficInfo类

    该类对应于traffic_info表中一条记录的数据,我们简单取几个字段,如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package org.shirdrn.mybatis;
     
    import java.io.Serializable;
     
    public class TrafficInfo implements Serializable {
         
         private static final long serialVersionUID = -8696613205078899594L;
         int id;
         String domain;
         String month;
         int monthlyTraffic;
         
         public int getId() {
              return id;
         }
         public void setId(int id) {
              this.id = id;
         }
         public String getDomain() {
              return domain;
         }
         public void setDomain(String domain) {
              this.domain = domain;
         }
         public String getMonth() {
              return month;
         }
         public void setMonth(String month) {
              this.month = month;
         }
         public int getMonthlyTraffic() {
              return monthlyTraffic;
         }
         public void setMonthlyTraffic(int monthlyTraffic) {
              this.monthlyTraffic = monthlyTraffic;
         }
         
         @Override
         public String toString() {
              return "[id=" + id + ", domain=" + domain + ", month=" +
                        month + ", monthlyTraffic=" + monthlyTraffic + "]";
         }
         
    }
    • org.shirdrn.mybatis.mapper.TrafficInfoMapper接口类

    该类定义了一个与SQL配置进行映射的基本操作,实际的SQL配置有专门的XML文件来进行配置。该接口定义了如下操作:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    package org.shirdrn.mybatis.mapper;
     
    import java.util.List;
    import java.util.Map;
     
    import org.shirdrn.mybatis.TrafficInfo;
     
    public interface TrafficInfoMapper {
     
         /**
         * 根据指定id去查询记录,结果至多只有一条
         * @param id
         * @return
         */
         TrafficInfo getTrafficInfo(int id);
         
         /**
         * 根据指定的domain参数查询记录,返回一个记录的列表
         * @param domain
         * @return
         */
         List<TrafficInfo> getTrafficInfoList(String domain);
         
         /**
         * 根据一个 字段domain进行查询,但是存在多个domain的值,传入一个数组
         * @param domains
         * @return
         */
         List<TrafficInfo> getMultiConditionsList(String[] domains);
         
         /**
         * 根据多个字段进行查询,每个字段可能有多个值,所以参数是Map类型
         * @param conditions
         * @return
         */
         List<TrafficInfo> getMapConditionsList(Map<String, Object> conditions);
     
    }

    上面接口中定义的操作,一个比一个复杂,我们通过这一系列操作来说明在Mybatis中如果使用各种查询功能。

    • org/shirdrn/mybatis/mapper/TrafficInfoMapper.xml映射配置文件

    这个文件TrafficInfoMapper.xml对应了上面的org.shirdrn.mybatis.mapper.TrafficInfoMapper中定义的操作,通过XML的方式将对应的SQL查询构造出来,这个是Mybatis的核心功能。该文件的内容示例如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     
    <mapper namespace="org.shirdrn.mybatis.mapper.TrafficInfoMapper">
         <resultMap type="TrafficInfo" id="tfMap">
              <id property="id" column="id" />
              <result property="domain" column="domain" />
              <result property="month" column="month" />
              <result property="monthlyTraffic" column="monthlyTraffic" />
         </resultMap>
         
         <select id="getTrafficInfo" resultType="TrafficInfo" parameterType="int">
              SELECT * FROM domain_db.traffic_info WHERE id = #{id}
         </select>
         
         <select id="getTrafficInfoList" resultType="TrafficInfo" parameterType="string">
              SELECT * FROM domain_db.traffic_info WHERE domain = #{domain}
         </select>
         
         <select id="getMultiConditionsList" resultMap="tfMap">
              SELECT * FROM domain_db.traffic_info WHERE domain IN
              <foreach collection="array" index="index" item="domain" open=" (" separator="," close=")">
                 #{domain}
             </foreach>
         </select>
         
         <select id="getMapConditionsList" resultMap="tfMap">
              SELECT * FROM domain_db.traffic_info WHERE domain IN
              <foreach collection="domains" index="index" item="domain" open=" (" separator="," close=")">
                 #{domain}
             </foreach>
             AND status = 0 AND month IN
             <foreach collection="months" index="index" item="month" open=" (" separator="," close=")">
                 #{month}
             </foreach>
         </select>
     
    </mapper>

    如果你之前用过ibatis,应该很熟悉上面这个配置文件。上面:
    namespace指定该SQL映射配置文件的Mapper接口类,其中定义了基本的SQL查询操作(以我们给出的例子为例);
    resultMap中的type的值这里是一个别名,当然也可以使用对应的具体类全名(包名+类名),我们会在Mybatis的总的映射配置文件中进行配置,详见后面说明;
    select是查询SQL的配置,可以通过不同的元素进行动态构造,如if、foreach等;

    • Mybatis全局映射配置文件sqlMapConfig.xml

    该文件可以指定数据库连接池配置、别名配置、SQL映射配置文件组等内容,这里示例的配置内容如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     
    <configuration>
         <typeAliases>
              <typeAlias type="org.shirdrn.mybatis.TrafficInfo" alias="TrafficInfo" />
         </typeAliases>
         <mappers>
              <mapper resource="org/shirdrn/mybatis/mapper/TrafficInfoMapper.xml" />
         </mappers>
    </configuration>
    • Spring配置文件applicationContext.xml
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    <?xml version="1.0" encoding="UTF-8"?>
         xsi:schemaLocation="http://www.springframework.org/schema/beans
     
     
     
     
     
     
     
     
     
     
     
     
     
     
         <bean
              class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
              <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
              <property name="ignoreResourceNotFound" value="true" />
              <property name="locations">
                   <list>
                        <value>classpath*:/proxool.properties</value>
                   </list>
              </property>
         </bean>
     
         <context:component-scan base-package="org.shirdrn.mybatis" />
     
         <aop:aspectj-autoproxy proxy-target-class="true" />
         <aop:config proxy-target-class="true" />
     
         <bean id="dataSource" class="org.shirdrn.mybatis.utils.ProxoolDataSource">
              <property name="driver" value="${jdbc-0.proxool.driver-class}" />
              <property name="driverUrl" value="${jdbc-0.proxool.driver-url}" />
              <property name="user" value="${jdbc-0.user}" />
              <property name="password" value="${jdbc-0.password}" />
              <property name="alias" value="${jdbc-0.proxool.alias}" />
              <property name="prototypeCount" value="${jdbc-0.proxool.prototype-count}" />
              <property name="maximumActiveTime" value="${jdbc-0.proxool.maximum-active-time}" />
              <property name="maximumConnectionCount" value="${jdbc-0.proxool.maximum-connection-count}" />
              <property name="minimumConnectionCount" value="${jdbc-0.proxool.minimum-connection-count}" />
              <property name="simultaneousBuildThrottle"
                   value="${jdbc-0.proxool.simultaneous-build-throttle}" />
              <property name="verbose" value="${jdbc-0.proxool.verbose}" />
              <property name="trace" value="${jdbc-0.proxool.trace}" />
              <property name="houseKeepingTestSql" value="${jdbc-0.proxool.house-keeping-test-sql}" />
              <property name="houseKeepingSleepTime" value="${jdbc-0.proxool.house-keeping-sleep-time}" />
              <property name="maximumConnectionLifetime"
                   value="${jdbc-0.proxool.maximum-connection-lifetime}" />
         </bean>
     
         <bean id="dataSource0" class="org.jdbcdslog.ConnectionPoolDataSourceProxy">
              <property name="targetDSDirect" ref="dataSource" />
         </bean>
     
         <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="dataSource" ref="dataSource0" />
              <property name="configLocation" value="classpath:sqlMapConfig.xml"/>
         </bean>
         <bean id="trafficInfoMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
              <property name="mapperInterface" value="org.shirdrn.mybatis.mapper.TrafficInfoMapper" />
              <property name="sqlSessionFactory" ref="sqlSessionFactory" />
         </bean>
         <bean id="trafficInfoService" class="org.shirdrn.mybatis.TrafficInfoService">
              <property name="trafficInfoMapper" ref="trafficInfoMapper" />
         </bean>
     
    </beans>

    简单说明一下:
    dataSource使用的Proxool连接池组件;
    sqlSessionFactory是Mybatis的SessionFactory,注入了前面获取到的dataSource,同时指定了Mybatis的总的映射配置文件classpath:sqlMapConfig.xml,属性名为configLocation;
    trafficInfoMapper直接由Spring的org.mybatis.spring.mapper.MapperFactoryBean进行代理,需要注入属性mapperInterface(即我们定义的SQL Mapper操作的接口类)和sqlSessionFactory(前面的SessionFactory实例);
    trafficInfoService是我们最终在其中进行调用的服务类,注入了我们定义的SQL Mapper接口类的实例trafficInfoMapper。

    • org.shirdrn.mybatis.TrafficInfoService服务类

    为简单起见,我们就不定义服务接口了,直接在该类中实现,调用SQL Mapper中预定义的SQL查询操作,实现代码如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package org.shirdrn.mybatis;
     
    import java.util.List;
    import java.util.Map;
     
    import org.shirdrn.mybatis.mapper.TrafficInfoMapper;
     
    public class TrafficInfoService {
     
         private TrafficInfoMapper trafficInfoMapper;
         
         public void setTrafficInfoMapper(TrafficInfoMapper trafficInfoMapper) {
              this.trafficInfoMapper = trafficInfoMapper;
         }
     
         public TrafficInfo getTrafficInfo(int id) {
              return trafficInfoMapper.getTrafficInfo(id);
         }
         
         public List<TrafficInfo> getTrafficInfoList(String domain) {
              return trafficInfoMapper.getTrafficInfoList(domain);
         }
         
         public List<TrafficInfo> getMultiConditionsList(String[] domains) {
              return trafficInfoMapper.getMultiConditionsList(domains);
         }
         
         List<TrafficInfo> getMapConditionsList(Map<String, Object> conditions) {
              return trafficInfoMapper.getMapConditionsList(conditions);
         }
     
    }

    按照上面的配置,我们就能够实现从单个字段的查询,到多个字段的组合复杂查询。可以通过与实际编写代码来控制这些逻辑相比较,使用Mybatis可能配置上相对复杂一些,但是或得到的好处是非常多的,如代码可维护性好,看起来配置比较直观,出错的几率会大大减小。实际上,如果熟练的这种配置方式,就会在实际开发过程中,更好地去处理更加复杂的统计查询条件的组合逻辑。

    测试用例

    测试用例可以检测我们上面的配置是否生效,实现代码:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    package org.shirdrn.mybatis;
     
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
     
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
     
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = { "classpath:/applicationContext*.xml" })
    public class TestTrafficInfoService {
     
         @Autowired
         private TrafficInfoService trafficInfoService;
     
         @Test
         public void getTraffic() {
              int id = 1196;
              TrafficInfo result = trafficInfoService.getTrafficInfo(id);
              System.out.println(result);
         }
         
         @Test
         public void getTrafficList() {
              String domain = "make-the-cut.com";
              List<TrafficInfo> results = trafficInfoService.getTrafficInfoList(domain);
              System.out.println(results);
         }
         
         @Test
         public void getMultiConditionsList() {
              String[] domains = new String[] {
                        "make.tv", " make-the-cut.com", "makgrills.com", "makino.com"
              };
              List<TrafficInfo> results = trafficInfoService.getMultiConditionsList(domains);
              System.out.println(results);
         }
         
         @Test
         public void getMapConditionsList() {
              String[] domains = new String[] {
                        "make.tv", " make-the-cut.com", "makgrills.com", "makino.com"
              };
              List<String> months = Arrays.asList(new String[] {
                        "201203", "201204", "201205"
              });
              Map<String, Object> conditions = new HashMap<String, Object>(2);
              conditions.put("domains", domains);
              conditions.put("months", months);
              List<TrafficInfo> results = trafficInfoService.getMapConditionsList(conditions);
              System.out.println(results);
         }
     
    }

    查询进阶

    这里,给出一个实际的例子,是对每日报表的一个统计实例,为简单起见,只拿出2张表做LEFT JOIN连接。这个需求,要求查询时可以对每个维度取过得查询条件值,如对于维度osName,值可以使包含Android、IOS,对于另一个维度statDate,可以取最近2天(昨天和前天),等等,并且,这些组合条件可有可无。
    对应的Mybatis映射配置文件,内容如下所示:

    001
    002
    003
    004
    005
    006
    007
    008
    009
    010
    011
    012
    013
    014
    015
    016
    017
    018
    019
    020
    021
    022
    023
    024
    025
    026
    027
    028
    029
    030
    031
    032
    033
    034
    035
    036
    037
    038
    039
    040
    041
    042
    043
    044
    045
    046
    047
    048
    049
    050
    051
    052
    053
    054
    055
    056
    057
    058
    059
    060
    061
    062
    063
    064
    065
    066
    067
    068
    069
    070
    071
    072
    073
    074
    075
    076
    077
    078
    079
    080
    081
    082
    083
    084
    085
    086
    087
    088
    089
    090
    091
    092
    093
    094
    095
    096
    097
    098
    099
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     
    <mapper namespace="org.shirdrn.data.mappers.DailyAppUserMapper">
         <resultMap id="dailyAppUserMap" type="DailyAppUser">
              <id property="id" column="id" />
              <result property="primaryCategoryId" column="primary_category_id" />
              <result property="primaryCategoryName" column="primary_category_name" />
              <result property="secondaryCategoryId" column="secondary_category_id" />
              <result property="secondaryCategoryName" column="secondary_category_name" />
              <result property="cooperationMode" column="cooperation_mode" />
              <result property="merchantId" column="merchant_id" />
              <result property="merchantName" column="merchant_name" />
              <result property="osName" column="osName" />
              <result property="channelId" column="channel_id" />
              <result property="channelName" column="channel_name" />
              <result property="version" column="version" />
              <result property="statDate" column="stat_date" />
              <result property="newUserOpen" column="new_user_open" />
              <result property="activeUserOpen" column="active_user_open" />
              <result property="activeUserPlay" column="active_user_play" />
              <result property="oldUserOpen" column="old_user_open" />
              <result property="oldUserPlay" column="old_user_play" />
              <result property="averageTime" column="average_time" />
              <result property="newUserAverageTime" column="new_user_average_time" />
              <result property="oldUserAverageTime" column="old_user_average_time" />
              <result property="newUserOpen2Retention" column="new_user_open_2retention" />
              <result property="newUserOpen3Retention" column="new_user_open_3retention" />
              <result property="newUserOpen7Retention" column="new_user_open_7retention" />
              <result property="newUserOpen15Retention" column="new_user_open_15retention" />
              <result property="newUserOpen30Retention" column="new_user_open_30retention" />
         </resultMap>
     
         <select id="getDailyAppUserListByPage" resultMap="dailyAppUserMap">
              <include refid="getDailyAppUserList"/>
              LIMIT #{offset}, #{limit}
         </select>
          
         <select id="getDailyAppUserListForReport" resultMap="dailyAppUserMap">
              <include refid="getDailyAppUserList"/>
         </select>
          
         <sql id="getDailyAppUserList" >
              SELECT
                   d.id AS id,
                   d.primary_category_id AS primary_category_id,
                   d.primary_category_name AS primary_category_name,
                   d.secondary_category_id AS secondary_category_id,
                   d.secondary_category_name AS secondary_category_name,
                   d.cooperation_mode AS cooperation_mode,
                   d.merchant_id AS merchant_id,
                   d.osName AS osName,
                   d.channel_id AS channel_id,
                   (CASE WHEN d.channel_name IS NOT NULL THEN d.channel_name ELSE d.channel_id END) AS channel_name,
                   d.version AS version,
                   d.stat_date AS stat_date,
                   d.new_user_open AS new_user_open,
                   d.new_user_play AS new_user_play,
                   d.active_user_open AS active_user_open,
                   d.active_user_play AS active_user_play,
                   d.old_user_open AS old_user_open,
                   d.old_user_play AS old_user_play,
                   d.average_time AS average_time,
                   d.new_user_average_time AS new_user_average_time,
                   d.old_user_average_time AS old_user_average_time,
                   d.new_user_open_2retention AS new_user_open_2retention,
                   d.new_user_open_3retention AS new_user_open_3retention,
                   d.new_user_open_7retention AS new_user_open_7retention,
                   d.new_user_open_15retention AS new_user_open_15retention,
                   d.new_user_open_30retention AS new_user_open_30retention,
                   d.uninstall_cnt AS uninstall_cnt,
                   m.merchant_name AS merchant_name
              FROM daily_app_user d
              LEFT JOIN merchant m ON d.merchant_id=m.id
              WHERE d.stat_date = #{statDate}
              <if test="osNames!=null">
                   AND d.osName IN
                   <foreach collection="osNames" index="index" item="osName" open=" (" separator="," close=")">
                        #{osName}
                   </foreach>
              </if>
              <if test="channelNames!=null">
                   AND
                   <foreach collection="channelNames" index="index" item="channelName" open=" (" separator=" OR " close=")">
                        (d.channel_name LIKE CONCAT('%', CONCAT(#{channelName}, '%')))
                   </foreach>
              </if>
              <if test="versions!=null">
                   AND d.version IN
                   <foreach collection="versions" index="index" item="version" open=" (" separator="," close=")">
                        #{version}
                   </foreach>
              </if>
              <if test="merchantNames!=null">
                   AND
                   <foreach collection="merchantNames" index="index" item="merchantName" open=" (" separator=" OR " close=")">
                        (m.merchant_name LIKE CONCAT('%', CONCAT(#{%merchantName%}, '%')))
                   </foreach>
              </if>
              <if test="primaryCategories!=null">
                   AND d.primary_category_id IN
                   <foreach collection="primaryCategories" index="index" item="primaryCategory" open=" (" separator="," close=")">
                        #{primaryCategory}
                   </foreach>
              </if>
              <if test="secondaryCategories!=null">
                   AND d.secondary_category_id IN
                   <foreach collection="secondaryCategories" index="index" item="secondaryCategory" open=" (" separator="," close=")">
                        #{secondaryCategory}
                   </foreach>
              </if>
              <if test="cooperationModes!=null">
                   AND d.cooperation_model IN
                   <foreach collection="cooperationModes" index="index" item="cooperationMode" open=" (" separator="," close=")">
                        #{cooperationMode}
                   </foreach>
              </if>
         </sql>
          
    </mapper>

    上述映射配置对应的Mapper定义,接口如下所示:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    package org.shirdrn.data.mappers;
     
    import java.util.List;
    import java.util.Map;
     
    import org.shirdrn.data.beans.DailyAppUser;
     
    public class DailyAppUserMapper {
     
         List<DailyAppUser> getDailyAppUserListByPage(Map<String, Object> conditions);
         List<DailyAppUser> getDailyAppUserListForReport(Map<String, Object> conditions);
    }

    需要说明的是,如果多个表,一定要设置好Mapper映射配置中每个select元素的resultMap属性,属性值就是前部分的resultMap定义的id。如果只从单个表查询数据,完全可以使用resultType,对应resultMap元素中配置的type属性所指定的别名。
    实际上,我们需要通过Map来传递参数,也就是把查询的条件值都收集起来,然后放到Map中,示例如下:

    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Map<String, Object> conditions = new HashMap<String, Object>();
    if(osNames != null) {
         conditions.put(DailyAppUserMapper.KEY_OS_NAMES, osNames);
    }
    if(channelNames != null) {
         conditions.put(DailyAppUserMapper.KEY_CHANNEL_NAMES, channelNames);
    }
    if(versions != null) {
         conditions.put(DailyAppUserMapper.KEY_VERSIONS, versions);
    }
    if(merchantNames != null) {
         conditions.put(DailyAppUserMapper.KEY_MERCHANT_NAMES, merchantNames);
    }
    if(primaryCategories != null) {
         conditions.put(DailyAppUserMapper.KEY_PRIMARY_CATEGORIES, primaryCategories);
    }
    if(secondaryCategories != null) {
         conditions.put(DailyAppUserMapper.KEY_SECONDARY_CATEGORIES, secondaryCategories);
    }
    if(cooperationModes != null) {
         conditions.put(ChannelDayMapper.KEY_COOPERATION_MODES, cooperationModes);
    }

    上面对应的DailyAppUserMapper中定义的一些Key常量名称,要和Mapper配置文件中foreach元素的collection属性值一致。

  • 相关阅读:
    Info.plist的秘密(raywenderlich笔记)
    我所理解的性能测试中负载测试与压力测试的区别
    seo优化
    localStorage,sessionStorage那些事儿
    浏览器cookie那些事儿
    JavaScript--Ajax请求
    javascript-理解原型、原型链
    React Native:从入门到原理
    知道这 20 个正则表达式,能让你少写 1,000 行代码
    程序猿进化必读:让App的运行速度与响应速度趋于一流(iOS)
  • 原文地址:https://www.cnblogs.com/zzwx/p/8820180.html
Copyright © 2011-2022 走看看