SQL映射文件
SQL映射文件顶级元素配置
- mapper:映射文件的根元素点,只有一个属性namespace(命名空间),其作用如下:
- 用于区分不同的mapper,全局唯一
- 绑定dao接口,即面向接口编程(mapper.xml的namespace必须和接口同名)
- 在不同的mapper文件中,子元素的id可以相同(MyBatis通过namespace和子元素的id联合区分)
- cache:配置给定命名空间的缓存
- cache-ref:从其他命名空间引用缓存配置
- resultMap:用来描述数据库结果集和对象的对应关系
- sql:可重用的SQL块,也可以被其他语句引用
- insert:映射插入语句
- update:映射更新语句
- select:映射查询语句
- delete:映射删除语句
使用select
<!-- 根据供应商名称查询供应商列表(模糊查询) -->
<select id="getProviderListByproName" resultType="Provider"
parameterType="string">
SELECT * FROM smbms_provider WHERE proName LIKE CONCAT
('%',#{proName},'%')
</select>
- id
- 命名空间中唯一的标识符
- 接口中的方法与映射文件中的SQL语句id一一对应
- parameterType
- 传入SQL语句的参数类型
- 它支持基础数据类型和复杂数据类型
- 对于一个参数入参可以使用Java基础数据类型,通过#{参数名}取值
- 若是多参数入参,需要复杂参数数据类型来支持,包括Java实体类、Map,通过#{属性名}或#{Map的key}来获取传入的参数值
- 内建别名对大小写不敏感
- resultType
- SQL语句返回值类型的完整类名或别名
使用resultMap
<!-- 数据库字段名与pojo的属性名不一致时,自动映射 -->
<resultMap type="User" id="userList">
<result property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<result property="phone" column="phone" />
<result property="birthday" column="birthday" />
<result property="gender" column="gender" />
<result property="userRole" column="userRole" />
<result property="userRoleName" column="roleName" />
</resultMap>
<!-- 查询用户列表(参数:对象入参) -->
<select id="getUserList" resultMap="userList" parameterType="User">
SELECT u.*,r.`roleName` FROM `smbms_user` u,`smbms_role` r WHERE
u.`userName` LIKE CONCAT ('%',#{userName},'%') AND
u.`userRole`=#{userRole} AND
u.`userRole`=r.`id`
</select>
resultMap元素用来描述如何将结果集映射到Java对象,此处使用resultMap对列表展示所需的必要字段来进行自由映射,特别是当数据库的字段名和POJO中的属性名不一致的情况下,比如角色名称,字段名column是roleName,而User对象的属性名则为userRoleName,此时就要做映射。
resultMap元素的属性值和子节点
- id 属性:resultMap的唯一标识 (此id值用于select元素resultMap属性的引用)
- type属性:表示resultMap映射结果类型
- result子节点:
- id:一般对应数据库中该行的主键id,设置此项可提高MyBatis性能
- result:映射到JavaBean的某个“简单类型”属性
- association:映射到JavaBean的某个“复杂类型”属性,比如JavaBean类
- collection:映射到JavaBean的某个“复杂类型”属性,比如集合
resultType和resultMap的关联和区别:
resultType :直接表示返回类型
resultMap :对外部resultMap的引用,它的应用场景:数据库字段信息与对象属性不一致或者复杂的联合查询,自由控制映射结果。
二者不能同时存在,本质上都是Map数据结构
MyBatis对resultMap自动映射的三个匹配级别
- NONE:禁止自动匹配
- PARTIAL(默认):自动匹配所有属性,有内部嵌套(association,collection)的除外。
- FULL:自动匹配所有。
association
- 复杂的类型关联,一对一
- 内部嵌套
- 映射一个嵌套JavaBean属性
- 属性
- property:映射数据库列的实体对象的属性
- javaType:完整Java类名或者别名
- resultMap:引用外部resultMap
- 子元素
- id(即使不指定ID,MyBatis也会工作,但是会导致严重的性能开销,所以选择尽量少的属性来唯一表示结果,主键和联合主键均可)
- result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名(确保所有列名都是唯一无歧义的)
column:数据库列名或者别名
<!-- 结果映射 -->
<resultMap type="User" id="userRoleResult">
<id property="id" column="id" />
<result property="userCode" column="userCode" />
<result property="userName" column="userName" />
<result property="userRole" column="userRole" />
<association property="role" javaType="Role" resultMap="roleResult" />
</resultMap>
<resultMap type="Role" id="roleResult">
<id property="id" column="r_id" />
<result property="roleCode" column="roleCode" />
<result property="roleName" column="roleName" />
</resultMap>
<!-- 根据角色id查询用户列表 -->
<select id="getUserListByRoleId" parameterType="Integer"
resultMap="userRoleResult">
SELECT u.*,r.`id` AS r_id,r.`roleCode`,r.`roleName` FROM
smbms_user u,smbms_role r WHERE u.`userRole`=#{userRole} AND
U.`userRole`=R.`id`
</select>
collection
- 复杂类型集合,一对多
- 内部嵌套
- 映射一个嵌套结果集到一个列表
- 属性
- property:映射数据库列的实体对象的属性
- ofType:完整Java类名或者别名(集合所包括的类型)
- resultMap:引用外部resultMap
- 子元素
- id
- result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
<!-- 根据供应商id查询其相关信息和其下的所有订单 -->
<resultMap type="Provider" id="providerListResult">
<id property="id" column="id"/>
<result property="proCode" column="proCode"/>
<result property="proName" column="proName"/>
<result property="proContact" column="proContact"/>
<result property="proPhone" column="proPhone"/>
<collection property="billList" ofType="Bill">
<result property="billCode" column="billCode"/>
<result property="productName" column="productName"/>
<result property="totalPrice" column="totalPrice"/>
<result property="isPayment" column="isPayment"/>
</collection>
</resultMap>
<select id="getProListAndBillByProId" resultMap="providerListResult" parameterType="Integer">
SELECT p.*,b.`billCode`,b.`productName`,b.`totalPrice`,b.`isPayment`
FROM `smbms_provider` p,`smbms_bill` b
WHERE p.`id`=1
AND p.`id`=b.`providerId`
</select>
增删改(insert、update、delete)
<!-- 增加供应商信息 -->
<insert id="addProvider" parameterType="Provider">
INSERT INTO
smbms_provider(proCode,proName,proDesc,proContact,proPhone,proAddress,
proFax,createdBy,creationDate)
VALUES(#{proCode},#{proName},#{proDesc},
#{proContact},#{proPhone},#{proAddress},#{proFax},
#{createdBy},#{creationDate})
</insert>
<!-- 根据供应商id删除供应商信息 -->
<delete id="deleteProvider" parameterType="Integer">
delete from
smbms_provider where id=#{id}
</delete>
<!-- 根据供应商ID修改供应商信息 -->
<update id="updateProvider" parameterType="Provider">
UPDATE smbms_provider
SET
proCode=#{proCode},proName=#{proName},proDesc=#{proDesc},proContact=#{proContact},
proPhone=#{proPhone},proAddress=#{proAddress},proFax=#{proFax},modifyBy=#{modifyBy},
modifyDate=#{modifyDate}
WHERE id=#{id}
</update>
对于增删改这类数据库更新操作,需要注意的两点:
- 该类型的操作本身默认返回执行SQL影响的行数,所以DAO层的接口方法返回值一般设置为int类型。最好不要是boolean类型。
- insert、update、delete元素中军没有resultType属性,只有查询操作需要对返回结果类型(resultType/resultMap)进行相应的指定。
使用@Param注解实现多参数入参()
如修改密码的业务只需要传入两个参数(id和新密码)
<!-- 修改用户当前密码 -->
<update id="updatePwd">
UPDATE `smbms_user` SET
userPassword=#{userPassword}
WHERE id=#{id}
</update>
/**
* 修改当前用户密码
* @param id
* @param pwd
* @return
*/
public int updatePwd(@Param("id")Integer id,@Param("userPassword")String pwd);
在MyBatis中参数入参,何时需要封装成对象入参,何时又需要使用多参数入参?
- 超过4个以上的参数最好封装成对象入参
- 对于参数固定的业务方法,最好使用多参数入参。原因是这种方法比较灵活,代码可读性高,可以清晰地看出接口方法中所需的参数是什么。比如修改个人密码,根据用户id删除用户,根据用户id查看用户明细。
MyBatis 缓存
- 一级缓存
作用范围为session域内,当session flush或者close之后,该session中的所有cache就会被清空 - 二级缓存
二级缓存就是global caching,它超出session之外,可以被所有SqlSession共享,开启它只需要在MyBatis的核心配置文件(mybatis-config.xml) settings中设置即可。
一级缓存缓存的是SQL语句,二级缓存缓存的是结果对象。 - 缓存配置
- MyBatis的全局cache配置
- 在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的
- 在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache
<!-- MyBatis的全局cache配置-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 在Mapper XML文件中设置缓存,默认情况下是没有开启缓存的-->
<cache eviction="FIFO" flushInterval="60000"
size="512" readOnly="true"/>
<!-- 在Mapper XML文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache-->
<select id="selectAll" resultType="Emp"
useCache="true">