生命周期:
1.SqlSessionFactoryBuilder
作用是构建SqlSessionFactory,构建完就失去作用,等待回收.故其生命周期只存在于方法的局部.
2.SqlSessionFactory
作用是创建SqlSession(会话),SqlSession会创建多次,故SqlSessionFactory需一直保留.
其生命周期为MyBatis应用的生命周期,且其功能唯一,故为单例,每一个数据库只对应一个SqlSessionFactory
3.SqlSession
会话,相当于JDBC的Connection对象,生命周期是一次对数据库的处理请求.
需注意的是SqlSession线程不安全.可执行多条SQL,保证事务的一致性
4.Mapper
接口,无实现类,作用是发送SQL,是一个方法级别的东西,可视为一条SQL语句的执行,其最大范围和SqlSession相同
properties元素配置读取优先级:
读取顺序:
properties元素体内指定的元素->properties的文件:(resource指定的类路径下属性文件)或(url指定路径下属性文件)->方法参数传递的属性
优先级顺序:
要注意的是,先读取的属性会被后读取的属性所覆盖,所以优先级是与读取顺序颠倒的,如下:
方法参数传递的属性->properties的(resource指定的类路径下属性文件)或(url指定路径下属性文件)-->properties元素体内指定的元素
使用时建议使用properties文件,并避免混合使用多种方法赋值
typeHandler 类型处理器:
作用:
建立sql类型与java类型的对应关系
常用配置:
javaType(java类型),jdbcType(JDBC类型)
处理场景:
1.javaType -> jdbcType: 使用PreparedStatement(预处理语句)设置参数
2.jdbcType -> javaType: 使用ResultSet(结果集)取值
特殊字符串替换和处理(#和$)
#:
占位符号(编译好SQL语句再取值),会启用预编译(将字符串里的单引号'前加转义符号的反斜杠\,使其成为简单的string,而无法注入), 较安全,推荐
$:
sql拼接符号(取值以后再去编译SQL语句),不启用预编译,不安全,纯碎的 string 替换,一般用于传入数据库对象,例如传入字段名或表名(不能带单引号),所以MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
select * from user where name = #{name};
会解析成
select * from user where name = ?;
再替换成
select * from user where name = 'Jack';
而
select * from user where name = ${name};
会DBMS替换成
select * from user where name = 'Jack';
参数配置(注意不可以换行):
1.直接指定类型
select * from user where name = 'Jack';
2.指定typeHandler
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
3.设置精度或其他信息
#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
select:
传递参数(parameterType)的三种方式;
1.Map(parameterType="map"):丧失可读性,应废弃
2.@Param注解(无需定义parameterType):直观,简单,参数少(<=5)时优先考虑
3.JavaBean(parameterType="bean全称"):适用于参数较多时
返回结果处理的两种方式:
1.resultType:
简单映射,可处理int,double,float等基本类型(resultType="int"),或javaBean(resultType="类的全称")
2.resultMap:
复杂映射,指定自定义的resultMap的id完成映射(resultMap="myResult",会寻找id为"myResult"的resultMap完成自定义的规则映射)
resultMap中的映射规则:
配置property和column属性完成映射,其中property要与对象的属性名相同,但是实际匹配是将两者转化为大写形式再做判断,
即property的"username"可以匹配上对象的userName,但实际开发应尽量按统一规则设置
级联的N+1问题:
一个学生对应多门学科,通过一个学生id找到一个学生及其对应的n个学科id,
再根据n个学科id对学科表进行查询,共执行(1+n)次,从而导致性能下降
延迟加载:
目的是处理N+1问题,按需加载.
取出一个学生信息后不马上取出所有学科信息,而是需要的时候再发送sql,取出数据
默认是即时加载,多条sql一次性发送性能比较好.
开启延迟加载的两个全局参数:
1.lazyLoadingEnabled:是否开启延迟加载功能
2.aggressiveLazyLoading:对任意延迟加载属性的调用是否使其完整加载(否则为按需加载)
开启延迟加载的局部参数:
fetchType:eager(默认),lazy
使用时在association和collection元素加上fetchType属性值
缓存cache:
系统缓存:
1.一级缓存:SqlSession层次共享,默认开启,同一SqlSession,同一Mapper,同一参数,同一方法,会缓存
2.二级缓存:SqlSessionFactory层次共享,默认不开启,返回的POJO对象需实现Serializable接口