MyBatis的动态SQL与日志Log4J、SQL语句构造器

一、MyBatis动态SQL

  • 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

  • 使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

  • 如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

    if

    • 使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:
      <select id="findActiveBlogWithTitleLike" resultType="Blog">
        SELECT * FROM BLOG WHERE state = ‘ACTIVE’
        <if test="title != null">
          AND title like #{title}
        </if>
      </select>
      
    • 这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果。
    • 通过 “title” 和 “author” 两个参数进行可选搜索,只需要加入另一个条件即可。
      <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 元素,它有点像 Java 中的 switch 语句。传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 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’” 设置成动态条件。
      <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>
      
    • 如果没有匹配的条件,最终这条 SQL 会变成这样:SELECT * FROM BLOG WHERE,这会导致查询失败。如果匹配的只是第二个条件,这条 SQL 会是这样:
      SELECT * FROM BLOG WHERE AND title like ‘someTitle’,这个查询也会失败。
    • MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。
      <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 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。
      <trim  prefix="WHERE"  prefixOverrides="AND |OR "> ... </trim>
      
    • prefixOverrides 属性会忽略通过管道符分隔的文本序列。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
      <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 元素等价的自定义 trim 元素
      <trim  prefix="SET"  suffixOverrides=","> ... </trim>
      

    foreach

    • 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
      <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 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

    script

    • 要在带注解的映射器接口类中使用动态 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 表达式以外创建一个变量,并将其绑定到当前的上下文。
      <select  id="selectBlogsLike"  resultType="Blog">
        <bind  name="pattern"  value="'%' + _parameter.getTitle() + '%'"  />
        SELECT * FROM BLOG WHERE title LIKE #{pattern}
      </select>
      

    多数据库支持

    • 如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。
      <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>
      

    动态 SQL 中的插入脚本语言

    • MyBatis 从 3.2 版本开始支持插入脚本语言,这允许你插入一种语言驱动,并基于这种语言来编写动态 SQL 查询语句。
      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);  
      }
      
    • 实现自定义语言驱动后,你就可以在 mybatis-config.xml 文件中将它设置为默认语言:
      <typeAliases>
        <typeAlias  type="org.sample.MyLanguageDriver"  alias="myLanguage"/>
      </typeAliases>
      <settings>
        <setting  name="defaultScriptingLanguage"  value="myLanguage"/>
      </settings>
      
    • 你也可以使用 lang 属性为特定的语句指定语言:
      <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缓存

  • 默认情况下,只启用了本地的会话缓存(SqlSession),它仅仅对一个会话中的数据进行缓存,会话缓存也称为一级缓存。二级缓存是全局缓存(SqlSessionFactory),需要手动开启:在SQL映射文件中添加一行:<cache/>

  • 缓存的清除策略:

    • LRU(Least Recently Uses):最近最少使用,移除最长时间不被使用的对象
    • FIFO(First In First Out):先进先出,按照对象进入缓存的顺序来移除他们。这也是数据结构中队列(Queue)的元素存取方式。
    • SOFT:软引用,基于来及回收器状态和软引用规则移除对象
    • WEAK:弱引用,更积极地基于垃圾收集器状态和弱引用规则来移除对象
  • 默认的清除策略是LRU

三、日志 log4j

  • Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:
    • SLF4J
    • Apache Commons Logging
    • Log4j 2
    • Log4j
    • JDK logging
  • MyBatis 内置日志工厂会基于运行时检测信息选择日志委托实现。它会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。
  • 可以在mybatis配置文件中设置日志选项,可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING,或者是实现了 org.apache.ibatis.logging.Log 接口,且构造方法以字符串为参数的类完全限定名。
  • 全局日志配置可以配置打印的日志级别,日志的输出对象。日志的四个级别:error、warn、info、debug,优先级从高到低;如果设置为error,只打印error信息,如果设置为debug,所有级别的信息都会打印;只会打印大于等于这个级别的日志。stdout是标准输出:打印在控制台。还可以将日志输出到文件,最后一行指定了最小输出宽度以及对齐方式。
  • MyBatis日志配置设置了跟踪的包、类或方法,对特定包下的类、特定类、特定方法才会打印日志。

四、测试动态SQL和日志log4j

  • 添加junit,mysql,mybatis 以及 log4j 的依赖到 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
    # 控制台输出
    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对象
         * @return
         */
        public static SqlSession getSession(){
            mSession = mFactory.openSession(true);
            return mSession;
        }
        /**
         * 关闭SqlSession对象
         * @param session 要关闭的SqlSession对象
         */
        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);
            }
        }
    }
    
  • 测试结果

     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);
            }
        }
    }
    
  • 测试结果

     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语句构造器

  • MyBatis 3 提供了方便的工具类来帮助解决该问题。使用SQL类,简单地创建一个实例来调用方法生成SQL语句。
  • SQL 语句生成器列表
方法 描述
SELECT(字串) SELECT(字符串...) 开始或插入到选择子句。可以被多次调用,参数也会添加到SELECT子句。参数通常使用逗号分隔的列名和别名列表,但也可以是数据库驱动程序接受的任意类型。
SELECT_DISTINCT(字符串) SELECT_DISTINCT(字符串...) 开始或插入到SELECT子句,也可以插入DISTINCT关键字到生成的查询语句中。可以被多次调用,参数也会添加到SELECT子句。参数通常使用逗号分隔的列名和别名列表,但也可以是数据库驱动程序接受的任意类型。
FROM(字符串) FROM(字符串...) 开始或插入到FROM子句。可以被多次调用,参数也会添加到FROM子句。参数通常是表名或别名,也可以是数据库驱动程序接受的任意类型。
JOIN(字符串) JOIN(字符串...) INNER_JOIN(字符串) INNER_JOIN(字符串...) LEFT_OUTER_JOIN(字符串) LEFT_OUTER_JOIN(字符串...) RIGHT_OUTER_JOIN(字符串) RIGHT_OUTER_JOIN(字符串...) 基于调用的方法,添加新的合适类型的JOIN子句。参数可以包含由列命和加入的条件组合成标准的加入。
WHERE(String) WHERE(String...) 插入新的 WHERE子句条件, 由AND链接。可以多次被调用,每次都由AND来链接新条件。使用 OR() 来分隔OR
OR() 使用OR来分隔当前的 WHERE子句条件。 可以被多次调用,但在一行中多次调用或生成不稳定的SQL
AND() 使用AND来分隔当前的 WHERE子句条件。 可以被多次调用,但在一行中多次调用或生成不稳定的SQL。因为 WHEREHAVING 二者都会自动链接 AND, 这是非常罕见的方法,只是为了完整性才被使用。
GROUP_BY(String) GROUP_BY(String...) 插入新的 GROUP BY子句元素,由逗号连接。 可以被多次调用,每次都由逗号连接新的条件。
HAVING(String) HAVING(String...) 插入新的 HAVING子句条件。 由AND连接。可以被多次调用,每次都由AND来连接新的条件。使用 OR() 来分隔OR
ORDER_BY(String) ORDER_BY(String...) 插入新的 ORDER BY子句元素, 由逗号连接。可以多次被调用,每次由逗号连接新的条件。
LIMIT(String) LIMIT(int) 附加一个LIMIT子句。与SELECT(),UPDATE()DELETE()一起使用时,此方法有效。并且此方法设计为在使用SELECT()时与OFFSET()一起使用。
OFFSET(String) OFFSET(long) 附加一个OFFSET子句。与SELECT()一起使用时,此方法有效。该方法设计为与LIMIT()一起使用。
OFFSET_ROWS(String) OFFSET_ROWS(long) 附加一个OFFSET n ROWS子句。与SELECT()一起使用时,此方法有效。该方法旨在与FETCH_FIRST_ROWS_ONLY()一起使用
FETCH_FIRST_ROWS_ONLY(String) FETCH_FIRST_ROWS_ONLY(int) 追加FETCH FIRST n ROWS ONLY子句。与SELECT()一起使用时,此方法有效。此方法设计为与OFFSET_ROWS()一起使用。
DELETE_FROM(String) 开始一个delete语句并指定需要从哪个表删除的表名。通常它后面都会跟着WHERE语句
INSERT_INTO(String) 开始一个insert语句并指定需要插入数据的表名。后面都会跟着一个或者多个VALUES() or INTO_COLUMNS() and INTO_VALUES()
SET(String) SET(String...) 针对update语句,插入到"set"列表中
UPDATE(String) 开始一个update语句并指定需要更新的表明。后面都会跟着一个或者多个SET(),通常也会有一个WHERE()
VALUES(String, String) 插入到insert语句中。第一个参数是要插入的列名,第二个参数则是该列的值。
INTO_COLUMNS(String...) 插入语句的形式是:INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
INTO_VALUES(String...) 插入语句的形式是:INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
ADD_ROW() 为批量插入添加新行。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352