MyBatis简介

 
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录。
1.Mybatis的功能架构分为三层(图片借用了百度百科):
1)       API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
2)       数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
3)      基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

 

 

2.resultType和resultMap的区别
MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的(对应着我们的model对象中的实体),而resultMap则是对外部ResultMap的引用(提前定义了db和model之间的隐射key-->value关系),但是resultType跟resultMap不能同时存在。
 
在MyBatis进行查询映射时,其实查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值则是其对应的值。
①当提供的返回类型属性是resultType时,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap,只是当提供的返回类型属性是resultType的时候,MyBatis对自动的给把对应的值赋给resultType所指定对象的属性。
②当提供的返回类型是resultMap时,因为Map不能很好表示领域模型,就需要自己再进一步的把它转化为对应的对象,这常常在复杂查询中很有作用。
3.resultMap
 resultMap 是MyBatis 中最重要最强大的元素了。你可以让你比使用JDBC 调用结果集省掉90%的代码,也可以让你做许多JDBC 不支持的事。现实上,要写一个等同类似于交互的映射这样的复杂语句,可能要上千行的代码。ResultMaps 的目的,就是这样简单的语句而不需要多余的结果映射,更多复杂的语句,除了只要一些绝对必须的语句描述关系以外,再也不需要其它的。
resultMap属性:type为java实体类;id为此resultMap的标识。
 
 resultMap可以设置的映射:
 
1. constructor – 用来将结果反射给一个实例化好的类的构造器
a) idArg – ID 参数;将结果集标记为ID,以方便全局调用
b) arg –反射到构造器的通常结果
 
2. id – ID 结果, ,id为主键映射
 
3. result – result其他基本数据库表字段到实体类属性的映射
 
4. association – 复杂类型的结合;多个结果合成的类型
a) nested result mappings – 几resultMap 自身嵌套关联,也可以引用到一个其它上
 
5. collection –复杂类型集合a collection of complex types
 
6. nested result mappings – resultMap 的集合,也可以引用到一个其它上
 
7. discriminator – 使用一个结果值以决定使用哪个resultMap
 
 
 
 
3.4 association联合
联合元素用来处理“一对一”的关系。需要指定映射的Java实体类的属性,属性的javaType(通常MyBatis 自己会识别)。对应的数据库表的列名称。如果想覆写的话返回结果的值,需要指定typeHandler。
不同情况需要告诉MyBatis 如何加载一个联合。MyBatis 可以用两种方式加载:
1. select: 执行一个其它映射的SQL 语句返回一个Java实体类型。较灵活;
2. resultsMap: 使用一个嵌套的结果映射来处理通过join查询结果集,映射成Java实体类型。
 
例如,一个班级对应一个班主任。 首先定义好班级中的班主任属性:
private TeacherEntity teacherEntity; 
3.4.1使用select实现联合
 例:班级实体类中有班主任的属性,通过联合在得到一个班级实体时,同时映射出班主任实体。
 这样可以直接复用在TeacherMapper.xml文件中定义好的查询teacher根据其ID的select语句。而且不需要修改写好的SQL语句,只需要直接修改resultMap即可。
 
 ClassMapper.xml文件部分内容:
     <resultMap type="ClassEntity" id="classResultMap">  
         <id property="classID" column="CLASS_ID" />  
         <result property="className" column="CLASS_NAME" />  
         <result property="classYear" column="CLASS_YEAR" />  
         <association property="teacherEntity" column="TEACHER_ID" select="getTeacher"/>  
     </resultMap>  
       
     <select id="getClassByID" parameterType="String" resultMap="classResultMap">  
         SELECT * FROM CLASS_TBL CT  
         WHERE CT.CLASS_ID = #{classID};  
     </select>  

TeacherMapper.xml文件部分内容:

     <resultMap type="TeacherEntity" id="teacherResultMap">  
         <id property="teacherID" column="TEACHER_ID" />  
         <result property="teacherName" column="TEACHER_NAME" />  
         <result property="teacherSex" column="TEACHER_SEX" />  
         <result property="teacherBirthday" column="TEACHER_BIRTHDAY"/>  
         <result property="workDate" column="WORK_DATE"/>  
         <result property="professional" column="PROFESSIONAL"/>  
     </resultMap>  
       
     <select id="getTeacher" parameterType="String"  resultMap="teacherResultMap">  
         SELECT *  
           FROM TEACHER_TBL TT  
          WHERE TT.TEACHER_ID = #{teacherID}  
     </select> 
3.4.2使用resultMap实现联合
 与上面同样的功能,查询班级,同时查询器班主任。需在association中添加resultMap(在teacher的xml文件中定义好的),新写sql(查询班级表left join教师表),不需要teacher的select。
 
 修改ClassMapper.xml文件部分内容:
     <resultMap type="ClassEntity" id="classResultMap">  
         <id property="classID" column="CLASS_ID" />  
         <result property="className" column="CLASS_NAME" />  
         <result property="classYear" column="CLASS_YEAR" />  
         <association property="teacherEntity" column="TEACHER_ID"  resultMap="teacherResultMap"/>  
     </resultMap>  
       
     <select id="getClassAndTeacher" parameterType="String" resultMap="classResultMap">  
         SELECT *  
           FROM CLASS_TBL CT LEFT JOIN TEACHER_TBL TT ON CT.TEACHER_ID = TT.TEACHER_ID  
          WHERE CT.CLASS_ID = #{classID};  
     </select>

 

3.5 collection聚集

聚集元素用来处理“一对多”的关系。需要指定映射的Java实体类的属性,属性的javaType(一般为ArrayList);列表中对象的类型ofType(Java实体类);对应的数据库表的列名称;
不同情况需要告诉MyBatis 如何加载一个聚集。MyBatis 可以用两种方式加载:
1. select: 执行一个其它映射的SQL 语句返回一个Java实体类型。较灵活;
2. resultsMap: 使用一个嵌套的结果映射来处理通过join查询结果集,映射成Java实体类型。
 
例如,一个班级有多个学生。首先定义班级中的学生列表属性:
private List<StudentEntity> studentList;  

3.5.1使用select实现聚集

 用法和联合很类似,区别在于,这是一对多,所以一般映射过来的都是列表。所以这里需要定义javaType为ArrayList,还需要定义列表中对象的类型ofType,以及必须设置的select的语句名称(需要注意的是,这里的查询student的select语句条件必须是外键classID)。
 
ClassMapper.xml文件部分内容:
     <resultMap type="ClassEntity" id="classResultMap">  
         <id property="classID" column="CLASS_ID" />  
         <result property="className" column="CLASS_NAME" />  
         <result property="classYear" column="CLASS_YEAR" />  
         <association property="teacherEntity" column="TEACHER_ID"  select="getTeacher"/>  
         <collection property="studentList" column="CLASS_ID" javaType="ArrayList" ofType="StudentEntity" select="getStudentByClassID"/>  
     </resultMap>  
       
     <select id="getClassByID" parameterType="String" resultMap="classResultMap">  
         SELECT * FROM CLASS_TBL CT  
         WHERE CT.CLASS_ID = #{classID};  
     </select> 

StudentMapper.xml文件部分内容:

 

     <!-- java属性,数据库表字段之间的映射定义 -->  
     <resultMap type="StudentEntity" id="studentResultMap">  
         <id property="studentID" column="STUDENT_ID" />  
         <result property="studentName" column="STUDENT_NAME" />  
         <result property="studentSex" column="STUDENT_SEX" />  
         <result property="studentBirthday" column="STUDENT_BIRTHDAY" />  
     </resultMap>  
       
     <!-- 查询学生list,根据班级id -->  
     <select id="getStudentByClassID" parameterType="String" resultMap="studentResultMap">  
         <include refid="selectStudentAll" />  
         WHERE ST.CLASS_ID = #{classID}  
     </select> 

 

3.5.2使用resultMap实现聚集
 使用resultMap,就需要重写一个sql,left join学生表。
     <resultMap type="ClassEntity" id="classResultMap">  
         <id property="classID" column="CLASS_ID" />  
         <result property="className" column="CLASS_NAME" />  
         <result property="classYear" column="CLASS_YEAR" />  
         <association property="teacherEntity" column="TEACHER_ID"  resultMap="teacherResultMap"/>  
         <collection property="studentList" column="CLASS_ID" javaType="ArrayList" ofType="StudentEntity" resultMap="studentResultMap"/>  
     </resultMap>  
       
     <select id="getClassAndTeacherStudent" parameterType="String" resultMap="classResultMap">  
         SELECT *  
           FROM CLASS_TBL CT  
                LEFT JOIN STUDENT_TBL ST  
                   ON CT.CLASS_ID = ST.CLASS_ID  
                LEFT JOIN TEACHER_TBL TT  
                   ON CT.TEACHER_ID = TT.TEACHER_ID  
           WHERE CT.CLASS_ID = #{classID};  
     </select> 

 

 
 

基础知识参考  http://www.mybatis.org/mybatis-3/zh/getting-started.html

MyBatis中使用#和$书写占位符有什么区别?
答:#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在SQL中。注意:使用$占位符可能会导致SQL注射攻击,能用#的地方就不要使用$,写order by子句的时候应该用$而不是#

 

解释一下MyBatis中命名空间(namespace)的作用。
答:在大型项目中,可能存在大量的SQL语句,这时候为每个SQL语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在MyBatis中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个SQL语句就成了定义在这个命名空间中的一个ID。只要我们能够保证每个命名空间中这个ID是唯一的,即使在不同映射文件中的语句ID相同,也不会再产生冲突了。

145、MyBatis中的动态SQL是什么意思?
答:对于一些复杂的查询,我们可能会指定多个查询条件,但是这些条件可能存在也可能不存在,例如在58同城上面找房子,我们可能会指定面积、楼层和所在位置来查找房源,也可能会指定面积、价格、户型和所在位置来查找房源,此时就需要根据用户指定的条件动态生成SQL语句。如果不使用持久层框架我们可能需要自己拼装SQL语句,还好MyBatis提供了动态SQL的功能来解决这个问题。MyBatis中用于实现动态SQL的元素主要有:
- if
- choose / when / otherwise
- trim
- where
- set
- foreach

下面是映射文件的片段。

<select id="foo" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="content != null">
            and content = #{content}
        </if>
        <if test="owner != null">
            and owner = #{owner}
        </if>
   </select>

当然也可以像下面这些书写。

<select id="foo" parameterType="Blog" resultType="Blog">
        select * from t_blog where 1 = 1 
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="content != null">
                and content = #{content}
            </when>
            <otherwise>
                and owner = "owner1"
            </otherwise>
        </choose>
    </select>

再看看下面这个例子。

  <select id="bar" resultType="Blog">
        select * from t_blog where id in
        <foreach collection="array" index="index"
            item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </select>

 

posted @ 2018-01-04 10:29  daniel456  阅读(162)  评论(0编辑  收藏  举报