MyBatis動態SQL

項目的創建和之前一樣,具體的看之前的文章,整體結構就是這樣

一、if

對於該標籤的執行,當 test 的值為 true 時,會將其包含的 SQL 片斷拼接到其所在的 SQL 語句中。
語法:<if test=」條件」> sql 語句的部分 </if>

接口方法:StudentDao

// 動態的sql時,使用java對象作為參數
    List<Student> selectStudentIf(Student student);

mapper文件:StudentDao.xml

    <!--if的使用
         <if test="使用的參數為java對象屬性值作為判斷條件">
         語法:屬性=xxx值
    -->

    <!-- 
	注意,當這樣寫的時候,name不滿足而age滿足的時候會出現問題
    正常:select id,name,age,email from student where name = ? or age > ?
    不正常: select id,name,age,email from student where or age > ? 
	這個時候會有語法錯誤
    所以寫的是時候要在where後面這樣
    where 1=1
    這樣寫的話即使name不滿足,後面的也不不會出現語法錯誤
    select id,name,age,email from student where 1=1 or age > ?
    但這樣也會出現其他的bug,因為是or,並且1=1永遠為true,所以age無論傳入多大都會有數據的
    -->
    <select id="selectStudentIf" resultType="com.md.domain.Student">

      select id,name,age,email from student
      where 1=1
      <if test="name != null and name != '' ">
          name = #{name}
      </if>

      <if test="age > 0" >
          or age > #{age}
      </if>

    </select>

測試

    @Test
    public void testSelectStudentIf(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        Student student = new Student();
        student.setAge(20);
        
        List<Student> studentList = dao.selectStudentIf(student);
        studentList.forEach(stu-> System.out.println(stu));
		sqlSession.close();

    }

此時即使數據庫中,無論年紀多大的都會被查出來,所以就有了下面的標籤

二、where

<if/>標籤的中存在一個比較麻煩的地方:需要在 where 後手工添加 1=1 的子句。因為,若 where 後
的所有<if/>條件均為 false,而 where 後若又沒有 1=1 子句,則 SQL 中就會只剩下一個空的 where,SQL
出錯。所以,在 where 後,需要添加永為真子句 1=1,以防止這種情況的發生。但當數據量很大時,會
嚴重影響查詢效率

使用<where/>標籤,在有查詢條件時,可以自動添加上 where 子句;沒有查詢條件時,不會添加where 子句。需要注意的是,第一個<if/>標籤中的 SQL 片斷,可以不包含 and。不過,寫上 and 也不錯,系統會將多出的 and 去掉。但其它<if/>中 SQL 片斷的 and,必須要求寫上。否則 SQL 語句將拼接出錯

<where> 用來包含 多個<if>的, 當多個if有一個成立的, <where>會自動增加一個where關鍵字,並去掉 if中多餘的 and ,or等

語法:<where> 其他動態 sql </where>

接口方法

// 動態的sql時,使用java對象作為參數
    List<Student> selectStudentWhere(Student student);

mapper

 <!--where的使用

        select id,name,age,email from student WHERE name = ? or age > ?
        select id,name,age,email from student WHERE age > ?
        這樣就避免了上面的bug
    -->

    <select id="selectStudentWhere" resultType="com.md.domain.Student">

      select id,name,age,email from student
      <where>
          <if test="name != null and name != '' ">
              name = #{name}
          </if>

          <if test="age > 0" >
              or age > #{age}
          </if>

      </where>

    </select>

測試:

 @Test
    public void testSelectStudentWhere(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        Student student = new Student();
        student.setName("白昊天");
        student.setAge(20);

        List<Student> studentList = dao.selectStudentWhere(student);
        studentList.forEach(stu-> System.out.println(stu));
        sqlSession.close();


    }

此時就不會出現之前的bug了

三、foreach

<foreach/>標籤用於實現對於數組與集合的遍歷。對其使用,需要注意:

  • collection 表示要遍歷的集合類型, list ,array 等。
  • open、close、separator 為對遍歷內容的 SQL 拼接

語法

<foreach collection=" 集合類型" open=" 開始的字符" close=" 結束的字符"
item=" 集合中的成員" separator=" 集合成員之間的分隔符">
#{item 的值}
</foreach>

例子,查詢學號1001、1002、1003學生的信息

如果是用純java來拼接這個查詢sql語句

@Test
    public void testfor(){
        List<Integer> list = new ArrayList<>();
        list.add(1001);
        list.add(1002);
        list.add(1003);

        String sql = "select * from student where id in";

        StringBuilder builder = new StringBuilder("");


        // 添加開始
        builder.append("(");
        for (Integer i : list){
            builder.append(i).append(",");
        }
        // 因為最後多添加了一個逗號,所以在這裡進行刪除
        builder.deleteCharAt(builder.length()-1);

        builder.append(")");

        sql = sql + builder.toString();
        System.out.println(sql);

//        select * from student where id in(1001,1002,1003)

    }

1. 用法一

接口

// 傳入的是普通list
List<Student> selectForeachOne(List<Integer> idlist);

mapper

select id,name,age,email from student where id in ( ? , ? , ? )

<select id="selectForeachOne" resultType="com.md.domain.Student">

      select id,name,age,email from student where id in
      <foreach collection="list" item="myid" open="(" close=")" separator=",">

        #{myid}

      </foreach>
    </select>

測試:

 @Test
    public void testSelectForeachOne(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        List<Integer> list = new ArrayList<>();
        list.add(1001);
        list.add(1002);
        list.add(1003);

        List<Student> studentList = dao.selectForeachOne(list);
        studentList.forEach(stu-> System.out.println(stu));

        sqlSession.close();
    }

2. 用法二

接口

//    foreach 用法二 , 傳入的是對象集合
    List<Student> selectForeachTwo(List<Student> stulist);

mapper文件

由於傳入的是對象,所以要用對象.屬性

<select id="selectForeachTwo" resultType="com.md.domain.Student">

        select id,name,age,email from student where id in
        <foreach collection="list" item="stu" open="(" close=")" separator=",">
            #{stu.id}
        </foreach>

    </select>

測試方法

    @Test
    public void testSelectForeachTwo(){

        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        List<Student> students = new ArrayList<>();
        Student stu1 = new Student();
        stu1.setId(1003);
        students.add(stu1);

        List<Student> studentList = dao.selectForeachTwo(students);
        studentList.forEach(stu-> System.out.println(stu));
//        select id,name,age,email from student where id in ( ? )
//        Student{id=1003, name='白昊天', email='[email protected]', age=18}
        sqlSession.close();
    }

當然了,對於mapper文件的sql語句還可以這樣寫

<!-- 直接在外面寫小括號,只有能湊成完成的sql語句就行-->
    <select id="selectForeachTwo" resultType="com.md.domain.Student">

        select id,name,age,email from student where id in (
        <foreach collection="list" item="stu" separator=",">
            #{stu.id}
        </foreach>
        )
    </select>

效果和上面的是一樣的,能完成的拼湊出sql語句即可

四、sql代碼片段

<sql/>標籤用於定義 SQL 片斷,以便其它 SQL 標籤復用。

而其它標籤使用該 SQL 片斷,需要使用<include/>子標籤。該<sql/>標籤可以定義 SQL 語句中的任何部分,所以<include/>子標籤可以放在動態 SQL的任何位置

接口方法:

List<Student> selectStudentSqlFragment(List<Student> stuList);

mapper文件

<!-- 創建 sql 片段 id: 片段的自定義名稱 -->
<sql id="studentSql">
	select id,name,email,age from student
</sql>
<select id="selectStudentSqlFragment" resultType="com.md.domain.Student">
<!-- 引用 sql 片段 -->
	<include refid="studentSql"/>
	<if test="list !=null and list.size > 0 ">
	where id in
	<foreach collection="list" open="(" close=")"
		item="stuobject" separator=",">
	#{stuobject.id}
	</foreach>
<	/if>
</select>

測試方法

@Test
public void testSelectSqlFragment() {
	List<Student> list = new ArrayList<>();
	Student s1 = new Student();
	s1.setId(1002);
	list.add(s1);
	s1 = new Student();
	s1.setId(1005);
	list.add(s1);
	List<Student> studentList = studentDao.selectStudentSqlFragment(list);
	studentList.forEach( stu -> System.out.println(stu));
}

五、總結

根據條件能夠使用不同的sql語句,使用mybatis標籤

1. if

判斷條件,條件為true,就會把if之前的sql加入到主sql語句之後

2. where

<where> 標籤裏面多個if標籤,如果有一個if判斷為true,就會在sql的後面加入where關鍵字,而還會自動的去掉無用的and、or等字符

3. foreach

循環數組,list集合,主要看語法格式

4. sql代碼片段

復用常用的sql語句

  • 先定義<sql id=”自定義名唯一” > sql語句 </sql>
  • 再使用 <include refid = “id的值”>
Tags: