一、Mybatis概述:
1、简介:
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。
MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
2、官网:http://www.mybatis.org/mybatis-3/
中文官方文档:http://www.mybatis.org/mybatis-3/zh/index.html
3、特点:
1)支持自定义SQL、存储过程、及高级映射
2)实现自动对SQL的参数设置
3)实现自动对结果集进行解析和封装
4)通过XML或者注解进行配置和映射
5)实现Java对象与数据库表的映射转换
4、架构:
①MyBatis有两类配置文件:mybatis-condig.xml和xxxMapper.xml
a)mybatis-condig.xml,是MyBatis的全局配置文件,包含全局配置信息,如数据库连接参数、插件等。整个框架中只需要一个即可。
b)xxxMapper.xml,是映射文件,里面配置要执行的SQL语句,每个SQL对应一个Statement,可以有多个Mapper.xml文件。
②首先会通过SqlSessionFactoryBuilder来加载配置文件,生成一个SqlSessionFactor
a)会加载mybatis-config.xml和mapper.xml
b)加载mapper.xml的时候,顺便会对Sql进行编译,形成statement
③通过SqlSessionFactory建立连接,获取SqlSession对象
④MyBatis获取要执行的statement,进行自动参数设置
⑤SqlSession底层会通过Executor(执行器)来执行编译好的Statement,获取结果
⑥SQL的输入参数类型:POJO、HashMap、其他基本数据
⑦查询结果的输出形式:POJO、HashMap、其他基本数据
二、快速入门:
1、导入依赖:mybatis依赖包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
2、编写全局配置文件:外部配置,运行环境,数据源,指定所有的mapper映射文件
<properties resource="jdbc.properties"/>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper.xml"/>
<mapper resource="xxxMapper.xml"/>
<!-- class指定接口的全路径,要求xml文件必须和接口处于同一包下,并且名称完全相同(后缀名不同) -->
<!-- <mapper class="com.psm.mybatis.dao.UserDao"/> -->
<!-- 要求xml文件必须和接口处于同一包下,并且名称完全相同(后缀名不同) -->
<!-- <package name="com.psm.mybatis.dao"/> -->
<!-- 问题: java代码和xml耦合在一起,没有分离,分离交给和spring整合后来解决-->
</mappers>
3、编写Mapper.xml映射文件:因为mybatis动态代理的使用,书写时,要将namespace指定为接口的全路径
<mapper namespace="userMapper">
<!-- select标签定义一个查询操作
id是唯一标识,通常是接口的方法名称
resultType返回类型,通常是类型别名
resultMap返回类型,指向的是resultMap标签的id
-->
<select id="queryUserById" resultType="user">
select * from tb_user where id = #{id}
</select>
</mapper>
4、编写测试代码:
①指定全局配置文件的路径:String resource = "mybatis-config.xml";
②获取输入流,关联全局配置文件:InputStream inputStream = Resources.getResourceAsStream(resource);
③构建SqlSessionFactory:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
④获取SqlSession:SqlSession session = sqlSessionFactory.openSession();
⑤执行statement(动态代理),要指定两个参数:
//1、通过Mapper.xml中的 namespace + statement的ID来确定要执行哪个statement
// 2、SQL中需要接收的实际参数
User user = session.selectOne("userMapper.queryUserById", 1L);
5、程序执行流程:
①编写配置文件(全局配置文件mybatis-config.xml和所有的mapper.xml映射文件)
简单来说:就是准备JDBC连接参数以及要用到的Sql语句。
②加载配置,创建SqlSessionFactory
这里获取连接参数,获取Sql,对Sql进行预编译,形成statement。
③通过SqlSessionFactory创建SqlSession
这里就是调用了连接参数,连接数据库,形成会话。
④通过SqlSession执行statement,实现CRUD
给前面编译好的statement设置Sql参数,然后执行。
⑤通过SqlSession提交事务
⑥通过SqlSession关闭会话
6、userName为Null问题:
解决方案:①对查询的结果列使用别名 as
②开启自动驼峰匹配:<setting name="mapUnderscoreToCamelCase" value="true"/>
③结果集映射
三、完整的CRUD:
1、定义UserDAO接口
2、编写SQL到mapper.xml中
3、编写DAO实现类
4、使用工具生成测试类
5、编写测试代码
四、动态代理实现DAO:
1、CRUD代码分析:都是通过SqlSession调用的。
2、思路分析:动态代理接口
3、mybatis动态代理实现DAO
①规则:
1)每个DAO接口对应一个Mapper.xml文件
2)mapper.xml的namespace必须是接口的全名称
3)mapper.xml中的每个statement的id必须是接口中对应的方法名
4)statement中定义的resultType必须和接口中对应方法的返回值一致(这一点即便不是动态代理也得遵守)
5)在mybatis中,一般接口命名规则不是XxxDAO,而是XxxMapper,这一点不是必须的,但类似约定。
②新建Mapper
③修改UserMapper.xml文件
注意:1)namespace改成接口全名称
2)statement的id必须与方法名一致
④编写测试类
⑤总结:MyBatis动态代理生成DAO的步骤:
1)编写数据管理的接口XxxMapper
2)编写该接口对应的Mapper.xml
a)namespace必须与Mapper接口全名一致
b)statement的id必须和Mapper接口中的对应方法名一致
c)statement的resultType必须和Mapper接口中对应方法返回值一致
3)通过SqlSession的getMapper(XxxMapper.class)方法来获取动态代理的Mapper实现类对象
五、mybatis-config.xml全局配置文件详解:
1、Properties属性:引用外部的properties文件。
通过Properties引用外部属性文件后,可以通过${属性名}来引用外部文件中的属性值。
jdbc.properties:jdbc.username 编码规范,传参
2、settings设置:
①缓存全局开关:cacheEnabled
②延迟加载的全局开关:lazyLoadingEnabled、aggressiveLazyLoading
③是否开启自动驼峰命名规则:mapUnderscoreToCamelCase
3、typeAliases类型别名:
①单独定义:resultType=""
②扫描包:<package name="包路径" />
注意:Mybatis中的别名是不区分大小写的。但是一般建议大家严格按照类的简称来写。
4、typeHandler类型处理器
5、plugins插件:
MyBatis中的插件,其实类似于拦截器的效果,可以实现在MyBatis的整个运行流程中的 某些指定位置进行拦截:
Executor:对执行器进行拦截,上图括号内是可以拦截的方法
ParameterHandler:参数处理时进行拦截
ResultSetHandler:处理结果集,封装Java对象时进行拦截
StatementHandler:编译statement时进行拦截
6、Environment环境
7、Mappers映射器配置:
①使用项目资源路径:<mapper resource="xxxMapper.xml"/>
②使用url地址:<mapper url="file:///var/mappers/xxxMapper.xml"/>
③使用接口的全路径名称:<mapper class="接口全路径"/>
④配置扫描包:<package name="包名称"/>
六、Mapper.xml映射文件详解:
1、概述:映射语句
insert\update\delete\select
sql片段:sql
结果集映射:resultMap
2、CRUD操作:
①select
属性:id:这个statement的唯一标示
parameterType:输入参数类型,可选参数,mybatis可以自动推断数据类型
resultType:查询结果类型,如果结果是集合,请写集合内元素类型!
resultMap:结果集映射,这个和resultType 只能存在1个,应对复杂的结果集
②insert、update和delete
属性:id:这个statement的唯一标示
parameterType:输入参数类型,可选参数,mybatis可以自动推断数据类型
③insert语句实现ID回写
属性:useGenerateKeys:自增主键的回显功能,默认是false
④#{}的用法:预编译的占位符作用
#{属性名} 表示占位,和参数名无关 用注解@Param时,和参数名有关。
${} 表示拼接,和参数类型无关
一个参数时:基本类型或包装类、String类型、引用类型、HashMap类型
多个参数时:如果有多个参数,请使用@Param注解来指定参数名称,代码可读性好
#{0} #{1}、#{param1} #{param2}、#{userName} #{password} @Param
⑤${}的用法:${}底层其实使用的是OGNL表达式。
a)${}获取参数的方式:无论是1个参数,还是多个参数,都使用@Param注解,然后通过注解的中指定的名称取值。
一个参数时,MyBatis底层会把这个参数 以键为’value’的形式存入Map中,因此取值的时候,必须${value},或者通过@Param注解。
多个参数时,此时必须以${param1}、${param2}方式或者@Param注解方式来获取参数。
b)${}获取参数的问题:${}在取值时,并不会进行预编译,而是直接拼接SQL语句,无法防止SQL注入问题。
${}取值的时候,需要自己判断参数数据类型,如果是字符串,还得自己加引号:”${}”。
⑥面试题:#和$的区别与联系
区别:
1)#是占位符,会对SQL进行预编译,相当于?; $是做SQL拼接,有SQL注入的隐患
2)#不需要关注数据类型,Mybatis自动实现类型转换。 $必须自己判断数据类型
联系:
两者都支持通过@Param注解 指定参数名称,来获取参数值。推荐这种方式!
3、ResultMap 结果集映射
①概述:定义SQL查询的结果与Java对象的映射关系。
②解决字段名与列名不一致问题方案3:column property
③autoMapping自动映射:autoMapping="true"
4、SQL片段
七、动态SQL:
1、if
注意:
在写SQL时,我们使用了”%${name}%”来拼接SQL,这样在传参数时,可以只写姓名
这里也可以写#{name}来进行预编译,那么传参数时,就必须在参数中写上”%李%”了
2、choose,when,otherwise
动态标签中有if,但是没有else,如果我们有多条件,就需要用choose标签
choose中可以定义多个when和1个otherwise,所有状态中只能有一个成立:
多个when类似与if 和 else if,otherwise类似于最后的else。
3、where增加条件
4、set修改时,判断字段非空和非null
5、foreach循环
八、缓存:
1、一级缓存:session级别缓存,作用于当前会话。
特点:
①mybatis的一级缓存默认就是开启的,并且无法关闭。
②mybatis的一级缓存作用域是当前session,一次openSession()后,如果相同的statement和相同参数,则不进行查询而是从缓存命中并且返回,如果没有命中则查询数据库。
③任何的增删改操作都会导致缓存被清空。
④缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
2、二级缓存:SessionFactory级别缓存,作用于整个SessionFactory,多个会话之间可以共享缓存。
特点:
①二级缓存需要手动开启,开启的方式是在Mapper.xml中添加标签:<cache/>
②二级缓存的作用域是整个SessionFactory,如果namespace、statement和SQL参数一致,则缓存命中。
九、高级查询(表关联查询):
1、一对一查询
2、一对多查询
3、多对多查询
4、延迟加载:添加cglib依赖
十、有关xml中的特殊字符
1)使用特殊符合
2)使用CDATA