Springboot+mybatis的动态sql案例

139 篇文章 6 订阅

在报表类应用中,通常需要根据不同的维度去组合复杂的查询条件,然后构造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"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<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"?>

<beans xmlns="Index of /schema/beans"

     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="Index of /schema/context"

     xmlns:aop="Index of /schema/aop" xmlns:tx="Index of /schema/tx"

     xsi:schemaLocation="Index of /schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

Index of /schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

Index of /schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

Index of /schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

     <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>

     <!-- mybatis-spring – -->

     <!-- mybatis-spring – -->

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码海兴辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值