MyBatis的CURD操作(動態SQL)

動態SQL

動態 SQL,主要用於解決查詢條件不確定的情況:在程序運行期間,根據用戶提交的查詢條件進行查詢。提交的查詢條件不同,執行的 SQL 語句不同。若將每種可能的情況均逐一列出,對所有條件進行排列組合,將會出現大量的 SQL 語句。此時,可使用動態 SQL 來解決這樣的問題。

動態 SQL,即通過 MyBatis 提供的各種標籤對條件作出判斷以實現動態拼接 SQL 語句。這裏的條件判斷使用的表達式爲 OGNL 表達式。 常用的動態 SQL 標籤有<if/>、 <where/>、<choose/>、<foreach/>等。

MyBatis 的動態 SQL 語句,與 JSTL 中的語句非常相似。

項目實例

(1) 定義數據庫表

{$ asset_img curd12.jpg $}

(2) 定義實體

public class Student {
	private Integer id;
	private String name;
	private int age;
	private double score;

}

(3) 創建工具類

public class MyBatisUtils {
	private static SqlSessionFactory sqlSessionFactory;

	public static SqlSession getSqlSession() {
		try {
			InputStream is = Resources.getResourceAsStream("mybatis.xml");
			if (sqlSessionFactory == null) {
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
			}
			return sqlSessionFactory.openSession();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}

(4)定義測試類

定義 @Before 與 @After 方法

public class MyTest {
	private IStudentDao dao;
	private SqlSession sqlSession;

	@Before
	public void setUp() {
		sqlSession = MyBatisUtils.getSqlSession();
		dao = sqlSession.getMapper(IStudentDao.class);
	}
	
	@After
	public void tearDown() {
		if (sqlSession != null) {
			sqlSession.close();
			
		}
	}

}

注意:
在 mapper 的動態 SQL 中若出現大於號(>)、小於號(<)、大於等於號(>=),小於等於號(<=)等符號,最好將其轉換爲實體符號。否則, XML 可能會出現解析出錯問題。特別是對於小於號(<),在 XML 中是絕對不能出現的。否則,一定出錯。

{% asset_img curd13.jpg %}

<if/>標籤

對於該標籤的執行,當 test 的值爲 true 時,會將其包含的 SQL 片斷拼接到其所在的 SQL語句中。這引發的問題是,查詢條件不確定,查詢條件依賴於用戶提交的內容。此時,就可使用動態 SQL 語句,根據用戶提交內容對將要執行的 SQL 進行拼接。

(1)定義 Dao 接口

public interface IStudentDao {
	List<Student> selectStudentsByIf(Student student);
	
}

(2)定義映射文件

爲了解決兩個條件均未做設定的情況,在 where 後添加了一個“1=1”的條件。這樣就不至於兩個條件均未設定而出現只剩下一個 where,而沒有任何可拼接的條件的不完整 SQL 語句。

    <!-- if標籤 -->
	<select id="selectStudentsByIf" resultType="Student">
		select id,name,age,score 
		from student 
		where 1 = 1
		<if test="name != null and name != ''">
			and name like '%' #{name} '%'
		</if>
		<if test="age > 0">
			and age > #{age}
		</if>
	</select>

(3)修改測試類

	@Test
	public void test01() {
		Student stu = new Student("張", 18, 0);
//		Student stu = new Student("", 23, 0);
//		Student stu = new Student("", 0, 0);
		
		List<Student> students = dao.selectStudentsByIf(stu);
		for (Student student : students) {
			System.out.println(student);
		}
	}

(4)運行結果

{% asset_img curd14.jpg %}

{% asset_img curd15.jpg %}

{% asset_img curd16.jpg %}

<where/>標籤

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

(1)修改 Dao 接口

	List<Student> selectStudentsByWhere(Student student);

(2)定義映射文件

	<!-- where標籤 -->
	<select id="selectStudentsByWhere" resultType="Student">
		select id,name,age,score 
		from student 
		<where>
			<if test="name != null and name != ''">
				and name like '%' #{name} '%'
			</if>
			<if test="age > 0">
				and age > #{age}
			</if>
		</where>
	</select>

(3)修改測試類

	@Test
	public void test02() {
		Student stu = new Student("張", 18, 0);
//		 Student stu = new Student("", 23, 0);
//		 Student stu = new Student("", 0, 0);
		
		List<Student> students = dao.selectStudentsByWhere(stu);
		for (Student student : students) {
			System.out.println(student);
		}
	}

(4)運行結果

{% asset_img curd17.jpg%}

<choose/>標籤

該標籤中只可以包含<when/><otherwise/>,可以包含多個與一個<otherwise/>。它們聯合使用,完成 Java 中的開關語句 switch…case 功能。

(1)修改 Dao 接口

	List<Student> selectStudentsByChoose(Student student);

(2)定義映射文件

	<!-- choose標籤 -->
	<select id="selectStudentsByChoose" resultType="Student">
		select id,name,age,score 
		from student 
		<where>
			<choose>
				<when test="name != null and name !=''">
					and name like '%' #{name} '%'
				</when>
				<when test="age > 0">
					and age > #{age}
				</when>
				<otherwise>
					1 = 2
				</otherwise>
			</choose>
		</where>
	</select>

(3)修改測試類

	@Test
	public void test03() {
//		Student stu = new Student("張", 18, 0);
		Student stu = new Student("", 23, 0);
//		Student stu = new Student("", 0, 0);
		
		List<Student> students = dao.selectStudentsByChoose(stu);
		for (Student student : students) {
			System.out.println(student);
		}
	}

<foreach/>標籤

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

  • collection 表示要遍歷的集合類型,這裏是數組,即 array。
  • open、 close、 separator 爲對遍歷內容的 SQL 拼接。

(1)修改 Dao 接口

	List<Student> selectStudentsByForeach(int[] ids);
	List<Student> selectStudentsByForeach2(List<Integer> ids);
	List<Student> selectStudentsByForeach3(List<Student> ids);

(2)定義映射文件

	<!-- foreach標籤 ,遍歷數組-->
	<select id="selectStudentsByForeach" resultType="Student">
		<!-- select id,name,age,score from student where id in (1,3,5) -->
		select id,name,age,score 
		from student 
		<if test="array.length > 0">
			where id in 
			<foreach collection="array" item="myid" open="(" close=")" separator=",">
				#{myid}
			</foreach>
		</if>
	</select>
	
	<!-- foreach標籤 ,遍歷泛型爲基本類型的 List-->
	<select id="selectStudentsByForeach2" resultType="Student">
		<!-- select id,name,age,score from student where id in (1,3,5) -->
		select id,name,age,score 
		from student 
		<if test="list.size > 0">
			where id in 
			<foreach collection="list" item="myid" open="(" close=")" separator=",">
				#{myid}
			</foreach>
		</if>
	</select>
	
	<!-- foreach標籤遍歷泛型爲自定義類型的 List -->
	<select id="selectStudentsByForeach3" resultType="Student">
		<!-- select id,name,age,score from student where id in (1,3,5) -->
		select id,name,age,score 
		from student 
		<if test="list.size > 0">
			where id in 
			<foreach collection="list" item="stu" open="(" close=")" separator=",">
				#{stu.id}
			</foreach>
		</if>
	</select>

(3)修改測試類

	@Test
	public void test04() {
		int[] ids = {1, 3, 4};
		List<Student> students = dao.selectStudentsByForeach(ids);
		for (Student student : students) {
			System.out.println(student);
		}
	}
	
	@Test
	public void test05() {
		List<Integer> ids = new ArrayList<>();
		ids.add(1);
		ids.add(3);
		
		List<Student> students = dao.selectStudentsByForeach2(ids);
		for (Student student : students) {
			System.out.println(student);
		}
	}
	
	@Test
	public void test06() {
		Student stu1 = new Student();
		stu1.setId(1);
		Student stu2 = new Student();
		stu2.setId(3);
		
		List<Student> stus = new ArrayList<>();
		stus.add(stu1);
		stus.add(stu2);
		
		List<Student> students = dao.selectStudentsByForeach3(stus);
		for (Student student : students) {
			System.out.println(student);
		}
	}

<sql/>標籤

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

(1)修改 Dao 接口

	List<Student> selectStudentsBySqlFragment(List<Student> ids);

(2)定義映射文件

	<!-- sql標籤 -->
	<select id="selectStudentsBySqlFragment" resultType="Student">
		<!-- select id,name,age,score from student where id in (1,3,5) -->
		select <include refid="selectColumns"/>
		from student 
		<if test="list.size > 0">
			where id in 
			<foreach collection="list" item="stu" open="(" close=")" separator=",">
				#{stu.id}
			</foreach>
		</if>
	</select>
	
	<sql id="selectColumns">
		id,name,age,score 
	</sql>

(3)修改測試類

	@Test
	public void test07() {
		Student stu1 = new Student();
		stu1.setId(1);
		Student stu2 = new Student();
		stu2.setId(3);
		
		List<Student> stus = new ArrayList<>();
		stus.add(stu1);
		stus.add(stu2);
		
		List<Student> students = dao.selectStudentsBySqlFragment(stus);
		for (Student student : students) {
			System.out.println(student);
		}
	}

(4)運行結果

{% asset_img curd18.jpg %}

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