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的值”>