在映射器中,我们主要可以定义如下几类元素:
- select 查询,可以自定义查询参数和返回结果
- insert 插入,执行后返回一个整型,代表插入的条数
- update、delete
- sql 允许定义一部分SQL,在其它地方应用它
- resultMap 用来描述数据库结果集返回对象(和select中的resultType作用相同,select中只能二选一)
- cache、cache-ref 定义和引用缓存策略
1. select
map文件
<mapper namespace="com.demo.mybatis.mapper.RoleDAO"> <resultMap id="roleMap" type="role"> <id column="id" property="id" javaType="int" jdbcType="INTEGER"/> <result column="role_name" property="roleName" jdbcType="VARCHAR" javaType="string"/> <!--<result column="sex" property="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>--> <result column="sex" property="sex" typeHandler="com.demo.mybatis.handler.MaleTypeHandler"/> </resultMap> <select id="getRole" parameterType="int" resultMap="roleMap"> SELECT * FROM t_role WHERE id=#{id} </select> </mapper>
Mapper接口
public interface RoleDAO { Role getRole(Integer id); }
1.1 自动映射配置
在名etting的两个关于自动映射的配置参数
- autoMappingBehavior 默认为true ,表示启动自动映射,这样select出来的列就可以自动更具列名自动映射到POJO中的属性
- mapUnderscoreToCamelcase 默认为false,表示提供数据库的下划线命名方式与java中的驼峰命名方式之间的映射转化
- 非自动映射下,通过resultMap中的<result>来配置,如
<resultMap id="roleMap" type="role">
<id column="id" property="id" javaType="int" jdbcType="INTEGER"/>
<result column="role_name" property="roleName" jdbcType="VARCHAR" javaType="string"/>
<!--<result column="sex" property="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>-->
<result column="sex" property="sex" typeHandler="com.demo.mybatis.handler.MaleTypeHandler"/>
</resultMap>
1.2 传递多个参数的情况
- 1. 使用@param("xxxx")来传递
- 2. 把Mapper接口中的函数入参包装成POJO对象,在XML中直接使用POJO中属性
- 3. 把Mapper接口中的函数入参包装成Map对象,在XML中直接使用map中key
说明:当参数形式固定时,使用第一二种。参数数量较少时,使用第一种;数量较多时使用第二种
2. insert
<insert id="insert" parameterType="string">
INSERT into t_role (role_name) VALUES (#{roleName})
<!--
INSERT into t_role (role_name) VALUES (#{roleName javaType=string, jdbcType=VARCHAR, typeHandler=com.demo.mybatis.handler.MyStringTypeHandler})
-->
</insert>
2.1 插入时主键回填
定义好主键属性,同时设置userGeneratedKeys=true ,当插入成功后,原POJO中的主键属性会被回填值
3. 参数
- #{param}与${param}的区别
${param}是直接引入参数,如当传入的param为列名、表名时可以使用,select ${param} from table_1,此时需要注意sql的安全性
#{param} 把参数当做sql语句参数映入,会做一定的自动转化或处理,这样会增加sql的安全性
- 参数配置
当传入的参数需要进行一些特殊处理,或者需要确定使用哪个typeHandler进行处理时,需要用到参数配置
1. 指定类型
2. 指定类型和typeHandler
3. 指定保存精度
- 对存储过程的支持
存储过程存在三种参数:输入(IN),输出(OUT),输入输出(INOUT)。Mybatis都提供了良好的支持
4. sql元素
sql元素还可以包含属性
5. resultMap元素
<resultMap id="test" type="java.test"> <constructor> <!--构造函数及参数--> <idArg></idArg> <arg></arg> </constructor> <id></id> <!--id字段--> <result></result> <!--普通字段--> <!--一对一关系,调用其它mapper的相应函数获取数据--> <association property="pojoProperty" column="sqlColumn" select="xxx.mapper.Mapper.findXXX"> </association> <!--一对多关系,调用其它mapper的相应函数获取数据--> <collection property=""></collection> <!--根据字段来判断类型--> <discriminator javaType="" column=""> <case value=""></case> </discriminator> </resultMap>
6. 级联的问题
- 级联深度太深(超过三层)时,不宜使用 ->性能问题,且不利于理解和维护
- 如果一个表绑定了太多级联关系,会导致一个关系多执行一条sql语句,这样会导致性能下降,也称为N+1问题
- 通过延迟加载策略解决N+1问题
- 对很紧密的级联关系可以采用即时加载,非频繁字段采用延迟加载
- setting中的用于控制延迟策略的两个全局参数:
1. lazyLoadingEnabled 默认为false,代表不启动延迟加载
2. aggressiveLazyLoading 对延迟加载的属性调用会触发其它带有延迟加载的属性进行加载
- <association>和<collection>中的 fetchType属性控制为局部开关,有eager和lazy两种取值
- 在Mybatis中,延迟加载通过动态代理(早期采用cglib,新版采用javassist)实现,通过对返回对象POJO进行代理,保存相关sql和参数,并增加判断逻辑,监控具有延迟加载的属性获取方法,一旦发生调用,就执行加载逻辑
7. 缓存问题
Mybatis提供了一级缓存和二级缓存,默认只开启一级缓存
- 一级缓存只在同一个SqlSession中共享
- 二级缓存在SqlSessionFactory层面共享,只能看到其它SqlSession.commit()之后的缓存变化
- 二级缓存需要POJO实现了Serializable接口
- 配置缓存使用<cache type="xxxx"/>
- Mybatis支持自定义缓存,比如现在流行的Redis缓存服务器,自定义缓存需要实现如下接口:
- 定制sql级的缓存策略