cache – 该命名空间的缓存配置。 cache-ref – 引用其它命名空间的缓存配置。 resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。 parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。 sql – 可被其它语句引用的可重用语句块。 insert – 映射插入语句。 update – 映射更新语句。 delete – 映射删除语句。 select – 映射查询语句。
在之前我们学习了mybatis的全局配置文件,下面我们开始学习mybatis的映射文件,在映射文件中,可以编写以下的顶级元素标签:
1 2 3 4 5 6 7 8 9 cache – 该命名空间的缓存配置。 cache-ref – 引用其它命名空间的缓存配置。 resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。 parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。 sql – 可被其它语句引用的可重用语句块。 insert – 映射插入语句。 update – 映射更新语句。 delete – 映射删除语句。 select – 映射查询语句。
在每个顶级元素标签中可以添加很多个属性,下面我们开始详细了解下具体的配置。
1.insert、update、delete元素 属性 描述 id
在命名空间中唯一的标识符,可以被用来引用这条语句。 parameterType
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 parameterMap
用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 flushCache
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 timeout
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 statementType
可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 useGeneratedKeys
(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。 keyProperty
(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset
)。如果生成列不止一个,可以用逗号分隔多个属性名称。 keyColumn
(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 databaseId
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
1 2 3 4 5 6 7 8 9 10 11 <insert id ="insertUser" useGeneratedKeys ="true" keyProperty ="id" > insert into user(user_name) values(#{userName}) </insert > <insert id ="insertUser2" > <selectKey order ="BEFORE" keyProperty ="id" resultType ="integer" > select max(id)+1 from user </selectKey > insert into user(id,user_name) values(#{id},#{userName}) </insert >
2.select元素 1.select的参数传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <select id ="selectEmpByNoAndName" resultType ="com.mashibing.bean.Emp" > select * from emp where empno=#{empno} and ename=#{ename} </select > <select id ="selectEmpByNoAndName2" resultType ="com.mashibing.bean.Emp" > select * from emp where empno=#{empno} and ename=#{ename} </select >
2.参数的取值方式 在xml文件中编写sql语句的时候有两种取值的方式,分别是#{}和${},下面来看一下他们之间的区别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="selectEmpByNoAndName" resultType ="com.mashibing.bean.Emp" > select * from #{t} where empno=${empno} and ename=${ename} </select >
3.处理集合返回结果 EmpDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <select id ="selectAllEmp" resultType ="com.mashibing.bean.Emp" > select * from emp </select > <select id ="selectEmpByEmpReturnMap" resultType ="map" > select * from emp where empno = #{empno} </select > <select id ="getAllEmpReturnMap" resultType ="com.mashibing.bean.Emp" > select * from emp </select >
UserDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package com.mashibing.dao;import com.mashibing.bean.Emp;import org.apache.ibatis.annotations.MapKey;import org.apache.ibatis.annotations.Param;import java.util.List;import java.util.Map;public interface EmpDao { public Emp findEmpByEmpno (Integer empno) ; public int updateEmp (Emp emp) ; public int deleteEmp (Integer empno) ; public int insertEmp (Emp emp) ; Emp selectEmpByNoAndName (@Param("empno") Integer empno, @Param("ename") String ename,@Param("t") String tablename) ; Emp selectEmpByNoAndName2 (Map<String,Object> map) ; List<Emp> selectAllEmp () ; Map<String,Object> selectEmpByEmpReturnMap (Integer empno) ; @MapKey("empno") Map<Integer,Emp> getAllEmpReturnMap () ; }
4.自定义结果集—resultMap Dog.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.mashibing.bean;public class Dog { private Integer id; private String name; private Integer age; private String gender; public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getName () { return name; } public void setName (String name) { this .name = name; } public Integer getAge () { return age; } public void setAge (Integer age) { this .age = age; } public String getGender () { return gender; } public void setGender (String gender) { this .gender = gender; } @Override public String toString () { return "Dog{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + '}' ; } }
dog.sql
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 SET FOREIGN_KEY_CHECKS= 0 ;DROP TABLE IF EXISTS `dog`;CREATE TABLE `dog` ( `id` int (11 ) NOT NULL AUTO_INCREMENT, `dname` varchar (255 ) DEFAULT NULL , `dage` int (11 ) DEFAULT NULL , `dgender` varchar (255 ) DEFAULT NULL , PRIMARY KEY (`id`) ) ENGINE= InnoDB AUTO_INCREMENT= 4 DEFAULT CHARSET= utf8; INSERT INTO dog VALUES ('1' , '大黄' , '1' , '雄' );INSERT INTO dog VALUES ('2' , '二黄' , '2' , '雌' );INSERT INTO dog VALUES ('3' , '三黄' , '3' , '雄' );
DogDao.java
1 2 3 4 5 6 7 8 package com.mashibing.dao;import com.mashibing.bean.Dog;public interface DogDao { public Dog selectDogById (Integer id) ; }
DogDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?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.mashibing.dao.DogDao" > <select id ="selectDogById" resultMap ="myDog" > select * from dog where id = #{id} </select > <resultMap id ="myDog" type ="com.mashibing.bean.Dog" > <id column ="id" property ="id" > </id > <result column ="dname" property ="name" > </result > <result column ="dage" property ="age" > </result > <result column ="dgender" property ="gender" > </result > </resultMap > </mapper >
5.联合查询 emp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 package com.mashibing.bean;import java.util.Date;public class Emp { private Integer empno; private String ename; private String job; private Integer mgr; private Date hiredate; private Double sal; private Double common; private Dept dept; public Emp () { } public Emp (Integer empno, String ename) { this .empno = empno; this .ename = ename; } public Emp (Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double common, Dept dept) { this .empno = empno; this .ename = ename; this .job = job; this .mgr = mgr; this .hiredate = hiredate; this .sal = sal; this .common = common; this .dept = dept; } public Integer getEmpno () { return empno; } public void setEmpno (Integer empno) { this .empno = empno; } public String getEname () { return ename; } public void setEname (String ename) { this .ename = ename; } public String getJob () { return job; } public void setJob (String job) { this .job = job; } public Integer getMgr () { return mgr; } public void setMgr (Integer mgr) { this .mgr = mgr; } public Date getHiredate () { return hiredate; } public void setHiredate (Date hiredate) { this .hiredate = hiredate; } public Double getSal () { return sal; } public void setSal (Double sal) { this .sal = sal; } public Double getCommon () { return common; } public void setCommon (Double common) { this .common = common; } public Dept getDept () { return dept; } public void setDept (Dept dept) { this .dept = dept; } @Override public String toString () { return "Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr=" + mgr + ", hiredate=" + hiredate + ", sal=" + sal + ", common=" + common + ", dept=" + dept + '}' ; } }
Dept.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package com.mashibing.bean;public class Dept { private Integer deptno; private String dname; private String loc; public Dept () { } public Dept (Integer deptno, String dname, String loc) { this .deptno = deptno; this .dname = dname; this .loc = loc; } public Integer getDeptno () { return deptno; } public void setDeptno (Integer deptno) { this .deptno = deptno; } public String getDname () { return dname; } public void setDname (String dname) { this .dname = dname; } public String getLoc () { return loc; } public void setLoc (String loc) { this .loc = loc; } @Override public String toString () { return "Dept{" + "deptno=" + deptno + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + '}' ; } }
EmpDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <?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.mashibing.dao.EmpDao" > <select id ="selectEmpAndDept" resultMap ="empDept" > select * from emp left join dept on emp.deptno = dept.deptno where empno = #{empno}; </select > <resultMap id ="empDept" type ="com.mashibing.bean.Emp" > <id column ="empno" property ="empno" > </id > <result column ="ename" property ="ename" > </result > <result column ="job" property ="job" > </result > <result column ="mgr" property ="mgr" > </result > <result column ="hiredate" property ="hiredate" > </result > <result column ="sal" property ="sal" > </result > <result column ="comm" property ="common" > </result > <result column ="deptno" property ="dept.deptno" > </result > <result column ="dname" property ="dept.dname" > </result > <result column ="loc" property ="dept.loc" > </result > </resultMap > <resultMap id ="empDept" type ="com.mashibing.bean.Emp" > <id column ="empno" property ="empno" > </id > <result column ="ename" property ="ename" > </result > <result column ="job" property ="job" > </result > <result column ="mgr" property ="mgr" > </result > <result column ="hiredate" property ="hiredate" > </result > <result column ="sal" property ="sal" > </result > <result column ="comm" property ="common" > </result > <association property ="dept" javaType ="com.mashibing.bean.Dept" > <id column ="deptno" property ="deptno" > </id > <result column ="dname" property ="dname" > </result > <result column ="loc" property ="loc" > </result > </association > </resultMap > </mapper >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test08 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp emp = mapper.selectEmpAndDept(7369 ); System.out.println(emp); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
6.获取集合元素 Dept.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.mashibing.bean;import java.util.List;public class Dept { private Integer deptno; private String dname; private String loc; private List<Emp> emps; public Dept () { } public Dept (Integer deptno, String dname, String loc) { this .deptno = deptno; this .dname = dname; this .loc = loc; } public Integer getDeptno () { return deptno; } public void setDeptno (Integer deptno) { this .deptno = deptno; } public String getDname () { return dname; } public void setDname (String dname) { this .dname = dname; } public String getLoc () { return loc; } public void setLoc (String loc) { this .loc = loc; } public List<Emp> getEmps () { return emps; } public void setEmps (List<Emp> emps) { this .emps = emps; } @Override public String toString () { return "Dept{" + "deptno=" + deptno + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + ", emps=" + emps + '}' ; } }
DeptDao.java
1 2 3 4 5 6 7 8 9 10 11 12 package com.mashibing.dao;import com.mashibing.bean.Dept;import com.mashibing.bean.Emp;import java.util.List;public interface DeptDao { public Dept getDeptAndEmps (Integer deptno) ; }
DeptDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?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.mashibing.dao.DeptDao" > <select id ="getDeptAndEmps" resultMap ="deptEmp" > select * from dept left join emp on dept.deptno = emp.deptno where dept.deptno=#{deptno} </select > <resultMap id ="deptEmp" type ="com.mashibing.bean.Dept" > <id property ="deptno" column ="deptno" > </id > <result property ="dname" column ="dname" > </result > <result property ="loc" column ="loc" > </result > <collection property ="emps" ofType ="com.mashibing.bean.Emp" > <id property ="empno" column ="empno" > </id > <result column ="ename" property ="ename" > </result > <result column ="job" property ="job" > </result > <result column ="mgr" property ="mgr" > </result > <result column ="hiredate" property ="hiredate" > </result > <result column ="sal" property ="sal" > </result > <result column ="comm" property ="common" > </result > </collection > </resultMap > </mapper >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test09 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { DeptDao mapper = sqlSession.getMapper(DeptDao.class); Dept deptAndEmps = mapper.getDeptAndEmps(10 ); System.out.println(deptAndEmps); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
7.分步查询 在上述逻辑的查询中,是由我们自己来完成sql语句的关联查询的,那么,我们能让mybatis帮我们实现自动的关联查询吗?
关联查询的分步
DeptDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.mashibing.dao;import com.mashibing.bean.Dept;import com.mashibing.bean.Emp;import java.util.List;public interface DeptDao { public Dept getDeptAndEmps (Integer deptno) ; public Dept getDeptAndEmpsBySimple (Integer deptno) ; }
EmpDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package com.mashibing.dao;import com.mashibing.bean.Emp;import org.apache.ibatis.annotations.MapKey;import org.apache.ibatis.annotations.Param;import java.util.List;import java.util.Map;public interface EmpDao { Emp selectEmpAndDept (Integer empno) ; Emp selectEmpAndDeptBySimple (Integer empno) ; }
DeptDao.xml
1 2 3 4 5 6 7 8 9 <?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.mashibing.dao.DeptDao" > <select id ="getDeptAndEmpsBySimple" resultType ="com.mashibing.bean.Dept" > select * from dept where deptno = #{deptno} </select > </mapper >
EmpDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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.mashibing.dao.EmpDao" > <select id ="selectEmpAndDeptBySimple" resultMap ="simpleEmpAndDept" > select * from emp where empno = #{empno} </select > <resultMap id ="simpleEmpAndDept" type ="com.mashibing.bean.Emp" > <id column ="empno" property ="empno" > </id > <result column ="ename" property ="ename" > </result > <result column ="job" property ="job" > </result > <result column ="mgr" property ="mgr" > </result > <result column ="hiredate" property ="hiredate" > </result > <result column ="sal" property ="sal" > </result > <result column ="comm" property ="common" > </result > <association property ="dept" select ="com.mashibing.dao.DeptDao.getDeptAndEmpsBySimple" column ="deptno" > </association > </resultMap > </mapper >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test08 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp emp = mapper.selectEmpAndDeptBySimple(7369 ); System.out.println(emp); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
集合的分步查询
EmpDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package com.mashibing.dao;import com.mashibing.bean.Emp;import org.apache.ibatis.annotations.MapKey;import org.apache.ibatis.annotations.Param;import java.util.List;import java.util.Map;public interface EmpDao { Emp selectEmpAndDeptBySimple (Integer empno) ; Emp selectEmpByStep (Integer empno) ; }
DeptDao.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package com.mashibing.dao;import com.mashibing.bean.Dept;import com.mashibing.bean.Emp;import java.util.List;public interface DeptDao { public Dept getDeptAndEmps (Integer deptno) ; public Dept getDeptAndEmpsBySimple (Integer deptno) ; public Dept getDeptAndEmpsByStep (Integer deptno) ; }
EmpDao.xml
1 2 3 4 5 6 7 8 9 10 <?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.mashibing.dao.EmpDao" > <select id ="selectEmpByStep" resultType ="com.mashibing.bean.Emp" > select * from emp where deptno = #{deptno} </select > </mapper >
DeptDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?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.mashibing.dao.DeptDao" > <select id ="getDeptAndEmpsByStep" resultMap ="deptEmpByStep" > select * from dept where deptno = #{deptno} </select > <resultMap id ="deptEmpByStep" type ="com.mashibing.bean.Dept" > <id property ="deptno" column ="deptno" > </id > <result property ="dname" column ="dname" > </result > <result property ="loc" column ="loc" > </result > <collection property ="emps" ofType ="com.mashibing.bean.Emp" select ="com.mashibing.dao.EmpDao.selectEmpByStep" column ="deptno" > </collection > </resultMap > </mapper >
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void test09 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { DeptDao mapper = sqlSession.getMapper(DeptDao.class); Dept deptAndEmpsByStep = mapper.getDeptAndEmpsByStep(10 ); System.out.println(deptAndEmpsByStep); } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
8.延迟查询 当我们在进行表关联的时候,有可能在查询结果的时候不需要关联对象的属性值,那么此时可以通过延迟加载来实现功能。在全局配置文件中添加如下属性
mybatis-config.xml
1 2 3 4 <settings > <setting name ="lazyLoadingEnabled" value ="true" /> </settings >
如果设置了全局加载,但是希望在某一个sql语句查询的时候不适用延时策略,可以添加如下属性:
1 <association property ="dept" select ="com.mashibing.dao.DeptDao.getDeptAndEmpsBySimple" column ="deptno" fetchType ="eager" />
3.动态sql 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if choose (when, otherwise) trim (where, set) foreach 1.if EmpDao.xml
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="getEmpByCondition" resultType ="com.mashibing.bean.Emp" > select * from emp where <if test ="empno!=null" > empno > #{empno} and </if > <if test ="ename!=null" > ename like #{ename} and </if > <if test ="sal!=null" > sal > #{sal} </if > </select >
EmpDao.java
1 public List<Emp> getEmpByCondition (Emp emp) ;
Test.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Test public void test10 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp emp = new Emp (); emp.setEmpno(6500 ); emp.setEname("%E%" ); emp.setSal(500.0 ); List<Emp> empByCondition = mapper.getEmpByCondition(emp); for (Emp emp1 : empByCondition) { System.out.println(emp1); } } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
看起来测试是比较正常的,但是大家需要注意的是如果我们传入的参数值有缺失会怎么呢?这个时候拼接的sql语句就会变得有问题,例如不传参数或者丢失最后一个参数,那么语句中就会多一个where或者and的关键字,因此在mybatis中也给出了具体的解决方案:
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="getEmpByCondition" resultType ="com.mashibing.bean.Emp" > select * from emp <where > <if test ="empno!=null" > empno > #{empno} </if > <if test ="ename!=null" > and ename like #{ename} </if > <if test ="sal!=null" > and sal > #{sal} </if > </where > </select >
现在看起来没有什么问题了,但是我们的条件添加到了拼接sql语句的前后,那么我们该如何处理呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <select id ="getEmpByCondition" resultType ="com.mashibing.bean.Emp" > select * from emp <trim prefix ="where" prefixOverrides ="and" suffixOverrides ="and" > <if test ="empno!=null" > empno > #{empno} and </if > <if test ="ename!=null" > ename like #{ename} and </if > <if test ="sal!=null" > sal > #{sal} and </if > </trim > </select >
2.foreach 动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <select id ="getEmpByDeptnos" resultType ="Emp" > select * from emp where deptno in <foreach collection ="deptnos" close =")" index ="idx" item ="deptno" open ="(" separator ="," > #{deptno} </foreach > </select >
3.choose 有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <select id ="getEmpByConditionChoose" resultType ="com.mashibing.bean.Emp" > select * from emp <where > <choose > <when test ="empno!=null" > empno > #{empno} </when > <when test ="ename!=null" > ename like #{ename} </when > <when test ="sal!=null" > sal > #{sal} </when > <otherwise > 1=1 </otherwise > </choose > </where > </select >
4.set 用于动态更新语句的类似解决方案叫做 set 。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <update id ="updateEmpByEmpno" > update emp <set > <if test ="empno!=null" > empno=#{empno}, </if > <if test ="ename!=null" > ename = #{ename}, </if > <if test ="sal!=null" > sal = #{sal} </if > </set > <where > empno = #{empno} </where > </update >
4.缓存 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
当添加上该标签之后,会有如下效果:
映射语句文件中的所有 select 语句的结果将会被缓存。 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。 缓存不会定时进行刷新(也就是说,没有刷新间隔)。 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。 在进行配置的时候还会分为一级缓存和二级缓存:
一级缓存:线程级别的缓存,是本地缓存,sqlSession级别的缓存
二级缓存:全局范围的缓存,不止局限于当前会话
1.一级缓存的使用 一级缓存是sqlsession级别的缓存,默认是存在的。在下面的案例中,大家发现我发送了两个相同的请求,但是sql语句仅仅执行了一次,那么就意味着第一次查询的时候已经将结果进行了缓存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Test public void test01 () { SqlSession sqlSession = sqlSessionFactory.openSession(); try { EmpDao mapper = sqlSession.getMapper(EmpDao.class); List<Emp> list = mapper.selectAllEmp(); for (Emp emp : list) { System.out.println(emp); } System.out.println("--------------------------------" ); List<Emp> list2 = mapper.selectAllEmp(); for (Emp emp : list2) { System.out.println(emp); } } catch (Exception e) { e.printStackTrace(); } finally { sqlSession.close(); } }
在大部分的情况下一级缓存是可以的,但是有几种特殊的情况会造成一级缓存失效:
1、一级缓存是sqlSession级别的缓存,如果在应用程序中只有开启了多个sqlsession,那么会造成缓存失效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @Test public void test02 () { SqlSession sqlSession = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); List<Emp> list = mapper.selectAllEmp(); for (Emp emp : list) { System.out.println(emp); } System.out.println("================================" ); SqlSession sqlSession2 = sqlSessionFactory.openSession(); EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class); List<Emp> list2 = mapper2.selectAllEmp(); for (Emp emp : list2) { System.out.println(emp); } sqlSession.close(); sqlSession2.close(); }
2、在编写查询的sql语句的时候,一定要注意传递的参数,如果参数不一致,那么也不会缓存结果
3、如果在发送过程中发生了数据的修改,那么结果就不会缓存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void test03 () { SqlSession sqlSession = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp empByEmpno = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno); System.out.println("================================" ); empByEmpno.setEname("zhangsan" ); int i = mapper.updateEmp(empByEmpno); System.out.println(i); System.out.println("================================" ); Emp empByEmpno1 = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno1); sqlSession.close(); }
4、在两次查询期间,手动去清空缓存,也会让缓存失效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void test03 () { SqlSession sqlSession = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp empByEmpno = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno); System.out.println("================================" ); System.out.println("手动清空缓存" ); sqlSession.clearCache(); System.out.println("================================" ); Emp empByEmpno1 = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno1); sqlSession.close(); }
2.二级缓存 二级缓存是全局作用域缓存,默认是不开启的,需要手动进行配置。
Mybatis提供二级缓存的接口以及实现,缓存实现的时候要求实体类实现Serializable接口,二级缓存在sqlSession关闭或提交之后才会生效。
1.缓存的使用 步骤:
1、全局配置文件中添加如下配置:
1 <setting name ="cacheEnabled" value ="true" />
2、需要在使用二级缓存的映射文件出使用标签标注
3、实体类必须要实现Serializable接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void test04 () { SqlSession sqlSession = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class); Emp empByEmpno = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno); sqlSession.close(); Emp empByEmpno1 = mapper2.findEmpByEmpno(1111 ); System.out.println(empByEmpno1); sqlSession2.close(); }
2.缓存的属性 eviction:表示缓存回收策略,默认是LRU
LRU:最近最少使用的,移除最长时间不被使用的对象
FIFO:先进先出,按照对象进入缓存的顺序来移除
SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInternal:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readonly:只读,true/false
true:只读缓存,会给所有调用这返回缓存对象的相同实例,因此这些对象不能被修改。
false:读写缓存,会返回缓存对象的拷贝(序列化实现),这种方式比较安全,默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 @Test public void test05 () { SqlSession sqlSession = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp empByEmpno = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno); sqlSession.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class); Emp empByEmpno2 = mapper2.findEmpByEmpno(1111 ); System.out.println(empByEmpno2); Emp empByEmpno3 = mapper2.findEmpByEmpno(1111 ); System.out.println(empByEmpno3); sqlSession2.close(); } @Test public void test05 () { SqlSession sqlSession = sqlSessionFactory.openSession(); EmpDao mapper = sqlSession.getMapper(EmpDao.class); Emp empByEmpno = mapper.findEmpByEmpno(1111 ); System.out.println(empByEmpno); sqlSession.close(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); EmpDao mapper2 = sqlSession2.getMapper(EmpDao.class); Emp empByEmpno2 = mapper2.findEmpByEmpno(1111 ); System.out.println(empByEmpno2); Emp empByEmpno3 = mapper2.findEmpByEmpno(1111 ); System.out.println(empByEmpno3); Emp empByEmpno4 = mapper2.findEmpByEmpno(7369 ); System.out.println(empByEmpno4); Emp empByEmpno5 = mapper2.findEmpByEmpno(7369 ); System.out.println(empByEmpno5); sqlSession2.close(); }
3、二级缓存的作用范围:
如果设置了全局的二级缓存配置,那么在使用的时候需要注意,在每一个单独的select语句中,可以设置将查询缓存关闭,以完成特殊的设置
1、在setting中设置,是配置二级缓存开启,一级缓存默认一直开启
1 <setting name ="cacheEnabled" value ="true" />
2、select标签的useCache属性:
在每一个select的查询中可以设置当前查询是否要使用二级缓存,只对二级缓存有效
3、sql标签的flushCache属性
增删改操作默认值为true,sql执行之后会清空一级缓存和二级缓存,而查询操作默认是false
4、sqlSession.clearCache()
只是用来清楚一级缓存
3.整合第三方缓存 在某些情况下我们也可以自定义实现缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。
1、导入对应的maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <dependency > <groupId > org.ehcache</groupId > <artifactId > ehcache</artifactId > <version > 3.8.1</version > </dependency > <dependency > <groupId > org.mybatis.caches</groupId > <artifactId > mybatis-ehcache</artifactId > <version > 1.2.0</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-api</artifactId > <version > 2.0.0-alpha1</version > </dependency > <dependency > <groupId > org.slf4j</groupId > <artifactId > slf4j-log4j12</artifactId > <version > 2.0.0-alpha1</version > <scope > test</scope > </dependency >
2、导入ehcache配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8" ?> <ehcache xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation ="http://ehcache.org/ehcache.xsd" > <diskStore path ="D:\ehcache" /> <defaultCache maxElementsInMemory ="1" maxElementsOnDisk ="10000000" eternal ="false" overflowToDisk ="true" timeToIdleSeconds ="120" timeToLiveSeconds ="120" diskExpiryThreadIntervalSeconds ="120" memoryStoreEvictionPolicy ="LRU" > </defaultCache > </ehcache >
3、在mapper文件中添加自定义缓存
1 <cache type ="org.mybatis.caches.ehcache.EhcacheCache" > </cache >