有的時候需要根據要查詢的參數動態的拼接SQL語句
常用標簽:
- if:字符判斷
- choose【when...otherwise】:分支選擇
- trim【where,set】:字符串截取,其中where標簽封裝查詢條件,set標簽封裝修改條件
- foreach:
if案例
1)在EmployeeMapper接口文件添加一個方法
public Student getStudent(Student student);
2)如果要寫下列的SQL語句,只要是不為空,就作為查詢條件,如下所示,這樣寫實際上是有問題的,所以我們要寫成動態SQL語句:
<select id="getEmployeeByConditionIf" resultType="com.neuedu.entity.Employee">
select *from tbl_employee where id = #{id} and user_name = #{userName} and email = #{email} and gender = #{gender}
</select>
3)用if標簽改寫為動態SQL,如下所示:
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
where
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</select>
4)測試代碼
@Test
public void TestgetStudent(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
Student student = new Student(4,"jack", "111", "jack@qq.com");
System.out.println(student);
Student student2 = bean.getStudent(student);
System.out.println(student2);
}
#測試結果沒問題,
但是仔細來說,上面的sql語句是有問題的,當我們不給動態sql語句傳遞id值的時候,sql語句的拼裝就會有問題!【name前有一個and】
- where 標簽
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
<where>
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</where>
</select>
3.需要注意:where標簽只會去掉第一個多出來的and或者or
也就是說使用where標簽有時候還是不能解決問題的,那怎么辦呢?我們這里可以使用trim標簽!
- trim標簽:可以自定義字符串的截取規則
<select id="getStudent" resultType="com.neuedu.mybatis.entity.Student">
SELECT *
FROM student
<trim prefix="where" prefixOverrides="and">
<if test="id != null">
id=#{id}
</if>
<if test="name !=null and name!=''">
and name=#{name}
</if>
<if test="password !=null and password !=''">
and password=#{password}
</if>
<if test="email !=null and email !=''">
and email=#{email}
</if>
</trim>
</select>
- choose標簽:分支選擇,類似於Java中的帶了break的switch...case
相當於確保了第一個case 符合之后,就跳出
案例演示:
1.在EmployeeMapper接口中添加一個方法
public List<Student> getStus(Student student);
2.sql映射文件
<select id="getStus" resultType="com.neuedu.mybatis.entity.Student">
select * from student
<where>
<choose>
<when test="id !=null">
id = #{id}
</when>
<when test="name !=null and name!=''">
name = #{name}
</when>
<when test="password !=null and password!=''">
password = #{password}
</when>
<when test="email !=null and email!=''">
email = #{email}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
</select>
- set標簽:字符串截取,可以寫在trim里面
set元素會動態前置set關鍵字,同時也會消除無關的逗號
1)在EmployeeMapper中添加一個更新的方法
public void updateStu(Student student);
2)在sql映射文件中,填寫相應的sql語句,如下所示【set標簽可以將字段后面的逗號去掉】
<update id="updateStu">
update student
<set>
<if test="name !=null and name!=''">
name=#{name},
</if>
<if test="password !=null and password !=''">
password=#{password},
</if>
<if test="email !=null and email !=''">
email=#{email}
</if>
</set>
where id = #{id}
</update>
3)測試類代碼為
@Test
public void TestUpdateStu(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
bean.updateStu(new Student(4, "jackk", null, null));
}
將set標簽用trim標簽代替
<update id="updateStu">
update student
<trim prefix="set" suffixOverrides=",">
<if test="name !=null and name!=''">
name=#{name},
</if>
<if test="password !=null and password !=''">
password=#{password},
</if>
<if test="email !=null and email !=''">
email=#{email}
</if>
</trim>
where id = #{id}
</update>
- foreach:遍歷元素
public List<Student> getStuByIdForEach(@Param("ids")List<Integer> ids);
2.在MyBatis的sql映射文件中寫相應的代碼
<select id="getStuByIdForEach" resultType="com.neuedu.mybatis.entity.Student">
select * from student
where id
in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
3.測試類代碼
@Test
public void getStuByIdForEach(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
List<Integer> list = Arrays.asList(16,17,18,19);
List<Student> stuByIdForEachlist = bean.getStuByIdForEach(list);
for (Student student : stuByIdForEachlist) {
System.out.println(student);
}
}
foreach標簽還可以用於批量保存數據,
1.在EmployeeMapper接口類中添加批量插入的方法
public void insertStus(@Param("stus")List<Student> student);
2.在EmployeeMapper.xml的sql映射文件中添加響應的語句
foreach 中用 collection,collection中是從Mapper接口傳來的參數,separator是去掉中間符號
<insert id="insertStus">
insert into student (name,password,email) values
<foreach collection="stus" item="stu" separator=",">
(#{stu.name},#{stu.password},#{stu.email})
</foreach>
</insert>
3.測試代碼
@Test
public void TestInsertStus(){
StudentMapper bean = ioc.getBean(StudentMapper.class);
List<Student> list = new ArrayList<Student>();
list.add(new Student("123","123", "123"));
list.add(new Student("123","123", "123"));
list.add(new Student("123","123", "123"));
bean.insertStus(list);
}
MyBatis-緩存機制
一級緩存:
案例:測試一級緩存【默認是開啟的】
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2);
System.out.println(emp == emp2);
session.commit();
session.close();
}
一級緩存失效的情況【4種】(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢)
1.sqlSession不同,重新定義SqlSession
將返回兩條select語句
將返回false,說明emp2不是emp的緩存
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
SqlSession session2 = sqlSessionFactory.openSession();
EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
Employee emp2 = mapper2.getEmpInfoById(4);
System.out.println(emp2);
System.out.println(emp == emp2);
session.commit();
session.close();
}
2.SqlSession相同,但是查詢條件不一樣[當前緩存中還沒有這個數據]
就是相當於根據不同條件再次查找
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
Employee emp2 = mapper.getEmpInfoById(16);
System.out.println(emp2);
System.out.println(emp == emp2);
session.commit();
session.close();
}
3.SqlSession相同,但是兩次查詢之間執行了增刪改操作【這次增刪改可能對當前數據有影響】
因為默認自動刷新了緩存
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
mapper.deleteEmp(16);
Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2);
System.out.println(emp == emp2);
session.commit();
session.close();
}
4.SqlSession相同,手動清除了一級緩存[緩存清空]
手動清除了緩存,所以得重新查找
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
session.clearCache();
Employee emp2 = mapper.getEmpInfoById(4);
System.out.println(emp2);
System.out.println(emp == emp2);
session.commit();
session.close();
}
二級緩存:
案例:
1)開啟全局二級緩存配置:
<setting name="cacheEnabled" value="true"/>
2)去mapper.xml中配置使用二級緩存
<cache eviction="FIFO" size="100" readOnly="false"/>
3)我們的POJO需要實現序列化接口[implements Serializable]
4)必須先關閉之前的sqlsession對象
測試:
可以看到只發送了一次SQL語句,第二次查詢時從二級緩存中拿到的數據,並沒有發送新的sql語句。
@Test
public void TestFirstCache(){
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
session = sqlSessionFactory.openSession();
mapper = session.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpInfoById(4);
System.out.println(emp);
session.close();
SqlSession session2 = sqlSessionFactory.openSession();
EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
Employee emp2 = mapper2.getEmpInfoById(4);
System.out.println(emp2);
session2.close();
}
需要注意的是:只有一級緩存中關閉的情況下,二級緩存才會被使用。
需要注意的是:在哪個Mapper.xml文件中開啟了<cache>緩存標簽,哪個Mapper中就開啟了二級緩存。
