MyBatis(十一):Mybatis 動態SQL語句完成多條件查詢


之前文章中對in的用法做過講解:《MyBatis(四):mybatis中使用in查詢時的注意事項

實際上對於多個參數的用法也是這是注意的:

多參&if判空&List集合判空&in用法

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @Select(value = {
            "<script>",
            " SELECT  `id`,`title` ",
            " FROM `tb_article` ",
            " WHERE `category_id`=#{article.categoryId} ",
            "   <if test='article.status!=null'>",
            "   AND `status` = #{article.status} ",
            "   </if>",
            "   <if test='typeList!=null and !typeList.isEmpty()'>",
            "       and `article_type` in",
            "        <foreach collection=\"typeList\" index=\"index\" item=\"item\" open=\"(\" separator=\",\" close=\")\">",
            "           #{item} ",
            "        </foreach>",
            "   </if>",
            "</script>"
            })
    @ResultMap(value = {"articleResultMap"})
    List<ArticlePo> queryByCondition(final @Param("article") ArticleModel article, final @Param("typeList") List<Integer> typeList);

1)上邊主要對普通參數判斷空用法:<if test='article.status!=null'>

2)集合判空的用法:<if test='typeList!=null and !typeList.isEmpty()'>

3)in的用法:<foreach collection=\"typeList\" index=\"index\" item=\"item\" open=\"(\" separator=\",\" close=\")\">";

4)多參數用法,實際上多個參數如果使用@SqlProvider方式是,在ArticleSqlProvider的類中方法中接收的參數對象為Map<String,Object>,該map集合中包含兩個對象:key:article的ArticleModel對象;key:typeList的List<Integer>對象。獲取方式:ArticleModel aritlce=(ArticleModel)map.get("aritcle");List<Integer> typeList=(List<Integer>)map.get("typeList");。

Mybatis使用POJO傳遞參數:

        @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
        @ResultMap("logResult")
        @Select(value={ 
                "<script>",
                "select * from `log` " ,
                "<where>" ,
                "     <if test=\"title!=null and title!=''\">" ,
                "          and `title` like CONCAT('%', #{title}, '%') " , 
                "     </if>" ,
                "     <if test=\"moduleType!=null \">" , 
                "          and `module_type`=#{moduleType} " , 
                "     </if>" , 
                "     <if test=\"operateType!=null \">" , 
                "          and `operate_type`=#{operateType} " , 
                "     </if>" , 
                "</where>",
                "</script>"
                })
        List<Log> getByPojo(Log log);

src/main/resources/mybatis-config.xml

<?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>
    <!-- 引用db.properties配置文件 -->
    <properties resource="jdbc.properties"/>
    <!--配置全局屬性-->
    <settings>
        <!-- 打開延遲加載的開關 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 將積極加載改為消極加載(即按需加載) -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 打開全局緩存開關(二級緩存)默認值就是 true -->
        <setting name="cacheEnabled" value="true"/>
        <!--使用jdbc的getGeneratekeys獲取自增主鍵值-->
        <setting name="useGeneratedKeys" value="true"/>
        <!--使用列別名替換別名  默認true select name as title form table; -->
        <setting name="useColumnLabel" value="true"/>
        <!--開啟駝峰命名轉換-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--打印sql日志-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <typeAliases>
        <package name="com.dx.test.model"/>
    </typeAliases>
    <!-- 
    元素類型為 "configuration" 的內容必須匹配 "
    (properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,
      plugins?,environments?,databaseIdProvider?,mappers?)"。
   -->
    <typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.ModuleType"/>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.OperateType"/>
    </typeHandlers>
    <!-- 對事務的管理和連接池的配置 -->
    <environments default="mysql_jdbc">
        <environment id="mysql_jdbc">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${name}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--
    <mappers>
        <mapper resource="resources/mapper/LogMapper.xml"/>
    </mappers>
    -->
    <mappers>
        <mapper class="com.dx.test.dao.LogMapper"></mapper>
    </mappers>
</configuration>
View Code

src/main/resources/log.properties

log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
View Code

src/main/resources/jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
name=root
password=123456
View Code

pom.xml

        <!--MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--MySql數據庫驅動 -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
View Code

LogMapper.java(Mybatis mapper類)

package com.dx.test.dao; 

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import com.dx.test.dao.sqlprovider.LogSqlProvider;
import com.dx.test.model.Log;
import com.dx.test.model.enums.ModuleType;
import com.dx.test.model.enums.OperateType;

@Mapper
public interface LogMapper {
    /**
     * 入庫日志
     * 
     * @param log 待入庫實體
     * @return 影響條數
     */
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    @InsertProvider(type = LogSqlProvider.class, method = "insert")
    public int insert(Log log);

    /**
     * 根據文章id,查詢日志詳情
     * 
     * @param id 日志id
     * @return 返回查詢到的日志詳情
     */
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @Results(id = "logResult", value = { 
            @Result(property = "id", column = "id", id = true),
            @Result(property = "title", column = "title"), 
            @Result(property = "content", column = "content"),
            @Result(property = "moduleType", column = "module_type", javaType = ModuleType.class),
            @Result(property = "operateType", column = "operate_type", javaType = OperateType.class),
            @Result(property = "dataId", column = "data_id"),
            @Result(property = "createUser", column = "create_user"),
            @Result(property = "createUserId", column = "create_user_id"),
            @Result(property = "createTime", column = "create_time")
            })
    @Select({ "select * from `log` where `id`=#{id}" })
    Log getById(@Param("id") Long id);
    
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select(value={ 
        "<script>",
        "select * from `log` " ,
        "<where>" ,
        "     <if test=\"title!=null and title!=''\">" ,
        "          and `title` like CONCAT('%', #{title}, '%') " , 
        "     </if>" ,
        "     <if test=\"moduleType!=null \">" , 
        "          and `module_type`=#{moduleType} " , 
        "     </if>" , 
        "     <if test=\"operateType!=null \">" , 
        "          and `operate_type`=#{operateType} " , 
        "     </if>" , 
        " </where>",
        "</script>"
        })
    List<Log> getByPojo(Log log);
    
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select(value={ 
            "<script>",
            "select * from `log` " ,
            "<where>" ,
            "     <if test=\"title!=null and title!=''\">" ,
            "          and `title` like CONCAT('%', #{title}, '%') " , 
            "     </if>" ,
            "     <if test=\"moduleType!=null \">" , 
            "          and `module_type`=#{moduleType} " , 
            "     </if>" , 
            "     <if test=\"operateType!=null \">" , 
            "          and `operate_type`=#{operateType} " , 
            "     </if>" , 
            " </where>",
            "</script>"
            })
    List<Log>  getByParameter(@Param("title") String title,@Param("moduleType") ModuleType moduleType,@Param("operateType") OperateType operateType);
    

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select(value={ 
            "<script>",
            "select * from `log` " ,
            "<where>" ,
            "     <if test=\"title!=null and title!=''\">" ,
            "          and `title` like CONCAT('%', #{title}, '%') " , 
            "     </if>" ,
            "     <if test=\"moduleType!=null \">" , 
            "          and `module_type`=#{moduleType} " , 
            "     </if>" , 
            "     <if test=\"operateType!=null \">" , 
            "          and `operate_type`=#{operateType} " , 
            "     </if>" , 
            " </where>",
            "</script>"
            })
    List<Log> getByMap(Map<String, Object> map);

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select({ 
        "<script>",
        "select * from `log` " ,
        "<where>" ,
        "    <choose> ",
        "        <when test=\"dataId!=null\">",
        "            and data_id=#{dataId}",
        "        </when>",
        "        <when test=\"id!=null\">",
        "            and id=#{id}",
        "        </when>",
        "        <otherwise>",
        "            and 1=1",
        "        </otherwise>",
        "    </choose>",
        "</where>" ,
        "</script>"})
    List<Log> getList(final Log log);

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
    @Update({ 
        "<script>",
        "update `log` " ,
        "<set>" ,
        "    <if test=\"dataId!=null\">",
        "        `data_id`=#{dataId},",
        "    </if>",
        "    <if test=\"title!=null\">",
        "        `title`=#{title},",
        "    </if>",
        "    <if test=\"content!=null\">",
        "        `content`=#{content} ",
        "    </if>",
        "</set>" ,
        " where id=#{id}",
        "</script>"})
    int update(final Log log);
    
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select({ "select * from `log` where `id`<#{log.id}" })
    List<Log> getListWithPager(@Param("log")Log log,@Param("pageNum") int pageNum,@Param("pageSize") int pageSize);
}
View Code

LogSqlProvider.java(LogMapper中使用sql代理類)

public class LogSqlProvider {
    /**
     * 生成插入日志SQL
     * @param log 日志實體
     * @return 插入日志SQL
     * */
    public String insert(Log log) {
        return new SQL() {
            {
                INSERT_INTO("log");
                INTO_COLUMNS("title", "module_type", "operate_type","data_id", "content", "create_time","create_user","create_user_id");
                INTO_VALUES("#{title}", "#{moduleType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}", "#{operateType,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler}","#{dataId}", "#{content}", "now()","#{createUser}","#{createUserId}");
            }
        }.toString();
    }
}
View Code

ModuleType.java(enum)

package com.dx.test.model.enums;

public enum ModuleType {
    Unkown(0),
    /**
     * 文章模塊
     */
    Article_Module(1),
    /**
     * 文章分類模塊
     **/
    Article_Category_Module(2),
    /**
     * 配置模塊
     */
    Settings_Module(3);
    
    private int value;

    ModuleType(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}
View Code

OperateType.java(enum)

package com.dx.test.model.enums;

public enum OperateType {
    /**
     * 如果0未占位,可能會出現錯誤。
     * */
    Unkown(0),
    /**
     * 新增
     */
    Create(1),
    /**
     * 修改
     */
    Modify(2),
    /**
     * 刪除
     */
    Delete(3),
    /**
     * 查看
     */
    View(4),
    /**
     * 作廢
     */
    UnUsed(5);

    private int value;

    OperateType(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}
View Code

Log.java(實體類)

package com.dx.test.model;

import java.util.Date;

import com.dx.test.model.enums.ModuleType;
import com.dx.test.model.enums.OperateType;
 
public class Log {
    private Long id; // 自增id
    private String title;// 日志msg
    private ModuleType moduleType;// 日志歸屬模塊
    private OperateType operateType; // 日志操作類型
    private String dataId; // 操作數據id
    private String content; // 日志內容簡介
    private Date createTime; // 新增時間
    private String createUser; // 新增人
    private String createUserId; // 新增人id

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public ModuleType getModuleType() {
        return moduleType;
    }

    public void setModuleType(ModuleType moduleType) {
        this.moduleType = moduleType;
    }

    public OperateType getOperateType() {
        return operateType;
    }

    public void setOperateType(OperateType operateType) {
        this.operateType = operateType;
    }

    public String getDataId() {
        return dataId;
    }

    public void setDataId(String dataId) {
        this.dataId = dataId;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(String createUser) {
        this.createUser = createUser;
    }

    public String getCreateUserId() {
        return createUserId;
    }

    public void setCreateUserId(String createUserId) {
        this.createUserId = createUserId;
    }

    @Override
    public String toString() {
        return "Log [id=" + id + ", title=" + title + ", moduleType=" + moduleType + ", operateType=" + operateType
                + ", dataId=" + dataId + ", content=" + content + ", createTime=" + createTime + ", createUser="
                + createUser + ", createUserId=" + createUserId + "]";
    }

}
View Code

MybatisTest.java(測試入口類)

package com.dx.test;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.dx.test.dao.LogMapper;
import com.dx.test.model.Log;
import com.dx.test.model.enums.ModuleType;
import com.dx.test.model.enums.OperateType;

public class MybatisTest {
    public static void main(String[] args) {
        InputStream config = null;
        try {
            config = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(config);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        LogMapper logMapper = sqlSession.getMapper(LogMapper.class);
        
        // choose:
        Log queryLog= new Log();
        queryLog.setDataId("1");
        List<Log> logByDataIdList=logMapper.getList(queryLog);
        for (Log item : logByDataIdList) {
            System.out.println(item);
        }
        
        System.out.println("==========================================================");
        String[] titleList = new String[] { "test", "test2", "awr", "a", "c", "tes", "ll", "gg", "dd", "22" };
        ModuleType[] moduleTypes = new ModuleType[] { ModuleType.Article_Category_Module, ModuleType.Article_Module,ModuleType.Settings_Module };
        OperateType[] operateTypes = new OperateType[] { OperateType.Create, OperateType.Delete, OperateType.Modify,OperateType.Modify, OperateType.UnUsed };
        for (int i = 0; i < 10; i++) {
            Log waitingInsertLog = new Log();

            waitingInsertLog.setTitle("log " + titleList[i]);
            waitingInsertLog.setContent("test content" + titleList[i]);
            waitingInsertLog.setCreateTime(new Date());
            waitingInsertLog.setCreateUser("test user");
            waitingInsertLog.setCreateUserId("test user id");
            waitingInsertLog.setDataId(String.valueOf(i + 100));
            waitingInsertLog.setModuleType(moduleTypes[i % 3]);
            waitingInsertLog.setOperateType(operateTypes[i % 5]);
            int newLogId = logMapper.insert(waitingInsertLog);
            System.out.println(waitingInsertLog.getId());
        }

        // set: 測試
        System.out.println("=========================================");
        Log waitingInsertLog = new Log();

        waitingInsertLog.setTitle("log");
        waitingInsertLog.setContent("test content");
        waitingInsertLog.setCreateTime(new Date());
        waitingInsertLog.setCreateUser("test user");
        waitingInsertLog.setCreateUserId("test user id");
        waitingInsertLog.setDataId("9999");
        waitingInsertLog.setModuleType(ModuleType.Article_Module);
        waitingInsertLog.setOperateType(OperateType.View);
        int newLogId = logMapper.insert(waitingInsertLog);

        System.out.println("insert result:"+logMapper.getById(waitingInsertLog.getId()));
        
        Log waitingUpdateLodLog=new Log();
        waitingUpdateLodLog.setId(waitingInsertLog.getId());
        waitingUpdateLodLog.setTitle("1111");
        waitingUpdateLodLog.setDataId("10000");
        waitingUpdateLodLog.setContent("test content test....");
        int updateStatus= logMapper.update(waitingUpdateLodLog);

        System.out.println("update result:"+logMapper.getById(waitingUpdateLodLog.getId()));
        
        // where:Pojo Parameter Map 三種傳遞參數的用法
        System.out.println("=========================================");

        String title = "test";
        ModuleType moduleType = ModuleType.Article_Category_Module;
        OperateType operateType = OperateType.Create;

        Log log = new Log();
        log.setTitle(title);
        log.setModuleType(moduleType);
        log.setOperateType(operateType);
        List<Log> logList = logMapper.getByPojo(log);
        for (Log item : logList) {
            System.out.println(item);
        }
        System.out.println("==========================================================");

        logList = logMapper.getByParameter(title, moduleType, operateType);
        for (Log item : logList) {
            System.out.println(item);
        }
        System.out.println("==========================================================");

        Map<String, Object> parameterMap = new HashMap<String, Object>();
        parameterMap.put("title", title);
        parameterMap.put("moduleType", moduleType);
        parameterMap.put("operateType", operateType);
        logList = logMapper.getByMap(parameterMap);
        for (Log item : logList) {
            System.out.println(item);
        }
        
        sqlSession.commit();
        sqlSession.close();
    }
}
View Code

備注:
1)這里moduleType、operateType都是enum類型,在mybatis-config.xml中已經注冊typeHandlers:

    <typeHandlers>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.ModuleType"/>
        <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.OperateType"/>
    </typeHandlers>

因此,這里完全不需要使用typeHandler、javaType屬性

{fieldName,typeHandler=org.apache.ibatis.type.EnumOrdinalTypeHandler,javaType=com.dx.test.model.enums.OperateType}

,當然如果加上這兩個屬性也不會拋出異常。
2)如果字段屬性類型為enum時,不能判定該值是否不為空字符串或者不為字符串0,這兩種用法都不正確,都會導致最終拋出異常:比如:

<if test=\"moduleType!=null and moduleType!='' \">
  and `module_type`=#{moduleType}
</if> 
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: invalid comparison: com.dx.test.model.enums.ModuleType and java.lang.String
### Cause: java.lang.IllegalArgumentException: invalid comparison: com.dx.test.model.enums.ModuleType and java.lang.String
        at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
        at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
        at com.sun.proxy.$Proxy13.getByPojo(Unknown Source)
        at com.dx.test.MybatisTest.main(MybatisTest.java:71)

<if test=\"moduleType!=null and moduleType!='0' \">
  and `module_type`=#{moduleType}
</if>
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.NumberFormatException: For input string: "Article_Category_Module"
### Cause: java.lang.NumberFormatException: For input string: "Article_Category_Module"
        at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
        at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
        at com.sun.proxy.$Proxy13.getByPojo(Unknown Source)
        at com.dx.test.MybatisTest.main(MybatisTest.java:71)

3)上邊例子中接收參數並未標注參數名稱,如果加上參數別名標注:List<Log> getByPojo(@Param("log") Log log);,這時在<script>中的sql中訪問相關屬性要訪問log對象下屬性:

        @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
        @ResultMap("logResult")
        @Select(value={ 
                "<script>",
                "select * from `log` " ,
                "<where>" ,
                "     <if test=\"log.title!=null and log.title!=''\">" ,
                "          and `title` like CONCAT('%', #{log.title}, '%') " , 
                "     </if>" ,
                "     <if test=\"log.moduleType!=null \">" , 
                "          and `module_type`=#{log.moduleType} " , 
                "     </if>" , 
                "     <if test=\"log.operateType!=null \">" , 
                "          and `operate_type`=#{log.operateType} " , 
                "     </if>" , 
                "</where>",
                "</script>"
                })
        List<Log> getByPojo(@Param("log") Log log);

否則會找不到相關屬性,拋出異常:

Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'title' not found. Available parameters are [log, param1]
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'title' not found. Available parameters are [log, param1]
        at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
        at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:139)
        at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:76)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
        at com.sun.proxy.$Proxy13.getByPojo(Unknown Source)
        at com.dx.test.MybatisTest.main(MybatisTest.java:71)

通過普通多個參數傳遞

        @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
        @ResultMap("logResult")
        @Select(value={ 
                        "<script>",
                        "select * from `log` " ,
                        "<where>" ,
                        "     <if test=\"title!=null and title!=''\">" ,
                        "          and `title` like CONCAT('%', #{title}, '%') " , 
                        "     </if>" ,
                        "     <if test=\"moduleType!=null \">" , 
                        "          and `module_type`=#{moduleType} " , 
                        "     </if>" , 
                        "     <if test=\"operateType!=null \">" , 
                        "          and `operate_type`=#{operateType} " , 
                        "     </if>" , 
                        "</where>",
                        "</script>"
                        })
        List<Log>  getByParameter(@Param("title") String title,@Param("moduleType") ModuleType moduleType,@Param("operateType") OperateType operateType);

這種方法比較容易理解,但是缺點需要逐個定義相關參數。

通過Map傳遞參數

        @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
        @ResultMap("logResult")
        @Select(value={ 
                        "<script>",
                        "select * from `log` " ,
                        "<where>" ,
                        "     <if test=\"title!=null and title!=''\">" ,
                        "          and `title` like CONCAT('%', #{title}, '%') " , 
                        "     </if>" ,
                        "     <if test=\"moduleType!=null \">" , 
                        "          and `module_type`=#{moduleType} " , 
                        "     </if>" , 
                        "     <if test=\"operateType!=null \">" , 
                        "          and `operate_type`=#{operateType} " , 
                        "     </if>" , 
                        "</where>",
                        "</script>"
                        })
        List<Log> getByMap(Map<String, Object> map);

備注:
1)這種方案由於傳遞的也是對象,和傳遞POJO一樣,如果不定義@Param在<script>內部直接方案相關屬性即可;
2)當在參數前定義了@Param時,比如:List<Log> getByMap(@Param("log") Map<String, Object> map);,此時訪問屬性時,必須加上map.前綴。

        @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
        @ResultMap("logResult")
        @Select(value={ 
                        "<script>",
                        "select * from `log` " ,
                        "<where>" ,
                        "     <if test=\"map.title!=null and map.title!=''\">" ,
                        "          and `title` like CONCAT('%', #{map.title}, '%') " , 
                        "     </if>" ,
                        "     <if test=\"map.moduleType!=null \">" , 
                        "          and `module_type`=#{map.moduleType} " , 
                        "     </if>" , 
                        "     <if test=\"map.operateType!=null \">" , 
                        "          and `operate_type`=#{map.operateType} " , 
                        "     </if>" , 
                        "</where>",
                        "</script>"
                        })
        List<Log> getByMap(@Param("map") Map<String, Object> map);

Trim替代Where、Set等

針對上邊的用法我們可以把getByMap(Map<String,Object> map)中Script中where使用trim來替代,例如:

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select(value={ 
            "<script>", 
            "select * from `log` " ,
            "<trim prefix=\"where\" prefixOverrides=\"and |or |abc \">" ,
            "     <if test=\"title!=null and title!=''\">" ,
            "          and `title` like CONCAT('%', #{title}, '%') " , 
            "     </if>" ,
            "     <if test=\"moduleType!=null \">" , 
            "          and `module_type`=#{moduleType} " , 
            "     </if>" , 
            "     <if test=\"operateType!=null \">" , 
            "          and `operate_type`=#{operateType} " , 
            "     </if>" , 
            "</trim>",
            "</script>"
            })
    List<Log> getByMap(Map<String, Object> map);

1)prefixOverrides:前綴覆蓋也就是說,where的后面緊跟着的是 and\or\abc,那么這些關鍵字都會被忽略
2)要注意 | 后面不能有空格,例如: |a 和| a 后面這個a和|之間有空格,會導致忽略失

Choose的用法:

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
    @ResultMap("logResult")
    @Select({ 
        "<script>",
        "select * from `log` " ,
        "<where>" ,
        "    <choose> ",
        "        <when test=\"dataId!=null\">",
        "            and data_id=#{dataId}",
        "        </when>",
        "        <when test=\"id!=null\">",
        "            and id=#{id}",
        "        </when>",
        "        <otherwise>",
        "            and 1=1",
        "        </otherwise>",
        "    </choose>",
        "</where>" ,
        "</script>"})
    List<Log> getList(final Log log);

注:choose相當於Java中的switch語句;當第一個when滿足時,就只執行第一個when中的條件。當when中的條件都不滿足時,就會執行默認的代碼塊,也就是otherwise中的語句。

Set的用法

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
    @Update({ 
        "<script>",
        "update `log` " ,
        "<set>" ,
        "    <if test=\"dataId!=null\">",
        "        `data_id`=#{dataId},",
        "    </if>",
        "    <if test=\"title!=null\">",
        "        `title`=#{title},",
        "    </if>",
        "    <if test=\"content!=null\">",
        "        `content`=#{content} ",
        "    </if>",
        "</set>" ,
        " where id=#{id}",
        "</script>"})
    int update(final Log log);

該set用法也可以使用trim來替代:

    @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
    @Update({ 
        "<script>",
        "update `log` " ,
        "<trim prefix=\"SET\" suffixOverrides=\", |abc \">" ,
        "    <if test=\"dataId!=null\">",
        "        `data_id`=#{dataId},",
        "    </if>",
        "    <if test=\"title!=null\">",
        "        `title`=#{title},",
        "    </if>",
        "    <if test=\"content!=null\">",
        "        `content`=#{content}, ",
        "    </if>",
        "</trim>" ,
        " where id=#{id}",
        "</script>"})
    int update(final Log log);

使用<trim>定義<set>規則:
1)suffixOverrides=", |abc",定義了無論是逗號","結尾還是"abc"結尾,都會被程序忽視,上面程序正常運行;
2)文中的abc規則是我添加的,原本只有過濾逗號","。

 


免責聲明!

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



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