栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis(二)Mybatis的高级使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis(二)Mybatis的高级使用

文章目录
    • 一、Mybatis接口绑定
      • 1.1 接口绑定的实现方式
        • 1.1.1 通过注解绑定(不常用)
        • 1.1.2 通过xml里面写SQL来绑定(常用)
      • 1.2 使用MyBatis的mapper接口调用时的4个要求
      • 1.3 接口绑定的相关问题
        • 1.3.1 Mybatis中不同的xml映射文件,id是否可以重复
        • 1.3.2 通常一个xml映射文件,都会写一个Dao接口与之对应,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗
    • 二、Mapper和对象
      • 2.1 当实体类中的属性名和表中的字段名不一样时的处理方法
        • 2.1.1 写SQL语句时起别名(较常用)
        • 2.1.2 在Mapper映射文件中使用resultMap来自定义映射规则(最常用)
        • 2.1.3 配置map-underscore-to-camel-case属性(不常用)
      • 2.2 resultType和resultMap
      • 2.3 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
      • 2.4 在mapper中如何传递多个参数
        • 2.4.1 顺序传参法(不常用)
        • 2.4.2 @Param注解传参法(较常用)
        • 2.4.3 Map传参法(常用)
        • 2.4.4 Java Bean传参法(常用)
    • 三、获取主键
      • 3.1 代理主键和自然主键
      • 3.2 获取主键
        • 3.2.1 使用useGeneratedKeys和keyProperty属性
        • 3.2.2 使用< selectKey >子标签
    • 四、动态SQL
      • 4.1 Mybatis动态sql是做什么的
      • 4.2 动态sql
        • 4.2.1 if
        • 4.2.2 choose
        • 4.2.3 where
        • 4.2.4 trim
        • 4.2.5 foreach
        • 4.2.6 sql
      • 4.3 Mybatis如何执行批量操作
        • 4.3.1 使用foreach标签
        • 4.3.2 使用ExecutorType.BATCH
    • 五、其它相关问题
      • 5.1 #{}和${}
        • 5.1.1 两者的使用场景
        • 5.1.2 两者的区别
      • 5.2 模糊查询like语句该怎么写
      • 5.3 Mybatis常用注解
      • 5.4 Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
      • 5.5 Mybatis映射文件中,如果A标签通过include引用了B标签的内容,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?
      • 5.6 关联查询
      • 5.7 Mybatis是否可以映射Enum枚举类
      • 5.8 Mybatis是如何进行分页的?分页插件的原理是什么?
      • 5.9 简述Mybatis的插件运行原理,以及如何编写一个插件
      • 5.10 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?

本系列文章:
  Mybatis(一)Mybatis的基本使用
  Mybatis(二)Mybatis的高级使用
  Mybatis(三)配置文件解析流程
  Mybatis(四)映射文件解析流程
  Mybatis(五)SQL执行流程
  Mybatis(六)数据源、缓存机制、插件机制

一、Mybatis接口绑定 1.1 接口绑定的实现方式

  在没使用绑定接口时,需要用SqlSession来进行增删改查,示例:

   student user = (student) session.selectOne("test.studentMapper.selectUserByID", 1);

  接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,直接调用接口方法就可以,这样比起原来了SqlSession提供的方法,有更加灵活的选择和设置。
  接口绑定有两种实现方式:

1.1.1 通过注解绑定(不常用)

  就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;示例:

	//这种方式不用写mapper.xml
	@Select("select * from `tb_Teacher` where id = #{id}")
	public teacher  selectTeacherByID(int id);
1.1.2 通过xml里面写SQL来绑定(常用)

  全局配置文件和mapper.xml文件是最基本的配置,仍然需要。不过,这次不编写dao类,直接创建一个mapper接口。示例:

package com.test.mapper;

import com.test.po.Student;
import java.util.List;

public interface StudentMapper {
	List findAll();
	int insert(Student student);
	int delete(Integer id);
	List findByName(String value);
}

  mapper.xml文件(namespace必须为接口的全路径名),示例:


    
        SELECT * FROM student WHERe name like '%${value}%';
    

  mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来:

  1. mapper接口的全限定名,要和mapper.xml的namespace属性一致;
  2. mapper接口中的方法名要和mapper.xml中的SQL标签的id一致;
  3. mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致;
  4. mapper接口中的方法出参类型,要和mapper.xml中SQL语句的返回值类型一致。

  测试代码示例:

public class MapperProxyTest {
	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void init() throws IOException {
		InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
	}

	@Test
	public void test() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		List studentList = mapper.findAll();
		studentList.forEach(System.out::println);
	}
}

  结果示例:

  基于这个mapper接口,mybatis会自动找到对应的mapper.xml,然后对mapper接口使用动态代理的方式生成一个代理类。

1.2 使用MyBatis的mapper接口调用时的4个要求

  1、Mapper接口方法名和mapper.xml中定义的每个sql的id相同。
  2、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
  3、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
  4、Mapper.xml文件中的namespace即是mapper接口的类路径`。 namespace示例:

	    
    	标签,都会被解析为一个MappedStatement对象。
  Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
  Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

二、Mapper和对象 2.1 当实体类中的属性名和表中的字段名不一样时的处理方法 2.1.1 写SQL语句时起别名(较常用)
	
		select * from employees where id = #{id}
	
	
	
    
    	
    	
    	
    	
    	
    	
    	
    

  在上面的例子中,last_name、dept_id是数据库中表的列名,lastName、deptId是实体类的属性名。

2.1.3 配置map-underscore-to-camel-case属性(不常用)

  该种方式最不常用,因为作用有限。该属性设置为true后,数据库中的下划线格式的字段名可以自动转换成Java代码中的驼峰格式,比如数据库的user_name和实体类属性:userName。但这种方式严格要求数据库中的字段名和Java代码中的属性名要有对应关系,才能完成字段名转换。

  • 1、application.yml配置map-underscore-to-camel-case示例
#mybatis配置
mybatis:
  typeAliasesPackage: com.example.mybaitsxml.dao.entity
  mapperLocations: classpath:mapper/*.xml
  configLocation: classpath:/mybatis-config.xml
  • 2、mybatis-config.xml配置map-underscore-to-camel-case示例
	
	    
	    
		    
	    
	
2.2 resultType和resultMap

  MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,但是resultType跟resultMap不能同时存在。

  • 1、resultType
      表示返回的结果的类型,此类型只能返回单一的对象(比如Integer、String等)。
      当返回的结果是一个集合的时候,并不需要resultMap,只需要使用resultType指定集合中的元素类型即可。示例:
	    
	    
		select * from employees where id = #{id}
	
	
	
    
    	
    	
    	
    	
    	
    	
    	
    
2.3 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

  第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。
  第二种是使用sql列的别名功能,将列别名书写为对象属性名。

  封装对象原理:有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

2.4 在mapper中如何传递多个参数 2.4.1 顺序传参法(不常用)
	public User selectUser(String name, int deptId);
	
         select id, username, password
         from some_table
         where username = #{username}
         and password = #{password}
	

  #{}里面的名称对应的是注解@Param括号里面修饰的名称。

这种方法在参数不多的情况还是比较直观的,推荐使用。

2.4.3 Map传参法(常用)
	public User selectUser(Map params);
	
	    select * from user
	    where user_name = #{userName} and dept_id = #{deptId}
	

  #{}里面的名称对应的是User类里面的成员属性。

这种方法直观,需要建一个实体类,扩展不容易,需要加属性,但代码可读性强,业务逻辑处理方便,推荐使用。

三、获取主键 3.1 代理主键和自然主键
  1. 自然主键是指事物属性中的自然唯一标示(例如身份证号);
  2. 代理主键是指与业务无关的,无意义的数字序列值;
  3. 在表设计时,优先推荐代理主键,不推荐自然主键(代理主键无意义,所以与业务解耦。另一方面,自然主键是自然界的事物,一般为字符串,处理麻烦)。
3.2 获取主键

  通常会将数据库表的主键id设为自增。在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,在插入一条记录后,有两种方式得到数据库自动生成的这条记录的主键id。

3.2.1 使用useGeneratedKeys和keyProperty属性

  示例:

	
        INSERT INTO student (name,score,age,gender) 
        VALUES (
        	#{name},
        	#{score},
        	#{age},
        	#{gender}
        );
    

  该方式适用于支持主键自增的数据库(Mysql、Sql server)。
  有三个地方可以设置useGeneratedKeys=true参数:

  • 1、在setting元素中设置 useGeneratedKeys参数
      在setting元素中设置的useGeneratedKeys是一个全局的参数,但是只是对接口接口映射器产生影响,对xml映射器无效。示例:
 
     
     

  代码中就可以获取ID了:

public interface TestMapper { 
    // 受全局useGeneratedKeys参数控制,添加记录之后将返回主键id 
    @Insert("insert into test(name,descr,url,create_time,update_time) values(#{name},#{descr},#{url},now(),now())") 
    Integer insertOneTest(Test test);
}
  • 2、在XML映射器中配置useGeneratedKeys参数
      示例:
	 
	 
    	insert into test(name,descr,url,create_time,update_time) 
    	values(
    		#{name},
    		#{descr},
    		#{url},
    		now(),
    		now()
    	) 
	
  • 3、在接口映射器中设置useGeneratedKeys参数
      示例:
	// 设置useGeneratedKeys为true,返回数据库自动生成的记录主键id 
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    @Insert("insert into test(name,descr,url,create_time,update_time) values(#{name},#{descr},#{url},now(),now())") 
    Integer insertOneTest(Test test);

  该类设置方式优先级高于第一种方式。

3.2.2 使用< selectKey >子标签

  示例:


        INSERT INTO student (name,score,age,gender) 
        VALUES (#{name},#{score},#{age},#{gender});
        
            SELECT LAST_INSERT_ID();
        
    

  如果使用的是Mysql这样的支持自增主键的数据库,可以简单的使用第一种方式。对于不支持自增主键的数据库,如Oracle,则没有主键返回这一概念,而需要在插入之前先生成一个主键。此时可以用标签,设置其order属性为BEFORE,并在标签体内写上生成主键的SQL语句,这样在插入之前,会先处理,生成主键,再执行真正的插入操作。

  使用<selectKey>标签来获取主键的方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。

  selectKey 元素描述:

  标签其实就是一条SQL,这条SQL的执行,可以放在主SQL执行之前或之后,并且会将其执行得到的结果封装到入参的Java对象的指定属性上。注意子标签只能用在标签中。上面的LAST_INSERT_ID()实际上是MySQL提供的一个函数,可以用来获取最近插入或更新的记录的主键id。

  获取主键示例:

public class MapperProxyTest {
	private SqlSessionFactory sqlSessionFactory;

	@Before
	public void init() throws IOException {
		InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
		sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
	}

	@Test
	public void test() {
		SqlSession sqlSession = sqlSessionFactory.openSession();
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		Student student = new Student(-1, "Podman", 130, 15, 0);
		mapper.insert(student);
		sqlSession.commit();
		System.out.println(student.getId());
	}
}
四、动态SQL 4.1 Mybatis动态sql是做什么的
  • 1、Mybatis的动态sql可以在xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
  • 2、Mybatis 提供了9种动态sql标签:
	trim|where|set|foreach|if|choose|when|otherwise|bind
  • 3、其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。
4.2 动态sql

  即根据具体的参数条件,来对SQL语句进行动态拼接。Mybatis里的主要动态标签如下:

4.2.1 if

  当满足test条件时,才会将标签内的SQL语句拼接上去。示例:

	
        select * from emp
        
            
                empno > #{empno}
            
            
                and ename = #{ename}
            
        
	
4.2.2 choose

  示例:


	
  		SELECT * FROM BLOG
  		
    		
         		state = #{state}
    		
    		
        		AND title like #{title}
    		
    		
        		AND author_name like #{author.name}
    		
  		
	
4.2.4 trim

  标签可以用标签代替。
  trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。示例:

 
    
        SELECT * FROM student WHERe id in
        
             #{item}
        
	

  一个较完整的例子。接口中的定义:

	public List selectEmpByDeptnos(@Param("deptnos") List deptnos);

 EmpDao.xml中的示例:

    
    
		SELECT * FROM user
		
	

	
     	
        	
         		AND username like '%${user.name}%'
         	
       
	
4.3 Mybatis如何执行批量操作 4.3.1 使用foreach标签

  使用该方式时,其中一种方式是在db链接url后面带一个参数:&allowMultiQueries=true,示例:

jdbc.url=jdbc:mysql://localhost:3306/common_mapper?useUnicode=true
	&characterEncoding=utf8&allowMultiQueries=true

  示例:

	
    	
    		update tb_question_template_seleteitem_detail 
    		set selectedName = #{item.selectedName}
    		where 1=1 and selectedId = #{item.selectedId}
    	
  	

  foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach标签的属性主要有item,index,collection,open,separator,close。

  • item   表示集合中每一个元素进行迭代时的别名,随便起的变量名;
  • index   指定一个名字,用于表示在迭代过程中,每次迭代到的位置,不常用;
  • open   表示该语句以什么开始,常用“(”;
  • separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;
  • close   表示以什么结束,常用“)”。

  以下为不使用&allowMultiQueries=true的示例。
  在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:

  • 1、如果传入的是单参数且参数类型是一个List,collection属性值为list,示例:
 	
     select * from t_blog where id in
     
          #{item}
     
     
  • 3、如果传入的参数是多个,就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。示例:

 

    INSERT INTO emp(ename,gender,email,did)
    VALUES
    
        (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
    

4.3.2 使用ExecutorType.BATCH

  Mybatis内置的ExecutorType有3种,默认为simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优; 但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的。具体用法如下:

//批量保存方法测试
@Test  
public void testBatch() throws IOException{
    SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
    //可以执行批量操作的sqlSession
    SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);

    try {
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        for (int i = 0; i < 1000; i++) {
            mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
        }

        openSession.commit();
    } finally {
        openSession.close();
    }
}

  mapper和mapper.xml如下:

public interface EmployeeMapper {   
    //批量保存员工
    Long addEmp(Employee employee);
}

    
        insert into employee(lastName,email,gender)
        values(
        	#{lastName},
        	#{email},
        	#{gender}
        )
    

五、其它相关问题 5.1 #{}和${} 5.1.1 两者的使用场景
  • 1、用#{}获取实体类属性
      如果入参类型是pojo,比如是Student类:
public class Student{
	private String name;
    private Integer age;
    //...
}

  #{name}表示取入参对象Student中的name属性,#{age}表示取age属性,这个过程是通过反射实现的。

  • **2、用KaTeX parse error: Expected 'EOF', got '&' at position 11: {}做模糊查询** &̲emsp; `{},一般会用在模糊查询的情景,比如SELECT * FROM student WHERe name like '% n a m e {name}%'`。它的处理阶段在`#{}`之前,它不会做参数类型解析,而仅仅是做了字符串的拼接,若入参的Student对象的name属性为zhangsan,则上面那条SQL最终被解析为`SELECt * FROM student WHERe name like '%zhangsan%'`。如果此时用的是`SELECt * FROM student WHERe name like '%#{name}%'`,这条SQL最终就会变成`SELECt * FROM student WHERe name like '%'zhangsan'%'`,所以模糊查询只能用` name{}`。
  • 3、用#{}传入参数
      普通的入参也可以用${},但由于${}不会做类型解析,就存在SQL注入的风险,比如:
	SELECt * FROM user WHERe name = '${name}' AND password = '${password}'

  假如password属性为'OR '1' = '1,最终的SQL会变成:

	SELECt * FROM user WHERe name = 'test' AND password = ''OR '1' = '1'

  因为OR '1' = '1'恒成立,这个where条件就不起作用了。

  • 4、用#{}传入基本类型参数
      对于简单类型(8种Java原始类型再加一个String)的入参,${}中参数的名字必须是value,示例:

        SELECT count(1) FROM `user` WHERe name like '%${value}%'

5.1.2 两者的区别
  • 1、#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。
      Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为"?",调用PreparedStatement的set方法来赋值。
      Mybatis在处理 $ {}时,就是把${}替换成变量的值。
  • 2、#{}方式能够很大程度防止sql注入,原因在于预编译机制;${}方式无法防止Sql注入。
  • 3、$方式一般用于传入数据库对象。
      当需要传入动态的表名,列名的时候就需要使用${},就是最直接的拼接字符串的行为。示例:
	#拼接出的表名示例:2016_salary
	select * from ${year}_salary where ...

    当排序时:按某个字段排序,升降序也需要使用${}来指定,因为SQL是不支持将排序填充进去的,必须一开始就指定(同表名)。示例:

	select .. from .. order by xxx xxx
  • 4、MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。
  • 5、一般能用#的就别用$。
5.2 模糊查询like语句该怎么写

  模糊查询的写法不止一种。

  • 1)’%${question}%’ 可能引起SQL注入,不推荐。
  • 2)"%"#{question}"%" 注意:因为#{…}解析成sql语句时候,会在变量外侧自动加单引号’ ',所以这里 % 需要使用双引号" ",不能使用单引号 ’ ',不然会查不到任何结果。
  • 3)CONCAt('%',#{question},'%') 使用CONCAt()函数,推荐。
  • 4)使用bind标签(不常用)
	
	  
	  select id,sex,age,username,password 
	  from person 
	  where username LIKE #{pattern}
	
5.3 Mybatis常用注解
  • @TableName
      @TableName注解用来将指定的数据库表和JavaBean 进行映射。示例:
@TableName("user")
public class UserBean {
    // ...
}
  • @TableId
      该注解用于将某个成员变量指定为数据表主键。示例:
@TableName("user")
public class UserBean {
   @TableId(value = "user_id", type = IdType.AUTO)
   private Integer userId;
}
  • @Param
      @Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中。示例:
	public int getUsersDetail(@Param("userid") int userid);
  • @TableField
      该注解用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射。示例:
@TableName(value = "user")
public class UserBean {
   @TableId(value = "user_id", type = IdType.AUTO)
   private String userId;
    
   @TableField("name")
   private String name;
    
   @TableField("sex")
   private String sex;
    
   @TableField("age")
   private Integer age;
}
  • @Mapper
      使用@Mapper注解要定义成一个接口interface。示例:
@Mapper
public interface Inter {
    @select("select * from sysuser where userid=#{id}")
    int queryUserByid(int id);
}
  • @MapperScan
      使用@MapperScan进行注解,一次性注解多个包。示例:
@SpringBootApplication  
@MapperScan({"com.kfit.demo","com.kfit.user"})  
public class App {  
    public static void main(String[] args) {  
       SpringApplication.run(App.class, args);  
    }  
} 
5.4 Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

  还有很多其他的标签,,加上动态sql的9个标签trim|where|set|foreach|if|choose|when|otherwise|bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。

5.5 Mybatis映射文件中,如果A标签通过include引用了B标签的内容,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面?

  虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。
  原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。

5.6 关联查询

  主要使用标签以及和子标签,进行关联查询。

  • 1、一对多查询
      以一个Category对应多个Product为例,一对多查询时,用到的标签为collection,写法示例:
    
        
            
            
     
            
            
            
                
                
                
            
        
     
        
        
            select 
            	c.*, 
            	p.*, 
            	c.id 'cid', 
            	p.id 'pid', 
            	c.name 'cname', 
            	p.name 'pname' 
            from category_ c 
            left join product_ p on c.id = p.cid
           
    
5.7 Mybatis是否可以映射Enum枚举类

  Mybatis可以映射枚举类。不单可以映射枚举类,Mybatis 可以映射任何对象到表的一列上。映射方式为自定义一个 TypeHandler,实现TypeHandler 的 setParameter()和getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 setParameter()和 getResult()两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。

5.8 Mybatis是如何进行分页的?分页插件的原理是什么?

  Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
  分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
  举例,原来的语句:

	select * from student

  拦截sql后重写为:

	select t.* from (select * from student)t limit 0,10
5.9 简述Mybatis的插件运行原理,以及如何编写一个插件

  Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。实现 Mybatis 的 Interceptor 接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,还需要在配置文件中配置你编写的插件。

5.10 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?

  Mybatis将所有Xml配置信息都封装到重量级对象Configuration内部。在Xml 映射文件中,标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。每一个