注解方式
常用注解标签
@Insert:插入 sql , 和 xml insert sql 语法完全一样
@Select :查询 sql, 和 xml select sql 语法完全一样
@Update :更新 sql, 和 xml update sql 语法完全一样
@Delete :删除 sql, 和 xml delete sql 语法完全一样
@Param :入参
@Results:设置结果集合
@Result :结果
public interface StudentDao {
@Delete("delete from student where id=#{id}")
void deleteStudent(int id);
}
@Test
public void delete(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
studentDao.deleteStudent(1);//调用接口中方法 对应的sql
sqlSession.commit();
sqlSession.close();
}
@Update("update student set num = 103 where id = #{id}")
void updateState(int id);
@Select("select num,name from student where id = #{id}")
Student findStudent(int id);
Mybatis动态SQL
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。 如果你有使用JDBC 或其他相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。
where、if
if test=“条件”:可以对传入的条件进行判断
对于查询条件个数不确定的情况,可使用元素。where标签:当where标签内的if有成立的,就会动态的添加一个where关键字;如果where后面有and、or这种关键字,也会动态删除
public interface StudentDao {
List<Student> findStudents1(Student student);
}
<select id="findStudents1" resultType="com.ffyc.mybatisPro.model.Student">
select * from student
<where>
<if test="num!=null">
and num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</where>
</select>
@Test
public void query(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student=new Student();
//student.setNum(103);
student.setName("李四");
studentDao.findStudents1(student);//调用接口中方法 对应的sql
sqlSession.close();
}
trim
trim中的prefix可以自定义指定关键字,如果if成立就动态的添加指定的关键字
prefixOverrides删除掉指定的开头的关键字
<select id="findStudents1" resultType="com.ffyc.mybatisPro.model.Student">
select * from student
<trim prefix="where" prefixOverrides="and|or">
<if test="num!=null">
and num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</trim>
</select>
choose、when、otherwise
相当于if…else if…else;choose里面可以有when,可以没有otherwise
<select id="findStudents1" resultType="com.ffyc.mybatisPro.model.Student">
select * from student
<trim prefix="where" prefixOverrides="and|or">
<choose>
<when test="num!=null">
num=#{num}
</when>
<when test="name!=null">
and name=#{name}
</when>
<otherwise>
and gender=#{gender}
</otherwise>
</choose>
</trim>
</select>
set
set 可以动态的添加set关键字,可以去除最后的逗号;主要用于多次修改中
public interface StudentDao {
void updateStudent(Student student);
}
<update id="updateStudent" parameterType="com.ffyc.mybatisPro.model.Student">
update student
<set>
<if test="num!=null">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</set>
where id=#{id}
</update>
也可以用trim实现
<update id="updateStudent" parameterType="com.ffyc.mybatisPro.model.Student">
update student
<trim prefix="set" suffixOverrides=",">
<if test="num!=null">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id=#{id}
</update>
@Test
public void update(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student=new Student();
student.setId(2);
student.setNum(104);
student.setName("李四44");
studentDao.updateStudent(student);//调用接口中方法 对应的sql
sqlSession.commit();
sqlSession.close();
}
foreach
对集合进行遍历(尤其是在构建 IN 条件语句的时候)
public interface StudentDao {
void deleteStudent(List<Integer> list);
}
<!--delete from student where id in (2,3)批量删除,对数组或集合进行遍历-->
<delete id="deleteStudent">
delete from student where id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
@Test
public void delete1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Integer> list=new ArrayList<>();
list.add(2);
list.add(3);
studentDao.deleteStudent(list);//调用接口中方法 对应的sql
sqlSession.commit();
sqlSession.close();
}
对数组进行遍历
public interface StudentDao {
void deleteStudent2(Integer[] array);
}
<delete id="deleteStudent2">
delete from student where id in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
@Test
public void delete2(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Integer[] array={4,5};
studentDao.deleteStudent2(array);//调用接口中方法 对应的sql
sqlSession.commit();
sqlSession.close();
}
标记语言中,特殊符号处理
方式一:转义符号处理。在 mybatis 中的 xml 文件中,存在一些特殊的符号,比如:<、>、"、&、<>等,正常书写 mybatis 会报错,需要对这些符号进行转义。具体转义如下所示:
特殊字符 | 转义字符 |
---|---|
< | < ; |
> | > ; |
" | " ; |
’ | &apos ; |
& | & ; |
public interface StudentDao {
List<Student> findStudents2(int num);
}
select id="findStudents2" resultType="com.ffyc.mybatisPro.model.Student">
select * from student where num<#{num}
</select>
@Test
public void query1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
studentDao.findStudents2(103);//调用接口中方法 对应的sql
sqlSession.close();
}
方式二:除了可以使用上述转义字符外,还可以使用<![CDATA[]]>来包裹特殊字符。如下所示:
<select id="findStudents2" resultType="com.ffyc.mybatisPro.model.Student">
select * from student where num <![CDATA[ < ]]> #{num}
</select>
<![CDATA[ ]]>是 XML 语法。在 CDATA 内部的所有内容都会被解析器忽略。但是有个问题那就是 、 、 等这些标签都不会被解析,所以 我们只把有特殊字符的语句放在 <![CDATA[ ]]> ,**尽量缩小<![CDATA[ ]]> 的范围。**
缓存
缓存(cache)的作用是为了减去数据库的压力,提高查询性能。缓存实现的原理是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存)中,当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库执行select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。
一级缓存
生:创建sqlsession
销毁:close()、clearCache()、执行update,delete,insert
Mybatis 有一级缓存和二级缓存。一级缓存的作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据,不再从数据库查询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的一级缓存也就不存在了。Mybatis 默认开启一级缓存。
@Test
public void cacheDemo1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student s1=studentDao.findStudentById(6);//调用接口中方法 对应的sql
Student s2=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();
}
查询了两次,但是sql语句执行了一次?因为两次查询的SQL语句一样,查询id为6 返回的对象会缓存到SqlSession对象中,SqlSession对象在内存中存,如果下一次还查询id为6的,就直接访问SqlSession 从缓存中拿就可以
一级缓存的生命周期
a、MyBatis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象;如果 SqlSession 调用了 close()方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存将不可用。
@Test
public void cacheDemo1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student s1=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();//清除缓存
SqlSession sqlSession2= MybatisUtil.getSqlSession();
StudentDao studentDao2 = sqlSession2.getMapper(StudentDao.class);
Student s2=studentDao2.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();
}
b、如果 SqlSession 调用了clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象仍可使用。
@Test
public void cacheDemo1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student s1=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.clearCache();//清除一级缓存中的数据
Student s2=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();
}
c、SqlSession 中执行了任何一个 update 操作(update()、delete()、insert()) ,都会清空一级缓存的数据,但是该对象可以继续使用。
@Test
public void cacheDemo1(){
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student s1=studentDao.findStudentById(6);//调用接口中方法 对应的sql
Student student=new Student();
student.setId(6);
student.setNum(106);
student.setName("李四");
studentDao.updateStudent(student);//中间执行新增、删除、修改操作,一级缓存也会清除
Student s2=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();
}
二级缓存
二级缓存是 SqlSessionFactory 级别的,SqlSessionFactory只有一个。
SqlSession1创建,查询到的数据放在SqlSessionFactory中,SqlSession1销毁;SqlSession2创建,仍然可以拿到SqlSessionFactory中数据
配置二级缓存
第一步:启用二级缓存
在 mybatis_config.xml中启用二级缓存,如下代码所示,当cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。
<!--在mybatis_config.xml中配置-->
<settings> <!--全局开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
</settings>
可以全局的开启缓存,也可以局部的开启或关闭缓存(useCache=“true”)
第二步:对象序列化
将所有的 model类实现序列化接口 Java.io. Serializable。
package com.ffyc.mybatisPro.model;
import java.io.Serializable;
public class Student implements Serializable {
//......
}
第三步:配置映射文件
在 Mapper 映射文件中添加,表示此 mapper 开启二级缓存。
当 SqlSeesion 关闭时,会将数据存入到二级缓存.
<!--StudentMapper.xml中配置二级缓存-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"
/>
public class MybatisUtil {
static SqlSessionFactory sessionFactory;
//静态代码块,在类加载时执行一次
static {
Reader reader = null;
try {
reader = Resources.getResourceAsReader("mybatis_config.xml");
} catch (IOException e) {
e.printStackTrace();
}
sessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
//创建并返回SqlSession
public static SqlSession getSqlSession(){
return sessionFactory.openSession();
}
}
@Test
public void cacheDemo2(){
//用的是同一个SqlSessionFactory
SqlSession sqlSession= MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student s1=studentDao.findStudentById(6);//调用接口中方法 对应的sql
sqlSession.close();//一级缓存销毁,毁时会将缓存写入到二级缓存
SqlSession sqlSession2= MybatisUtil.getSqlSession();
StudentDao studentDao2 = sqlSession2.getMapper(StudentDao.class);
Student s2=studentDao2.findStudentById(6);
//此时可以从二级缓存获取数据,因为共享的是同一个SqlSessionFactory
sqlSession.close();
}
可以单独为某一个语句关闭二级缓存,加上useCache=“false”,即使配置过二级缓存,二级缓存也会失效
<select id="findStudentById" parameterType="int" resultMap="studentMap" useCache="false">
select
s.id,
s.num,
s.name,
s.gender,
s.birthday,
d.num dormNum,
a.account,
s.oper_time
from student s left join dorm d on s.dormid=d.id
left join admin a on s.adminid=a.id
where s.id=#{id}
</select>