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屬性值一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM