目录
一、预习检查
1、列举下SQL映射文件的几个顶级元素 2、MyBatis多参数入参有几种处理方式? 3、mapper元素的namespace属性的作用是什么? 4、不同的SQL映射文件,元素的id必须不同吗? 5、谈谈你对association和collection元素的理解
二、上章回顾
MyBatis基本要素:
核心对象 最佳生命周期 SqlSessionFactoryBuilder 局部变量 SqlSessionFactory 从应用服务启动开始一直到应用服务停止 SqlSession 一次请求的有效期 核心对象 SqlSessionFactoryBuilder SqlSessionFactory SqlSession 通过namespace+id运行映射的SQL语句 基于Mapper接口的方式执行SQL语句 核心配置文件 properties typeAliases environments mappers SQL映射文件
三、本章目标
1、掌握基于SQL映射文件的增删改查操作 2、掌握为SQL映射文件传递参数的方法 3、掌握使用resultMap映射查询结果 4、了解MyBatis框架中缓存的使用方法
四、SQL映射的XML文件
MyBatis真正的特色在于SQL映射语句,功能强大,使用简单
SQL映射文件的几个顶级元素
mapper – SQL映射文件的根元素,有一个namespace属性 cache – 配置给定命名空间的缓存 cache-ref – 从其他命名空间引用缓存配置 resultMap – 用来描述数据库结果集和对象的对应关系 sql – 可以重用的SQL块,也可以被其他语句引用 insert – 映射插入语句 update – 映射更新语句 delete – 映射删除语句 select – 映射查询语句
五、mapper
mapper namespace属性,区别不同的mapper namespace和子元素的id联合保证唯一 绑定DAO接口 namespace的命名必须跟某个接口同名 接口中的方法与映射文件中SQL语句id一一对应
示例:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace 绑定一个对应的dao/mapper接口--> <mapper namespace="cn.cvs.mapper.SysUserMapper"> <!--查询全部用户信息--> <select id="getUserList" resultType="cn.cvs.pojo.SysUser"> SELECT * FROM `t_sys_user` </select> </mapper> 1234567891011注意事项:接口中的方法与映射文件中的sql语句ID一一对应
package cn.cvs.mapper; import cn.cvs.pojo.SysUser; import java.util.List; /** * @Created by Aiden * @Date 2022 */ public interface SysUserMapper { /** * 查询全部用书信息 * @return */ List<SysUser> getUserList(); } 1234567891011121314
六、select单一条件查询
select是MyBatis中最常用的元素之一 select元素有很多属性,可以详细配置每一条查询语句
id 命名空间中唯一的标识符 接口中的方法与映射文件中的SQL语句id一一对应 parameterType 传入SQL语句的参数类型 resultType SQL语句返回值类型的完整类名或别名
七、select多条件查询
教学思路: 抛出问题,根据项目截图说明,在查询的时候经常会多条件查询, 引申到增加和修改功能,参数可能会更多
parameterType
使用复杂数据类型 1)Java实体类 2)Map 3)通过 #{属性名} 或者 #{map的keyName} 获取传入的值 使用多个简单数据类型 1)int、String、Date等,一个参数传递单一数值 2)使用==@Param注解==为参数命名,通过 #{参数名} 获取传入的值
教学指导: 演示案例,改造上个案例,把paramteterType改为 对象入参和Map 入参 \==注意:==对于多个参数入参的方式,建议使用@Param注解为参数命名
八、resultMap
问题:
按条件查询得到用户表列表,需要显示指定字段,并显示用户角色名称(中文表述) 用户表中的roleId字段记录的是角色id,不是其对应的名称,此时该怎办呢?
问题分析:
修改SysUser实体类,增加userRoleName属性 修改查询SQL语句,连表查询roleName字段 实体类属性名于查询结果字段名不一致
解决方案: 1、可以修改sql语句和pojo,可以使用resultType做自动映射(需要注意的是:字段名和属性名是否一致,若不一致,那么需要给字段起别名,变成一致),对于列表要求显示指定字段(可以通过sql查询字段来控制) 2、推荐第二种方案:字段名不一致,并且显示指定列,通过resultMap来映射自定义结果
九、resultMap将结果集映射到Java对象
1.先在SysUser类中添加 userRoleName字段
public class SysUser{ private String userRoleName;//用户角色名字 public String getUserRoleName() { return userRoleName; } public void setUserRoleName(String userRoleName) { this.userRoleName = userRoleName; } } 12345678910112.在SysUserMapper.xml文件中添加如下配置
<resultMap id="userWithRoleName" type="SysUser"> <id property="id" column="id"/> <!--注意:要确保所有的别名或者字段名都是唯一且无歧义的--> <result property="userRoleName" column="roleName"/> </resultMap> <select id="getUserListWithRoleName" resultMap="userWithRoleName" parameterType="sysuser"> select u.*, r.roleName from t_sys_user u, t_sys_role r where u.realName like CONCAT ('%', #{realName}, '%') and u.roleId = #{roleId} and u.roleId = r.id </select> 12345678910
十、resultMap元素
resultMap元素的属性 id:resultMap的唯一标识 type:映射的结果类型 resultMap元素的子元素 id:指定和数据表主键字段对应的标识属性 设置此项可提高MyBatis性能 result:指定结果集字段和实体类属性的映射关系 association:映射“多对一”或“一对一”关系 (模型包含模型) collection: 映射“一对多”关系 (模型包含集合)
十一、嵌套结果映射之association
association 复杂的关联类型,映射一个嵌套JavaBean属性 多对一或一对一 属性,
第一个属性是“关联的嵌套映射”,该属性的标签名称为“association”。在resultMap中,当映射type为Java包装类时,可能会遇到包装类中含有其他Java包装类的属性,这里resultMap提供了association标签来定义结果集中包含的其他结果集。
association
复杂的关联类型,映射一个嵌套JavaBean属性
多对一或一对一
属性
property:用来映射查询结果子集的实体属性
javaType:完整Java类名或者别名
resultMap:引用外部resultMap子元素
id
result
十二、association映射复用
上述示例中使用resultMap联合一个association来映射SysUser+SysRole实例,那么association的SysRole结果映射是否可复用?
使用resultMap 扩展出Association的另一个属性:resultMap来联合映射,这样就可以使role结果映射可以重复使用,当然 若不需要重用,可以按照之前的写法,直接嵌套这个联合结果映射。根据具体业务而定
<resultMap id="sysRole" type="SysRole" > <id property="id" column="rid"/> <result property="code" column="code"/> <result property="roleName" column="roleName"/> </resultMap> <resultMap id="userWithSysRole" type="SysUser"> <id property="id" column="id"/> <result property="realName" column="realName"/> <association property="sysRole"javaType="SysRole" resultMap="sysRole" /> </resultMap> 1234567891011
十三、嵌套结果映射之collection
collection 复杂类型集合,映射嵌套结果集到一个列表 一对多 属性 property:实体类中用来映射查询结果子集的集合属性 ofType:集合中元素的类型,完整Java类名或者别名 resultMap:引用外部resultMap
子元素
id
result
<resultMap id="address" type="Address"> <id property="id" column="aid"/> <result property="contact" column="contact"/> <result property="addressDesc" column="addressDesc"/> <result property="postCode" column="postCode"/> <result property="tel" column="tel"/> </resultMap> <resultMap id="userWithAddresses" type="SysUser"> <id property="id" column="id"/> <result property="account" column="account"/> <result property="realName" column="realName"/> <!--resultMap:引用外部resultMap--> <collection property="addressList" ofType="address" resultMap="address"/> </resultMap> 123456789101112131415
十四、resultType与resultMap小结
resultType 直接表示返回类型 适用于比较简单直接的数据封装场景
resultMap 是对外部resultMap的引用 能够处理结果集字段名与实体类属性名不一致、或者需要对连接查询结果使用嵌套映射等较为复杂的问题
二者本质上都是基于Map数据结构,不能同时使用
十五、MyBatis自动映射
自动映射的前提:属性名与字段名一致
自动映射级别:autoMappingBehavior
<settings> <setting name="autoMappingBehavior" value="[NONE|PARTIAL|FULL]" /> </settings> 123
自动映射行为 resultType (不支持嵌套映射 没有嵌套映射的 有嵌套映射的resultMap NONE 失效 手工映射 手工映射 PARTIAL 自动映射 自动映射 手工映射 FULL 自动映射 自动映射 自动映射
十六、增Insert删Delete改Update
Insert: 新增 id: 接口方法名字 parameterType: 参数类型
注意: 1、Insert update delete 这类操作,本身默认就是返回影响的行数,所以不需要对resultType进行指定,只有查询类的操作,需要进行返回结果类型的指定 2、对于增删改这类更新操作,dao层接口方法的返回值为int类型,执行sql影响的行数。最好不要写boolean类型
演示示例:
增删改(insert、update、delete)这类操作通常返回影响行数,insert、update、delete元素均没有resultType/resultMap属性
1、SysUserMapper接口方法定义:
/** * 新增用户 * @param sysUser * @return int 影响的行数 */ int insert(SysUser sysUser); 1234562、SysUserMapper.xml映射文件配置:
<!-- 增加用户 --> <insert id="insert" parameterType="SysUser"> insert into t_sys_user (account, realName, password, sex, birthday,phone, address, roleId, createdUserId, createdTime) values (#{account}, #{realName}, #{password}, #{sex}, #{birthday}, #{phone}, #{address}, #{roleId}, #{createdUserId}, #{createdTime}) </insert> 1234563、SysUserMapperTest 单元测试类:
@Test public void insert() throws ParseException { SysUser user = new SysUser(); user.setAccount("test001"); user.setRealName("测试用户001"); user.setPassword("1234567"); Date birthday = new SimpleDateFormat("yyyy-MM-dd").parse("2003-10-22"); user.setBirthday(birthday); user.setAddress("测试地址abc"); user.setSex(1); user.setPhone("13512345678"); user.setRoleId(1); user.setCreatedUserId(1); user.setCreatedTime(new Date()); SqlSession sqlSession = null; int count = 0; try { sqlSession = MyBatisUtils.getSqlSession(); //新增 count = sqlSession.getMapper(SysUserMapper.class).insert(user); //模拟异常 //int i=5/0; sqlSession.commit();//提交事务 if (count > 0) { System.out.println("新增成功!"); } else { System.out.println("新增失败"); } } catch (Exception e) { System.out.println("错误异常,事务回滚==>"+e.getMessage()); count = -1; sqlSession.rollback();//回滚事务 } finally { MyBatisUtils.closeSqlSession(sqlSession); } } 12345678910111213141516171819202122232425262728293031323334353637
改 Update
id:接口方法名字 parameterType: 参数类型
1、SysUserMapper接口方法定义:
/** * 修改用户 * @param sysUser * @return int 影响的行数 */ int update(SysUser sysUser); 1234562、SysUserMapper.xml映射文件配置:
<!-- 修改用户 --> <update id="update" parameterType="SysUser"> update t_sys_user set account=#{account}, realName=#{realName}, password=#{password}, sex=#{sex}, phone=#{phone}, address=#{address}, birthday=#{birthday}, roleId=#{roleId}, updatedUserId=#{updatedUserId}, updatedTime=#{updatedTime} where id = #{id} </update> 123456783、SysUserMapperTest 单元测试类:
@Test public void update(){ SqlSession sqlSession = null; int count = 0; try { SysUser user = new SysUser(); user.setId(17); user.setAccount("testUpdate"); user.setRealName("测试用户修改"); user.setPassword("88888888"); Date birthday =new SimpleDateFormat("yyyy-MM-dd").parse("1990-10-16"); user.setBirthday(birthday); user.setAddress("地址测试修改"); user.setSex(2); user.setPhone("13612345678"); user.setRoleId(2); user.setUpdatedUserId(1); user.setUpdatedTime(new Date()); sqlSession = MyBatisUtils.getSqlSession(); count = sqlSession.getMapper(SysUserMapper.class).update(user); //模拟异常,进行回滚 //int i =5/0; sqlSession.commit();//提交事务 if (count > 0) { System.out.println("修改成功!"); } else { System.out.println("修改失败"); } } catch (Exception e) { System.err.println("错误异常,事务回滚==>"+e.getMessage()); count = -1; sqlSession.rollback();//回滚事务 }finally{ MyBatisUtils.closeSqlSession(sqlSession); } } 123456789101112131415161718192021222324252627282930313233343536
删 Delete
id: 接口方法名字 parameterType: 参数类型
1、SysUserMapper接口方法定义:
/** * 删除用户 * @param id 要删除的用户用户ID */ public int deleteUserById(@Param("id") Integer id); 123452、SysUserMapper.xml映射文件配置:
<!-- 根据用户Id删除用户信息 --> <delete id="deleteUserById" parameterType="integer"> delete from t_sys_user where id=#{id} </delete> 12343、SysUserMapperTest 单元测试类:
@Test public void deleteUserById() { SqlSession sqlSession = null; Integer delId = 17; int count = 0; try { sqlSession = MyBatisUtils.getSqlSession(); count = sqlSession.getMapper(SysUserMapper.class).deleteUserById(delId); sqlSession.commit();//提交事务 } catch (Exception e) { System.out.println("错误异常,事务回滚==>"+e.getMessage()); count = 0; sqlSession.rollback();//回滚事务 }finally{ MyBatisUtils.closeSqlSession(sqlSession); } } 1234567891011121314151617
十七、缓存
MyBatis缓存 一级缓存:SqlSession 二级缓存 二级缓存的配置
1、MyBatis的全局cache配置 2、在SQL映射文件中设置缓存,默认情况下是没有开启缓存的 3、在SQL映射文件配置支持cache后,如果需要对个别查询进行调整,可以单独设置 1231、MyBatis的全局cache配置
<settings> <setting name="cacheEnabled" value="true" /> </settings> 1232、在SQL映射文件中设置缓存
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" /> 13、在SQL映射文件配置支持cache后,如果需要对个别查询进行调整
<select id="selectAll" resultType="SysUser" useCache="true"> select * from t_sys_user; </select> 123
十八、本章总结
Mybatis框架的SQL映射文件提供select丶insert丶update丶delete等元素来实现SQL语句的映射。
SQL映射文件的根节点是mapper元素,其namespace属性的值需要保证全局唯一,用于区分不同的mapper。
基于面向接口编程的理念,mapper元素的namespace属性值应指定为Mapper接口的完全限定类名。
SQL映射文件select元素可以使用resultMap或resultType指定返回结果的类型,但是二者不能同时使用。
为Mapper接口方法传入多个简单类型的参数时,建议使用@Param注解为参数命名。
在元素中可以使用association元素和collection元素实现嵌套结果映射。