MyBatis——sql、if、choose、where、set、trim

1 前言

動態 SQL 是MyBatis 強大特性之一,主要包含 sql、if、choose、where、set、trim、foreach 等標籤,本文僅介紹前6個標籤的用法,對於 foreach 標籤的用法,將在下一個專題介紹。

  • <sql>:定義 SQL 片段,通過 <sql id="sql_id"></sql> 定義SQL片段,<include refid="sql_id"/> 引用定義好的片段
  • <if>:條件語句,用法:<if test="expression"></if>
  • <choose>:單選,用法:<choose> <when test=""></when> <otherwise></otherwise> </choose>
  • <where>:添加 where 關鍵字,去掉多餘的 and 和 or
  • <set>:解決 SQL 語句中可能出現過多逗號的問題
  • trim:截取並拼接,用法:<trim prefix="" suffix="" prefixOverrides="" suffixOverrides=""></trim>,prefix:在操作的 SQL 語句前加入某些內容,suffix:在操作的 SQL 語句後加入某些內容,prefixOverrides:把操作 SQL 語句前的某些內容去掉,suffixOverrides:把操作 SQL 語句後的某些內容去掉。

2 實驗環境

(1)導入 JAR 包

其中,前2個 jar 包下載地址見 → log4j-1.2.17.jar、 mybatis-3.4.1.jar,將 jar 包放入 lib 目錄下,並選中所有 jar 包,右鍵,選擇【Add to Build Path】。

(2) 工作目錄 

 注意:src 和 conf 目錄下的 com.mapper 包必須同名。

(3)配置文件 

log4j.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
	<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
		<param name="Encoding" value="UTF-8" />
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L)\n" />
		</layout>
	</appender>
 
	<logger name="java.sql">
		<level value="debug" />
	</logger>
 
	<logger name="org.apache.ibatis">
		<level value="info" />
	</logger>
 
	<root>
		<priority value="debug" />
		<appender-ref ref="STDOUT" />
	</root>
</log4j:configuration>

注意:log4j.xml文件名不能隨意更改。  

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>
	<!-- 設置或引入資源文件 -->
	<properties resource="jdbc.properties"></properties>
	
	<!-- 設置連接數據庫的環境,default用於設置默認使用的數據庫環境 -->
	<environments default="mysql">
		<!-- 設置某個具體的數據庫環境 -->
		<environment id="mysql">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	
	<!-- 引入映射文件 -->
	<mappers>
		<package name="com.mapper"/>
	</mappers>
</configuration>

jdbc.properties

# K = V
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/users
jdbc.username=root
jdbc.password=0.

3 案例分析

首先在 MySQL 中創建數據庫:users,再在此數據庫中創建表:students。

students 包含 sid(int)、sname(varchar)和 sex(varchar) 3個字段,其中,sid 設置了自增,students 表中數據如下:

首先介紹下公共的文件,主要包含 Student.java、StudentMapper.java,不同的是 StudentMapper.xml、Test.java,將在各節分別介紹。 

Student.java

package com.bean;
 
public class Student {
	private Integer sid;
	private String sname;
	private String sex; 
	
	public Student() {}

	public Student(Integer sid, String sname, String sex) {
		this.sid = sid;
		this.sname = sname;
		this.sex = sex;
	}

	public Integer getSid() {
		return sid;
	}
 
	public void setSid(Integer sid) {
		this.sid = sid;
	}
 
	public String getSname() {
		return sname;
	}
 
	public void setSname(String sname) {
		this.sname = sname;
	}
	
	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", sex=" + sex + "]";
	}
}

StudentMapper.java

package com.mapper;
 
import java.util.List;
import com.bean.Student;
 
public interface StudentMapper {
	public Student getStudentById(Integer sid);
	
	public List<Student> getStudents(Student student);
	
	public void updateStudent(Student student);
}

3.1 <sql> 標籤

StudentMapper.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.mapper.StudentMapper">
	<sql id="selectColumn">select sid,sname,sex from students</sql>
	
	<!-- public Student getStudentById(Integer sid); -->
	<select id="getStudentById" resultType="com.bean.Student">
		<include refid="selectColumn"/> where sid=#{sid}
	</select>
</mapper>

注意:<sql> 標籤標示一個 SQL 語句片段,通過 <include> 標籤使用標示的 SQL 語句片段。

Test.java

package com.test;
 
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.bean.Student;
import com.mapper.StudentMapper;
 
public class Test {
	
	public static void main(String[] args) throws IOException {
		InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		SqlSession sqlSession=sqlSessionFactory.openSession(true); //自動提交事務
		//getMapper:會通過動態代理動態生成StudentMapper的代理實現類
		StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
		
		Student student=mapper.getStudentById(1001);
		System.out.println(student);
	}
}

運行結果:

DEBUG 06-14 20:54:49,039 ==>  Preparing: select sid,sname,sex from students where sid=?  
Student [sid=1001, sname=張三, sex=1]

3.2 <if> 標籤

StudentMapper.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.mapper.StudentMapper">
	<!-- public List<Student> getStudents(Student student); -->
	<select id="getStudents" resultType="com.bean.Student">
		select sid,sname,sex from students where 
		<if test="sid!=null">
			sid=#{sid} and
		</if>
		<if test="sname!=null and sname!=''">
			sname=#{sname} and
		</if>
		<if test="sex!=null and sex!='' and (sex==1 or sex==0)">
			sex=#{sex}
		</if>
	</select>
</mapper>

注意:<if> 標籤中 test 屬性指定了標籤內語句塊能夠執行的條件。

 Test.java

package com.test;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.bean.Student;
import com.mapper.StudentMapper;
 
public class Test {
	
	public static void main(String[] args) throws IOException {
		InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		SqlSession sqlSession=sqlSessionFactory.openSession(true); //自動提交事務
		//getMapper:會通過動態代理動態生成StudentMapper的代理實現類
		StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
		
		List<Student> students=mapper.getStudents(new Student(1001,"","1"));
		System.out.println(students);
	}
}

運行結果:

DEBUG 06-14 20:50:48,261 ==>  Preparing: select sid,sname,sex from students where sid=? and sex=?
[Student [sid=1001, sname=張三, sex=1]]

可以看到:由於 sname="",where 後面只有 sid 和 sex 兩個查詢條件。

3.3 <choose> 標籤

MyBatis 中沒有 else if 和 else 標籤,而 if 標籤只有兩個分支,不能滿足用戶多分支條件查詢的需求,而 choose 標籤能夠解決這一問題,其內部只有第一個符合條件的語句塊會執行。

StudentMapper.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.mapper.StudentMapper">
	<!-- public List<Student> getStudents(Student student); -->	
	<select id="getStudents" resultType="com.bean.Student">
		select sid,sname,sex from students where 
		<choose>
			<when test="sid!=null">
				sid=#{sid}
			</when>
			<when test="sname!=null and sname!=''">
				sname=#{sname}
			</when>
			<otherwise>
				sex=#{sex}
			</otherwise>
		</choose>
	</select>
</mapper>

注意:<choose> 標籤中最多隻有一個語句會執行,並且只有第一個符合條件的會執行;<when> 標籤中 test 屬性指定了標籤內語句塊能夠執行的條件;當 <when> 標籤內的條件都不滿足時,會執行 <otherwise> 標籤內語句,另外 <otherwise> 是非必須的,即可以省去。

 Test.java

package com.test;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.bean.Student;
import com.mapper.StudentMapper;
 
public class Test {
	
	public static void main(String[] args) throws IOException {
		InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		SqlSession sqlSession=sqlSessionFactory.openSession(true); //自動提交事務
		//getMapper:會通過動態代理動態生成StudentMapper的代理實現類
		StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
		
		List<Student> students=mapper.getStudents(new Student(null,"李四",""));
		System.out.println(students);
	}
}

運行結果:

DEBUG 06-14 21:14:24,168 ==>  Preparing: select sid,sname,sex from students where sname=?
[Student [sid=1002, sname=李四, sex=0]]

可以看到:where 後面只有 sname 這一個查詢條件。

3.4 <where> 標籤

3.2節 StudentMapper.xml 中部分代碼如下:

		select sid,sname,sex from students where 
		<if test="sid!=null">
			sid=#{sid} and
		</if>
		<if test="sname!=null and sname!=''">
			sname=#{sname} and
		</if>
		<if test="sex!=null and sex!='' and (sex==1 or sex==0)">
			sex=#{sex}
		</if>

若最後一個條件不符合條件,則會在末尾多個 and,不符合 SQL 語法,因此會報錯。

方案一(添加條件【1=1】)

可以通過如下方法解決此問題:

		select sid,sname,sex from students where 1=1 
		<if test="sid!=null">
			and sid=#{sid} 
		</if>
		<if test="sname!=null and sname!=''">
			and sname=#{sname} 
		</if>
		<if test="sex!=null and sex!='' and (sex==1 or sex==0)">
			and sex=#{sex} 
		</if>

Test.java 同3.3節。 

 運行結果:

DEBUG 06-14 22:08:56,654 ==>  Preparing: select sid,sname,sex from students where 1=1 and sname=?
[Student [sid=1002, sname=李四, sex=0]]

可以看到:where 後面多了個條件【1=1】。

方案二(使用 <where> 標籤)

StudentMapper.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.mapper.StudentMapper">
	<!-- public List<Student> getStudents(Student student); -->
	<select id="getStudents" resultType="com.bean.Student">
		select sid,sname,sex from students
		<where>
			<if test="sid!=null">
				and sid=#{sid} 
			</if>
			<if test="sname!=null and sname!=''">
				and sname=#{sname} 
			</if>
			<if test="sex!=null and sex!='' and (sex==1 or sex==0)">
				and sex=#{sex} 
			</if>
		</where>
	</select>
</mapper>

注意:<where> 標籤用於添加 where 關鍵字,並刪除第一個可能多餘的 and 和 or。 

Test.java 同3.3節。  

運行結果:

DEBUG 06-14 22:04:00,454 ==>  Preparing: select sid,sname,sex from students WHERE sname=?  
[Student [sid=1002, sname=李四, sex=0]]

可以看到:替換了多餘的 and。 

3.5 <set> 標籤

StudentMapper.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.mapper.StudentMapper">	
	<!-- public void updateStudent(Student student); -->
	<update id="updateStudent">
		update students
		<set>
			<if test="sname!=null and sname!=''">
				sname=#{sname},
			</if>
			<if test="sex!=null and sex!='' and (sex==1 or sex==0)">
				sex=#{sex}
			</if>
		</set>
		where sid=#{sid}
	</update>
</mapper>

注意:<set> 標籤用於添加 set 關鍵字,並刪除最後一個可能多餘的逗號,如:以上代碼中,若只有第一個 <if> 執行,將會多一個逗號。

Test.java

package com.test;
 
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.bean.Student;
import com.mapper.StudentMapper;
 
public class Test {
	
	public static void main(String[] args) throws IOException {
		InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(is);
		SqlSession sqlSession=sqlSessionFactory.openSession(true); //自動提交事務
		//getMapper:會通過動態代理動態生成StudentMapper的代理實現類
		StudentMapper mapper=sqlSession.getMapper(StudentMapper.class);
		
		mapper.updateStudent(new Student(1001,"張三三",""));		
	}
}

更新後數據庫中 students 表中數據如下:

控制檯輸出如下:

DEBUG 06-14 22:35:50,138 ==>  Preparing: update students SET sname=? where sid=?  

 可以看到:where 後面去掉了多餘的逗號。

3.6 <trim> 標籤

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章