MyBatis的動(dòng)態(tài)SQL與日志Log4J丧慈、SQL語(yǔ)句構(gòu)造器

一、MyBatis動(dòng)態(tài)SQL

  • 動(dòng)態(tài) SQL 是 MyBatis 的強(qiáng)大特性之一兴泥。如果你使用過(guò) JDBC 或其它類(lèi)似的框架工育,你應(yīng)該能理解根據(jù)不同條件拼接 SQL 語(yǔ)句有多痛苦,例如拼接時(shí)要確保不能忘記添加必要的空格搓彻,還要注意去掉列表最后一個(gè)列名的逗號(hào)如绸。利用動(dòng)態(tài) SQL,可以徹底擺脫這種痛苦旭贬。

  • 使用動(dòng)態(tài) SQL 并非一件易事怔接,但借助可用于任何 SQL 映射語(yǔ)句中的強(qiáng)大的動(dòng)態(tài) SQL 語(yǔ)言,MyBatis 顯著地提升了這一特性的易用性稀轨。

  • 如果你之前用過(guò) JSTL 或任何基于類(lèi) XML 語(yǔ)言的文本處理器扼脐,你對(duì)動(dòng)態(tài) SQL 元素可能會(huì)感覺(jué)似曾相識(shí)。在 MyBatis 之前的版本中奋刽,需要花時(shí)間了解大量的元素瓦侮。借助功能強(qiáng)大的基于 OGNL 的表達(dá)式,MyBatis 3 替換了之前的大部分元素佣谐,大大精簡(jiǎn)了元素種類(lèi)肚吏,現(xiàn)在要學(xué)習(xí)的元素種類(lèi)比原來(lái)的一半還要少。

    if

    • 使用動(dòng)態(tài) SQL 最常見(jiàn)情景是根據(jù)條件包含 where 子句的一部分狭魂。比如:
      <select id="findActiveBlogWithTitleLike" resultType="Blog">
        SELECT * FROM BLOG WHERE state = ‘ACTIVE’
        <if test="title != null">
          AND title like #{title}
        </if>
      </select>
      
    • 這條語(yǔ)句提供了可選的查找文本功能罚攀。如果不傳入 “title”吁断,那么所有處于 “ACTIVE” 狀態(tài)的 BLOG 都會(huì)返回;如果傳入了 “title” 參數(shù)坞生,那么就會(huì)對(duì) “title” 一列進(jìn)行模糊查找并返回對(duì)應(yīng)的 BLOG 結(jié)果仔役。
    • 通過(guò) “title” 和 “author” 兩個(gè)參數(shù)進(jìn)行可選搜索,只需要加入另一個(gè)條件即可是己。
      <select  id="findActiveBlogLike"  resultType="Blog">
          SELECT * FROM BLOG WHERE state = ‘ACTIVE’ 
        <if  test="title != null"> 
          AND title like #{title} 
        </if>
        <if  test="author != null and author.name != null">
          AND author_name like #{author.name}
        </if>
      </select>
      

    choose又兵、when、otherwise

    • MyBatis 提供了 choose 元素卒废,它有點(diǎn)像 Java 中的 switch 語(yǔ)句沛厨。傳入了 “title” 就按 “title” 查找,傳入了 “author” 就按 “author” 查找的情形摔认。若兩者都沒(méi)有傳入逆皮,就返回標(biāo)記為 featured 的 BLOG。
      <select id="findActiveBlogLike" resultType="Blog">
        SELECT * FROM BLOG WHERE state = ‘ACTIVE’
        <choose>
          <when test="title != null">
            AND title like #{title}
          </when>
          <when test="author != null and author.name != null">
            AND author_name like #{author.name}
          </when>
          <otherwise>
            AND featured = 1
          </otherwise>
        </choose>
      </select>
      

    trim参袱、where电谣、set

    • 將 “state = ‘ACTIVE’” 設(shè)置成動(dòng)態(tài)條件。
      <select  id="findActiveBlogLike"  resultType="Blog">
        SELECT * FROM BLOG WHERE
        <if  test="state != null"> 
          state = #{state} 
        </if> 
        <if  test="title != null"> 
          AND title like #{title}
        </if>  
        <if  test="author != null and author.name != null">
          AND author_name like #{author.name}
        </if>  
      </select>
      
    • 如果沒(méi)有匹配的條件抹蚀,最終這條 SQL 會(huì)變成這樣:SELECT * FROM BLOG WHERE剿牺,這會(huì)導(dǎo)致查詢(xún)失敗。如果匹配的只是第二個(gè)條件环壤,這條 SQL 會(huì)是這樣:
      SELECT * FROM BLOG WHERE AND title like ‘someTitle’晒来,這個(gè)查詢(xún)也會(huì)失敗。
    • MyBatis 有一個(gè)簡(jiǎn)單且適合大多數(shù)場(chǎng)景的解決辦法郑现。而在其他場(chǎng)景中湃崩,可以對(duì)其進(jìn)行自定義以符合需求。
      <select  id="findActiveBlogLike"  resultType="Blog">
        SELECT * FROM BLOG
        <where> 
          <if  test="state != null">
            state = #{state}
          </if> 
          <if  test="title != null">
            AND title like #{title}
          </if>
          <if  test="author != null and author.name != null">
            AND author_name like #{author.name}
          </if>
        </where>
      </select>
      
    • where 元素只會(huì)在子元素返回任何內(nèi)容的情況下才插入 “WHERE” 子句接箫。而且攒读,若子句的開(kāi)頭為 “AND” 或 “OR”,where 元素也會(huì)將它們?nèi)コ形H绻?where 元素與你期望的不太一樣整陌,你也可以通過(guò)自定義 trim 元素來(lái)定制 where 元素的功能。
      <trim  prefix="WHERE"  prefixOverrides="AND |OR "> ... </trim>
      
    • prefixOverrides 屬性會(huì)忽略通過(guò)管道符分隔的文本序列瞎领。上述例子會(huì)移除所有 prefixOverrides 屬性中指定的內(nèi)容,并且插入 prefix 屬性中指定的內(nèi)容随夸。用于動(dòng)態(tài)更新語(yǔ)句的類(lèi)似解決方案叫做 set九默。set 元素可以用于動(dòng)態(tài)包含需要更新的列,忽略其它不更新的列宾毒。
      <update  id="updateAuthorIfNecessary">
        update Author
        <set>
          <if  test="username != null"> username=#{username}, </if>
          <if  test="password != null"> password=#{password}, </if>
          <if  test="email != null"> email=#{email}, </if>
          <if  test="bio != null"> bio=#{bio} </if>
        </set>
        where id=#{id}
      </update>
      
    • 與 set 元素等價(jià)的自定義 trim 元素
      <trim  prefix="SET"  suffixOverrides=","> ... </trim>
      

    foreach

    • 動(dòng)態(tài) SQL 的另一個(gè)常見(jiàn)使用場(chǎng)景是對(duì)集合進(jìn)行遍歷(尤其是在構(gòu)建 IN 條件語(yǔ)句的時(shí)候)驼修。
      <select  id="selectPostIn"  resultType="domain.blog.Post">
        SELECT * FROM POST P WHERE ID in
        <foreach  item="item"  index="index"  collection="list"  open="("  separator=","  close=")">
           #{item}
        </foreach>
      </select>
      
    • foreach 元素的功能非常強(qiáng)大,它允許你指定一個(gè)集合,聲明可以在元素體內(nèi)使用的集合項(xiàng)(item)和索引(index)變量乙各。它也允許你指定開(kāi)頭與結(jié)尾的字符串以及集合項(xiàng)迭代之間的分隔符墨礁。

    script

    • 要在帶注解的映射器接口類(lèi)中使用動(dòng)態(tài) SQL,可以使用 script 元素耳峦。
       @Update({"<script>",  "update Author",  "  <set>",  " 
      <if test='username != null'>username=#{username},</if>",  "
      <if test='password != null'>password=#{password},</if>",  "
      <if test='email != null'>email=#{email},</if>",  " 
      <if test='bio != null'>bio=#{bio}</if>",  "
      </set>",  "where id=#{id}",  "</script>"}) 
      void updateAuthorValues(Author author);
      

    bind

    • bind 元素允許你在 OGNL 表達(dá)式以外創(chuàng)建一個(gè)變量恩静,并將其綁定到當(dāng)前的上下文。
      <select  id="selectBlogsLike"  resultType="Blog">
        <bind  name="pattern"  value="'%' + _parameter.getTitle() + '%'"  />
        SELECT * FROM BLOG WHERE title LIKE #{pattern}
      </select>
      

    多數(shù)據(jù)庫(kù)支持

    • 如果配置了 databaseIdProvider蹲坷,你就可以在動(dòng)態(tài)代碼中使用名為 “_databaseId” 的變量來(lái)為不同的數(shù)據(jù)庫(kù)構(gòu)建特定的語(yǔ)句驶乾。
      <insert  id="insert">
        <selectKey  keyProperty="id"  resultType="int"  order="BEFORE">
          <if  test="_databaseId == 'oracle'">
            select seq_users.nextval from dual
          </if>
          <if  test="_databaseId == 'db2'">
            select nextval for seq_users from sysibm.sysdummy1"
          </if>
        </selectKey>
          insert into users values (#{id}, #{name})
      </insert>
      

    動(dòng)態(tài) SQL 中的插入腳本語(yǔ)言

    • MyBatis 從 3.2 版本開(kāi)始支持插入腳本語(yǔ)言,這允許你插入一種語(yǔ)言驅(qū)動(dòng)循签,并基于這種語(yǔ)言來(lái)編寫(xiě)動(dòng)態(tài) SQL 查詢(xún)語(yǔ)句级乐。
      public  interface  LanguageDriver  {
          ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject,  BoundSql boundSql); 
          SqlSource createSqlSource(Configuration configuration,  XNode script,  Class<?> parameterType); 
          SqlSource createSqlSource(Configuration configuration,  String script,  Class<?> parameterType);  
      }
      
    • 實(shí)現(xiàn)自定義語(yǔ)言驅(qū)動(dòng)后,你就可以在 mybatis-config.xml 文件中將它設(shè)置為默認(rèn)語(yǔ)言:
      <typeAliases>
        <typeAlias  type="org.sample.MyLanguageDriver"  alias="myLanguage"/>
      </typeAliases>
      <settings>
        <setting  name="defaultScriptingLanguage"  value="myLanguage"/>
      </settings>
      
    • 你也可以使用 lang 屬性為特定的語(yǔ)句指定語(yǔ)言:
      <select  id="selectBlog"  lang="myLanguage">
        SELECT * FROM BLOG
      </select>
      
    • 在你的 mapper 接口上添加 @Lang 注解:
      public  interface  Mapper  {
          @Lang(MyLanguageDriver.class)
          @Select("SELECT * FROM BLOG")
          List<Blog> selectBlog();
      }
      

二县匠、MyBatis緩存

  • 默認(rèn)情況下风科,只啟用了本地的會(huì)話(huà)緩存(SqlSession),它僅僅對(duì)一個(gè)會(huì)話(huà)中的數(shù)據(jù)進(jìn)行緩存乞旦,會(huì)話(huà)緩存也稱(chēng)為一級(jí)緩存丐重。二級(jí)緩存是全局緩存(SqlSessionFactory),需要手動(dòng)開(kāi)啟:在SQL映射文件中添加一行:<cache/>

  • 緩存的清除策略:

    • LRU(Least Recently Uses):最近最少使用杆查,移除最長(zhǎng)時(shí)間不被使用的對(duì)象
    • FIFO(First In First Out):先進(jìn)先出扮惦,按照對(duì)象進(jìn)入緩存的順序來(lái)移除他們。這也是數(shù)據(jù)結(jié)構(gòu)中隊(duì)列(Queue)的元素存取方式亲桦。
    • SOFT:軟引用崖蜜,基于來(lái)及回收器狀態(tài)和軟引用規(guī)則移除對(duì)象
    • WEAK:弱引用,更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則來(lái)移除對(duì)象
  • 默認(rèn)的清除策略是LRU

三客峭、日志 log4j

  • Mybatis 通過(guò)使用內(nèi)置的日志工廠提供日志功能豫领。內(nèi)置日志工廠將會(huì)把日志工作委托給下面的實(shí)現(xiàn)之一:
    • SLF4J
    • Apache Commons Logging
    • Log4j 2
    • Log4j
    • JDK logging
  • MyBatis 內(nèi)置日志工廠會(huì)基于運(yùn)行時(shí)檢測(cè)信息選擇日志委托實(shí)現(xiàn)。它會(huì)(按上面羅列的順序)使用第一個(gè)查找到的實(shí)現(xiàn)舔琅。當(dāng)沒(méi)有找到這些實(shí)現(xiàn)時(shí)等恐,將會(huì)禁用日志功能。
  • 可以在mybatis配置文件中設(shè)置日志選項(xiàng)备蚓,可選的值有:SLF4J课蔬、LOG4J、LOG4J2郊尝、JDK_LOGGING二跋、COMMONS_LOGGING、STDOUT_LOGGING流昏、NO_LOGGING扎即,或者是實(shí)現(xiàn)了 org.apache.ibatis.logging.Log 接口吞获,且構(gòu)造方法以字符串為參數(shù)的類(lèi)完全限定名。
  • 全局日志配置可以配置打印的日志級(jí)別谚鄙,日志的輸出對(duì)象各拷。日志的四個(gè)級(jí)別:error、warn闷营、info烤黍、debug,優(yōu)先級(jí)從高到低粮坞;如果設(shè)置為error蚊荣,只打印error信息,如果設(shè)置為debug莫杈,所有級(jí)別的信息都會(huì)打踊ダ;只會(huì)打印大于等于這個(gè)級(jí)別的日志筝闹。stdout是標(biāo)準(zhǔn)輸出:打印在控制臺(tái)媳叨。還可以將日志輸出到文件,最后一行指定了最小輸出寬度以及對(duì)齊方式关顷。
  • MyBatis日志配置設(shè)置了跟蹤的包糊秆、類(lèi)或方法,對(duì)特定包下的類(lèi)议双、特定類(lèi)痘番、特定方法才會(huì)打印日志。

四平痰、測(cè)試動(dòng)態(tài)SQL和日志log4j

  • 添加junit汞舱,mysql,mybatis 以及 log4j 的依賴(lài)到 pom.xml 中

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com</groupId>
        <artifactId>MyBatisSQL</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.19</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.6</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.6</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
    </project>
    
  • Mybatis.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>
        <properties resource="db.properties">
        </properties>
        <settings>
            <setting name="logImpl" value="LOG4J"/>
        </settings>
        <typeAliases>
            <package name="com.pojo" />
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${user}"/>
                    <property name="password" value="${pass}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>    
            <package name="com.pojo" />
        </mappers>
    </configuration>
    
  • db.properties

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3307/mysqls?serverTimezone=UTC
    user=root
    pass=123456
    
  • log4j.properties

    log4j.rootLogger=debug, stdout, F
    # MyBatis 日志配置
    log4j.logger.com.qfedu=TRACE
    # 控制臺(tái)輸出
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%6p [%t] - %m%n
    log4j.appender.F = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.F.File =myproj.log
    log4j.appender.F.Append = true
    log4j.appender.F.Threshold = DEBUG
    log4j.appender.F.layout=org.apache.log4j.PatternLayout
    log4j.appender.F.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss}-[%p %F\:%L]  %m%n
    
  • User.java

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private int uid;
        private String username;
        private String password;
        private int age;
        private String addr;
    }
    
  • IUserDao.java

    public interface IUserDao {
        @Select("select * from user")
        List<User> getAll();
    }
    
  • IUserDao.xml

    <?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="com.pojo.IUserDao">
        <sql id="all">
            select * from user
        </sql>
        <select id="selectAll" resultType="user">
            <include refid="all"/>
        </select>
        <select id="selectUserByUid" resultType="user">
            <include refid="all"/>
            where uid = #{uid}
        </select>
        <select id="selectIf" resultType="user">
            <include refid="all"/>
            <where>
                <if test="username != null">
                    username = #{username}
                </if>
                <if test="password != null">
                    and password = #{password}
                </if>
            </where>
        </select>
        <select id="selectIn" resultType="user">
            <include refid="all" />
           <where>
                uid in
                <foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
                    #{id}
                </foreach>
            </where>
        </select>
    </mapper>
    
  • SessionUtils.java

    public class SessionUtils {
        private static SqlSession mSession = null;
        private static SqlSessionFactory mFactory = null;
        static {
            try {
                mFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
            } catch (IOException e) {
                  e.printStackTrace();
            }
        }
        /**
         * 獲取SqlSession對(duì)象
         * @return
         */
        public static SqlSession getSession(){
            mSession = mFactory.openSession(true);
            return mSession;
        }
        /**
         * 關(guān)閉SqlSession對(duì)象
         * @param session 要關(guān)閉的SqlSession對(duì)象
         */
        public static void closeSession(SqlSession session){
            if(session != null){
                session.close();
                session = null;
            }
        }
    }
    
  • TestLog.java

    public class TestLog {
        private SqlSession session = null;
        @Before
        public void setUp() {
            session = SessionUtils.getSession();
        }
        @After
        public void tearDown() {
            SessionUtils.closeSession(session);
        }
        @Test
        public void testLog(){
            IUserDao userDao = session.getMapper(IUserDao.class);
            List<User> list = userDao.getAll();
            for (User u : list) {
                System.out.println(u);
            }
        }
    }
    
  • 測(cè)試結(jié)果

     DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
     DEBUG [main] - Class not found: org.jboss.vfs.VFS
     DEBUG [main] - JBoss 6 VFS API is not available in this environment.
     DEBUG [main] - Class not found: org.jboss.vfs.VirtualFile
     DEBUG [main] - VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
     DEBUG [main] - Using VFS adapter org.apache.ibatis.io.DefaultVFS
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Reader entry: IUserDao.class
     DEBUG [main] - Reader entry: User.class
     DEBUG [main] - Listing file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Reader entry: ????   4 ?? 
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Reader entry: ????   4 n   ? Q     ? R     ? S     ? T     ? U? V
     DEBUG [main] - Checking to see if class com.pojo.IUserDao matches criteria [is assignable to Object]
     DEBUG [main] - Checking to see if class com.pojo.User matches criteria [is assignable to Object]
     DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Reader entry: IUserDao.class
     DEBUG [main] - Reader entry: User.class
     DEBUG [main] - Listing file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Reader entry: ????   4 ?? 
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Reader entry: ????   4 n   ? Q     ? R     ? S     ? T     ? U? V
     DEBUG [main] - Checking to see if class com.pojo.IUserDao matches criteria [is assignable to Object]
     DEBUG [main] - Checking to see if class com.pojo.User matches criteria [is assignable to Object]
     DEBUG [main] - Opening JDBC Connection
     DEBUG [main] - Created connection 2030538903.
     DEBUG [main] - ==>  Preparing: select * from user 
     DEBUG [main] - ==> Parameters: 
     DEBUG [main] - <==      Total: 13
      User(uid=1, username=aaa, password=111111, age=10, addr=aaaa)
      User(uid=2, username=bbb, password=222222, age=11, addr=aaaa)
      User(uid=3, username=ccc, password=333333, age=12, addr=aaaa)
      User(uid=4, username=ddd, password=444444, age=13, addr=aaaa)
      User(uid=5, username=eee, password=555555, age=14, addr=aaaa)
      User(uid=6, username=fff, password=666666, age=15, addr=aaaa)
      User(uid=7, username=ggg, password=777777, age=16, addr=aaaa)
      User(uid=8, username=hhh, password=888888, age=17, addr=aaaa)
      User(uid=9, username=iii, password=999999, age=18, addr=aaaa)
      User(uid=10, username=jjj, password=000000, age=19, addr=aaaa)
      User(uid=11, username=kkk, password=000000, age=20, addr=aaaa)
      User(uid=12, username=lkt, password=888888, age=20, addr=suzhou)
      User(uid=15, username=ABC, password=111111, age=20, addr=南京)
     DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@79079097]
     DEBUG [main] - Returned connection 2030538903 to pool.
    
  • TestUserSQL.java

    public class TestUserSQL {
        private SqlSession session = null;
        @Before
        public void setUp() { session = SessionUtils.getSession(); }
        @After
        public void tearDown() { SessionUtils.closeSession(session); }
        @Test
        public void testGetAllUsers() {
            List<User> list = session.selectList("com.pojo.IUserDao.selectAll");
            for (User u : list) {
                System.out.println(u);
            }
        }
        @Test
        public void testGetAllUsersByUid() {
            User u = session.selectOne("com.pojo.IUserDao.selectUserByUid", 1);
            System.out.println(u);
        }
        @Test
        public void testGetUserByIf(){
            Map<String, Object> map = new HashMap<>();
            map.put("password", "333333");
            List<User> list = session.selectList("com.pojo.IUserDao.selectIf", map);
            for (User u : list) {
              System.out.println(u);
            }
        }
        @Test
        public void testGetUsersByIn(){
            List<Integer> ids = new ArrayList<>();
            Collections.addAll(ids, 1, 2, 3, 4, 100);
            System.out.println(ids);
            Map<String, Object> map = new HashMap<>();
            map.put("ids", ids);
            List<User> list = session.selectList("com.pojo.IUserDao.selectIn", map);
            for (User u : list) {
                System.out.println(u);
            }
        }
    }
    
  • 測(cè)試結(jié)果

     DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
     DEBUG [main] - Class not found: org.jboss.vfs.VFS
     DEBUG [main] - JBoss 6 VFS API is not available in this environment.
     DEBUG [main] - Class not found: org.jboss.vfs.VirtualFile
     DEBUG [main] - VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
     DEBUG [main] - Using VFS adapter org.apache.ibatis.io.DefaultVFS
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Reader entry: IUserDao.class
     DEBUG [main] - Reader entry: IUserDao.xml
     DEBUG [main] - Reader entry: User.class
     DEBUG [main] - Listing file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Reader entry: ????   4 ?? 
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.xml
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.xml
     DEBUG [main] - Reader entry: <?xml version="1.0" encoding="UTF-8" ?>
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Reader entry: ????   4 n   ? Q     ? R     ? S     ? T     ? U? V
     DEBUG [main] - Checking to see if class com.pojo.IUserDao matches criteria [is assignable to Object]
     DEBUG [main] - Checking to see if class com.pojo.User matches criteria [is assignable to Object]
     DEBUG [main] - Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - PooledDataSource forcefully closed/removed all connections.
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Reader entry: IUserDao.class
     DEBUG [main] - Reader entry: IUserDao.xml
     DEBUG [main] - Reader entry: User.class
     DEBUG [main] - Listing file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.class
     DEBUG [main] - Reader entry: ????   4 ?? 
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.xml
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/IUserDao.xml
     DEBUG [main] - Reader entry: <?xml version="1.0" encoding="UTF-8" ?>
     DEBUG [main] - Find JAR URL: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Not a JAR: file:/F:/IDEA-Work/MyBatisSQLAndLog4J/target/classes/com/pojo/User.class
     DEBUG [main] - Reader entry: ????   4 n   ? Q     ? R     ? S     ? T     ? U? V
     DEBUG [main] - Checking to see if class com.pojo.IUserDao matches criteria [is assignable to Object]
     DEBUG [main] - Checking to see if class com.pojo.User matches criteria [is assignable to Object]
     DEBUG [main] - Opening JDBC Connection
     DEBUG [main] - Created connection 515715487.
     DEBUG [main] - ==>  Preparing: select * from user 
     DEBUG [main] - ==> Parameters: 
     DEBUG [main] - <==      Total: 13
      User(uid=1, username=aaa, password=111111, age=10, addr=aaaa)
      User(uid=2, username=bbb, password=222222, age=11, addr=aaaa)
      User(uid=3, username=ccc, password=333333, age=12, addr=aaaa)
      User(uid=4, username=ddd, password=444444, age=13, addr=aaaa)
      User(uid=5, username=eee, password=555555, age=14, addr=aaaa)
      User(uid=6, username=fff, password=666666, age=15, addr=aaaa)
      User(uid=7, username=ggg, password=777777, age=16, addr=aaaa)
      User(uid=8, username=hhh, password=888888, age=17, addr=aaaa)
      User(uid=9, username=iii, password=999999, age=18, addr=aaaa)
      User(uid=10, username=jjj, password=000000, age=19, addr=aaaa)
      User(uid=11, username=kkk, password=000000, age=20, addr=aaaa)
      User(uid=12, username=lkt, password=888888, age=20, addr=suzhou)
      User(uid=15, username=ABC, password=111111, age=20, addr=南京)
     DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1ebd319f]
     DEBUG [main] - Returned connection 515715487 to pool.
     DEBUG [main] - Opening JDBC Connection
     DEBUG [main] - Checked out connection 515715487 from pool.
     DEBUG [main] - ==>  Preparing: select * from user where uid = ? 
     DEBUG [main] - ==> Parameters: 1(Integer)
     DEBUG [main] - <==      Total: 1
      User(uid=1, username=aaa, password=111111, age=10, addr=aaaa)
     DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1ebd319f]
     DEBUG [main] - Returned connection 515715487 to pool.
     DEBUG [main] - Opening JDBC Connection
     DEBUG [main] - Checked out connection 515715487 from pool.
     DEBUG [main] - ==>  Preparing: select * from user WHERE password = ? 
     DEBUG [main] - ==> Parameters: 333333(String)
     DEBUG [main] - <==      Total: 1
      User(uid=3, username=ccc, password=333333, age=12, addr=aaaa)
     DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1ebd319f]
     DEBUG [main] - Returned connection 515715487 to pool.
      [1, 2, 3, 4, 100]
     DEBUG [main] - Opening JDBC Connection
     DEBUG [main] - Checked out connection 515715487 from pool.
     DEBUG [main] - ==>  Preparing: select * from user WHERE uid in ( ? , ? , ? , ? , ? ) 
     DEBUG [main] - ==> Parameters: 1(Integer), 2(Integer), 3(Integer), 4(Integer), 100(Integer)
     DEBUG [main] - <==      Total: 4
      User(uid=1, username=aaa, password=111111, age=10, addr=aaaa)
      User(uid=2, username=bbb, password=222222, age=11, addr=aaaa)
      User(uid=3, username=ccc, password=333333, age=12, addr=aaaa)
      User(uid=4, username=ddd, password=444444, age=13, addr=aaaa)
     DEBUG [main] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1ebd319f]
     DEBUG [main] - Returned connection 515715487 to pool.
    

五宗雇、Mybatis的SQL語(yǔ)句構(gòu)造器

  • MyBatis 3 提供了方便的工具類(lèi)來(lái)幫助解決該問(wèn)題昂芜。使用SQL類(lèi),簡(jiǎn)單地創(chuàng)建一個(gè)實(shí)例來(lái)調(diào)用方法生成SQL語(yǔ)句赔蒲。
  • SQL 語(yǔ)句生成器列表
方法 描述
SELECT(字串) SELECT(字符串...) 開(kāi)始或插入到選擇子句泌神。可以被多次調(diào)用舞虱,參數(shù)也會(huì)添加到SELECT子句欢际。參數(shù)通常使用逗號(hào)分隔的列名和別名列表,但也可以是數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序接受的任意類(lèi)型砾嫉。
SELECT_DISTINCT(字符串) SELECT_DISTINCT(字符串...) 開(kāi)始或插入到SELECT子句幼苛,也可以插入DISTINCT關(guān)鍵字到生成的查詢(xún)語(yǔ)句中』拦危可以被多次調(diào)用舶沿,參數(shù)也會(huì)添加到SELECT子句。參數(shù)通常使用逗號(hào)分隔的列名和別名列表配并,但也可以是數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序接受的任意類(lèi)型括荡。
FROM(字符串) FROM(字符串...) 開(kāi)始或插入到FROM子句「刃可以被多次調(diào)用畸冲,參數(shù)也會(huì)添加到FROM子句。參數(shù)通常是表名或別名观腊,也可以是數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序接受的任意類(lèi)型邑闲。
JOIN(字符串) JOIN(字符串...) INNER_JOIN(字符串) INNER_JOIN(字符串...) LEFT_OUTER_JOIN(字符串) LEFT_OUTER_JOIN(字符串...) RIGHT_OUTER_JOIN(字符串) RIGHT_OUTER_JOIN(字符串...) 基于調(diào)用的方法,添加新的合適類(lèi)型的JOIN子句梧油。參數(shù)可以包含由列命和加入的條件組合成標(biāo)準(zhǔn)的加入苫耸。
WHERE(String) WHERE(String...) 插入新的 WHERE子句條件, 由AND鏈接儡陨⊥首樱可以多次被調(diào)用,每次都由AND來(lái)鏈接新條件骗村。使用 OR() 來(lái)分隔OR嫌褪。
OR() 使用OR來(lái)分隔當(dāng)前的 WHERE子句條件。 可以被多次調(diào)用胚股,但在一行中多次調(diào)用或生成不穩(wěn)定的SQL笼痛。
AND() 使用AND來(lái)分隔當(dāng)前的 WHERE子句條件。 可以被多次調(diào)用琅拌,但在一行中多次調(diào)用或生成不穩(wěn)定的SQL缨伊。因?yàn)?WHEREHAVING 二者都會(huì)自動(dòng)鏈接 AND, 這是非常罕見(jiàn)的方法,只是為了完整性才被使用财忽。
GROUP_BY(String) GROUP_BY(String...) 插入新的 GROUP BY子句元素倘核,由逗號(hào)連接。 可以被多次調(diào)用即彪,每次都由逗號(hào)連接新的條件紧唱。
HAVING(String) HAVING(String...) 插入新的 HAVING子句條件。 由AND連接隶校÷┮妫可以被多次調(diào)用,每次都由AND來(lái)連接新的條件深胳。使用 OR() 來(lái)分隔OR绰疤。
ORDER_BY(String) ORDER_BY(String...) 插入新的 ORDER BY子句元素, 由逗號(hào)連接舞终∏崆欤可以多次被調(diào)用癣猾,每次由逗號(hào)連接新的條件。
LIMIT(String) LIMIT(int) 附加一個(gè)LIMIT子句余爆。與SELECT()纷宇,UPDATE()DELETE()一起使用時(shí),此方法有效蛾方。并且此方法設(shè)計(jì)為在使用SELECT()時(shí)與OFFSET()一起使用像捶。
OFFSET(String) OFFSET(long) 附加一個(gè)OFFSET子句。與SELECT()一起使用時(shí)桩砰,此方法有效拓春。該方法設(shè)計(jì)為與LIMIT()一起使用。
OFFSET_ROWS(String) OFFSET_ROWS(long) 附加一個(gè)OFFSET n ROWS子句亚隅。與SELECT()一起使用時(shí)硼莽,此方法有效。該方法旨在與FETCH_FIRST_ROWS_ONLY()一起使用
FETCH_FIRST_ROWS_ONLY(String) FETCH_FIRST_ROWS_ONLY(int) 追加FETCH FIRST n ROWS ONLY子句枢步。與SELECT()一起使用時(shí)沉删,此方法有效。此方法設(shè)計(jì)為與OFFSET_ROWS()一起使用醉途。
DELETE_FROM(String) 開(kāi)始一個(gè)delete語(yǔ)句并指定需要從哪個(gè)表刪除的表名矾瑰。通常它后面都會(huì)跟著WHERE語(yǔ)句
INSERT_INTO(String) 開(kāi)始一個(gè)insert語(yǔ)句并指定需要插入數(shù)據(jù)的表名。后面都會(huì)跟著一個(gè)或者多個(gè)VALUES() or INTO_COLUMNS() and INTO_VALUES()隘擎。
SET(String) SET(String...) 針對(duì)update語(yǔ)句殴穴,插入到"set"列表中
UPDATE(String) 開(kāi)始一個(gè)update語(yǔ)句并指定需要更新的表明。后面都會(huì)跟著一個(gè)或者多個(gè)SET()货葬,通常也會(huì)有一個(gè)WHERE()采幌。
VALUES(String, String) 插入到insert語(yǔ)句中。第一個(gè)參數(shù)是要插入的列名震桶,第二個(gè)參數(shù)則是該列的值休傍。
INTO_COLUMNS(String...) 插入語(yǔ)句的形式是:INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
INTO_VALUES(String...) 插入語(yǔ)句的形式是:INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
ADD_ROW() 為批量插入添加新行。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蹲姐,一起剝皮案震驚了整個(gè)濱河市磨取,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柴墩,老刑警劉巖忙厌,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異江咳,居然都是意外死亡逢净,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)爹土,“玉大人甥雕,你說(shuō)我怎么就攤上這事∽偶ⅲ” “怎么了犀农?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵惰赋,是天一觀的道長(zhǎng)宰掉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赁濒,這世上最難降的妖魔是什么轨奄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮拒炎,結(jié)果婚禮上挪拟,老公的妹妹穿的比我還像新娘。我一直安慰自己击你,他們只是感情好玉组,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著丁侄,像睡著了一般惯雳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鸿摇,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天石景,我揣著相機(jī)與錄音,去河邊找鬼拙吉。 笑死潮孽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的筷黔。 我是一名探鬼主播往史,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼佛舱!你這毒婦竟也來(lái)了椎例?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤名眉,失蹤者是張志新(化名)和其女友劉穎粟矿,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體损拢,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陌粹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了福压。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掏秩。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡或舞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒙幻,到底是詐尸還是另有隱情映凳,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布邮破,位于F島的核電站诈豌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏抒和。R本人自食惡果不足惜矫渔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望摧莽。 院中可真熱鬧庙洼,春花似錦、人聲如沸镊辕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)征懈。三九已至石咬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間受裹,已是汗流浹背碌补。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棉饶,地道東北人厦章。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像照藻,于是被迫代替她去往敵國(guó)和親袜啃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348