- 一、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(六)数据源、缓存机制、插件机制
在没使用绑定接口时,需要用SqlSession来进行增删改查,示例:
student user = (student) session.selectOne("test.studentMapper.selectUserByID", 1);
接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,直接调用接口方法就可以,这样比起原来了SqlSession提供的方法,有更加灵活的选择和设置。
接口绑定有两种实现方式:
就是在接口的方法上面加上 @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必须为接口的全路径名),示例:
mapper接口和mapper.xml之间需要遵循一定规则,才能成功的让mybatis将mapper接口和mapper.xml绑定起来:
- mapper接口的全限定名,要和mapper.xml的namespace属性一致;
- mapper接口中的方法名要和mapper.xml中的SQL标签的id一致;
- mapper接口中的方法入参类型,要和mapper.xml中SQL语句的入参类型一致;
- 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、Mapper接口方法名和mapper.xml中定义的每个sql的id相同。
2、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
3、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。
4、Mapper.xml文件中的namespace即是mapper接口的类路径`。 namespace示例:
1.3 接口绑定的相关问题 1.3.1 Mybatis中不同的xml映射文件,id是否可以重复select * from student where id=#{id}
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复。namespace不是必须的,只是最佳实践而已。
原因:namespace+id是作为Map
xml文件中,namespace和id的示例:
1.3.2 通常一个xml映射文件,都会写一个Dao接口与之对应,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗delete from emp where empno = #{empno}
Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:
com.mybatis3.mappers.StudentDao.findStudentById
可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
select id, first_name firstName, email, salary, dept_id deptID from employees where id = #{id}
在上面的例子中,first_name、dept_id是数据库表里的列名,firstName、deptID是实体类对应的属性名。
2.1.2 在Mapper映射文件中使用resultMap来自定义映射规则(最常用)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 student where id=#{id}
- 2、resultMap
当进行关联查询的时候,在返回结果的对象中还包含另一个对象的引用时,此时需要返回自定义结果集合(比如DTO对象等),使用resultMap,示例:
2.3 Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?select * from employees where id = #{id}
第一种是使用
第二种是使用sql列的别名功能,将列别名书写为对象属性名。
封装对象原理:有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
2.4 在mapper中如何传递多个参数 2.4.1 顺序传参法(不常用)public User selectUser(String name, int deptId);
select * from user where user_name = #{0} and dept_id = #{1}
#{}里面的数字代表传入参数的顺序(这种方法不建议使用,sql层表达不直观,且一旦顺序调整容易出错)。
2.4.2 @Param注解传参法(较常用) //使用 @param 注解:
public interface usermapper {
user selectuser(@param("username") string username,@param("password") string password);
}
select id, username, password from some_table where username = #{username} and password = #{password}
#{}里面的名称对应的是注解@Param括号里面修饰的名称。
2.4.3 Map传参法(常用)这种方法在参数不多的情况还是比较直观的,推荐使用。
public User selectUser(Mapparams);
select * from user where user_name = #{userName} and dept_id = #{deptId}
#{}里面的名称对应的是Map里面的key名称。
2.4.4 Java Bean传参法(常用)这种方法适合传递多个参数,且参数易变能灵活传递的情况。
public User selectUser(User user);
select * from user where user_name = #{userName} and dept_id = #{deptId}
#{}里面的名称对应的是User类里面的成员属性。
三、获取主键 3.1 代理主键和自然主键这种方法直观,需要建一个实体类,扩展不容易,需要加属性,但代码可读性强,业务逻辑处理方便,推荐使用。
- 自然主键是指事物属性中的自然唯一标示(例如身份证号);
- 代理主键是指与业务无关的,无意义的数字序列值;
- 在表设计时,优先推荐代理主键,不推荐自然主键(代理主键无意义,所以与业务解耦。另一方面,自然主键是自然界的事物,一般为字符串,处理麻烦)。
通常会将数据库表的主键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,则没有主键返回这一概念,而需要在插入之前先生成一个主键。此时可以用
使用<selectKey>标签来获取主键的方式不仅适用于不提供主键自增功能的数据库,也适用于提供主键自增功能的数据库。
selectKey 元素描述:
获取主键示例:
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 的功能。
即根据具体的参数条件,来对SQL语句进行动态拼接。Mybatis里的主要动态标签如下:
4.2.1 if 当满足test条件时,才会将
SELECT * FROM student WHERe age >= 18 AND name like '%${name}%'
当有多个条件判断时,需要和where标签合起来使用。示例:
4.2.2 chooseselect * from emp empno > #{empno} and ename = #{ename}
示例:
4.2.3 whereSELECT * FROM BLOG WHERe state = 'ACTIVE' AND title like #{title} AND author_name like #{author.name} AND featured = 1
4.2.4 trimSELECT * FROM BLOG state = #{state} AND title like #{title} AND author_name like #{author.name}
trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。示例:
select * from emp
empno > #{empno} and
ename like #{ename} and
sal > #{sal} and
4.2.5 foreach
用来做迭代拼接的,通常会与SQL语句中的IN查询条件结合使用,注意,到parameterType为List(链表)或者Array(数组),后面在引用时,参数名必须为list或者array。如在foreach标签中,collection属性则为需要迭代的集合,由于入参是个List,所以参数名必须为list。示例:
SELECT * FROM student WHERe id in #{item}
一个较完整的例子。接口中的定义:
public ListselectEmpByDeptnos(@Param("deptnos") List deptnos);
EmpDao.xml中的示例:
select * from emp where deptno in
#{deptno}
测试代码:
EmpDao mapper = sqlSession.getMapper(EmpDao.class);
List list = mapper.selectEmpByDeptnos(Arrays.asList(10, 20));
4.2.6 sql
可将重复的SQL片段提取出来,然后在需要的地方,使用
4.3 Mybatis如何执行批量操作 4.3.1 使用foreach标签SELECT * FROM user AND username like '%${user.name}%'
使用该方式时,其中一种方式是在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}
- 2、如果传入的是单参数且参数类型是一个array数组,collection的属性值为array,示例:
select * from t_blog where id in #{item}
- 3、如果传入的参数是多个,就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key。示例:
4.3.2 使用ExecutorType.BATCHINSERT INTO emp(ename,gender,email,did) VALUES (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id})
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);
}
五、其它相关问题 5.1 #{}和${} 5.1.1 两者的使用场景insert into employee(lastName,email,gender) values( #{lastName}, #{email}, #{gender} )
- 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,示例:
5.1.2 两者的区别SELECT count(1) FROM `user` WHERe name like '%${value}%'
- 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、一般能用#的就别用$。
模糊查询的写法不止一种。
- 1)’%${question}%’ 可能引起SQL注入,不推荐。
- 2)"%"#{question}"%" 注意:因为#{…}解析成sql语句时候,会在变量外侧自动加单引号’ ',所以这里 % 需要使用双引号" ",不能使用单引号 ’ ',不然会查不到任何结果。
- 3)CONCAt('%',#{question},'%') 使用CONCAt()函数,推荐。
- 4)使用bind标签(不常用)
5.3 Mybatis常用注解select id,sex,age,username,password from person where username LIKE #{pattern}
- @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标签之外,还有哪些标签?
还有很多其他的标签,
虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。
原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。
主要使用
- 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
- 2、多对一查询
多对一查询时,用到的标签为:association,写法示例:
5.7 Mybatis是否可以映射Enum枚举类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
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,105.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 映射文件中,



