mapper接口开发
传统dao的开发问题(ibatis)
方法调用:字符串易错,硬编码
mapper代理开发
a) 编写全局配置
b) 编写接口(自动根据接口和映射文件创建实现类)
c) 编写映射文件
规范:
A. 映射文件和mapper接口同包同名(批量加载映射文件)
B. 接口的全限定名称必须和mapper映射文件的namespace保持一致
C. 接口中方法名称和mapper中的标签id保持一致
D. 方法的参数类型和mapper的paramerType保持一致
E. 方法的返回值类型和mapper的resultType和resultMap保持一致
<mapper namespace="mapper.BookMapper"> <select id="queryAll" resultType="book"> select * from book </select> </mapper>
d) 测试
SqlSession session = MybatisUtils.getSession(); //根据mapper接口生成实现类对象 BookMapper mapper = session.getMapper(BookMapper.class); System.out.println(mapper.queryAll()); MybatisUtils.closeSession(); //junit:单元测试 //1.加入junit的jar //2.使用junit实现测试(@test:作为单元直接运行 @before/@after:在test之前运行 )
输入参数和输出结果
输出结果
a) resultType:
如果结果集中所有的字段和对象中属性名称一一对应则映射成功;
如果结果集中字段的名称和属性名称部分一致,则一致的部分映射成功。
如果结果集中字段的名称和属性名称都不一致,则不会创建对象。
b) 字段和属性不一致实现封装
A. 起别名
B. resultMap(实现字段和属性之间的映射)
<!-- 实现结果集和对象的映射 id:唯一标识 type:封装的对象类型 --> <resultMap type="book" id="bookMap"> <!-- id:描述主键字段和属性之间的映射关系 column:字段 property:属性 --> <id column="bi" property="bid"/> <!-- result:非主键字段的映射 --> <result column="bnam" property="bname"/> <result column="autho" property="author"/> <result column="pric" property="price"/> </resultMap> <select id="queryAll" resultMap="bookMap"> select * from book </select>
动态sql
if: <select id="queryCombo" parameterType="book" resultType="book"> select * from book where 1 = 1 <if test="bid != 0"> and bid = #{bid} </if> <if test="bname != null"> and bname = #{bname} </if> </select> choose: <choose> <when test="bid != 0"> and bid = #{bid} </when> <otherwise> and bname = #{bname} </otherwise> </choose> where <where> <if test="bid != 0"> and bid = #{bid} </if> <if test="bname != null"> and bname = #{bname} </if> </where> foreach: select * from book where bid in <!-- collection:遍历的集合 item:每一项值 open:开始 close:结束 separator:分隔符 --> <foreach collection="list" item="bid" open="(" close=")" separator=","> #{bid} </foreach>
高级结果映射
1) 查询的结果集分布于多张表
2) 一对多:Role和User(查询role级联查询所有的员工信息)
<resultMap type="role" id="RoleMap"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> <!-- collection:将结果集数据封装到集合中 property:属性 ofType:单个对象的类型 column:关联的键 --> <collection property="users" ofType="user" column="rid"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <result column="rid" property="rid"/> </collection> </resultMap> <select id="queryRoleAndUser" resultMap="RoleMap"> select * from role r left join `user` u on r.rid = u.rid </select> Rolemapper.xml <resultMap type="role" id="RoleMap2"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> <!-- collection:将结果集数据封装到集合中 property:属性 ofType:单个对象的类型 column:关联的键 --> <collection property="users" ofType="user" column="rid" select="mapper.UserMapper.selectUser"> </collection> </resultMap> <select id="queryRoleAndUser2" resultMap="RoleMap2"> select * from role </select> UserMapper.xml <select id="selectUser" resultType="user"> select * from user where rid = #{rid} </select>
3) 一对一:查询user及其角色(user)
<resultMap type="user" id="userMap"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <!-- 将结果集数据封装到对象中 property:对象的属性名称 column:外键 javaType:对象的类型 --> <association property="role" column="rid" javaType="role"> <id column="rid" property="rid"/> <result column="rname" property="rname"/> </association> </resultMap> <select id="queryUserAndRole" resultMap="userMap"> select * from user u left join role r on u.rid = r.rid; </select> UserMapper: <resultMap type="user" id="userMap2"> <id column="uid" property="uid"/> <result column="uname" property="uname"/> <!-- 将结果集数据封装到对象中 property:对象的属性名称 column:外键 javaType:对象的类型 --> <association property="role" column="rid" javaType="role" select="mapper.RoleMapper.selectRole"> </association> </resultMap> <select id="queryUserAndRole2" resultMap="userMap2"> select * from user </select> RoleMapper <select id="selectRole" resultType="role"> select * from role where rid = #{rid} </select>
延迟加载
1) 延迟加载:按需加载(懒加载),只加载主查询,需要用到子查询信息时才去查询。
2) <collection><association>都具有延迟加载功能。但是默认关闭。
3) 需要打开延迟加载:
<settings> <!-- 延迟加载全局开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 3.4.1以上为false,否则为true --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
缓存
一级缓存
Mybatis中的一级缓存时默认开启的。
在内存中一块区域,以类似于map方式进行数据管理。
当用户第一次查询时,会根据sql,参数,rowbounds以及statement的id生成cacheKey,先从二级缓存中获取数据,如果为空,将从一级缓存中根据生成key获取value值,如果也为空,就从数据库进行查询,然后将key和查询的结果放置到一级缓存中。
当用户再次查询时,仍旧生成cacheKey,通过key从一级缓存中获取值,如果有值此时将直接返回不再查询数据库。
一级缓存是session级别的缓存。
如果执行增删改会清空一级缓存。
二级缓存
在内存中一块区域,以类似于map方式进行数据管理。
当用户第一次查询时,会根据sql,参数,rowbounds以及statement的id生成cacheKey,先从二级缓存中获取数据,如果为空,将从一级缓存中根据生成key获取value值,如果也为空,就从数据库进行查询,然后将key和查询的结果放置到一级缓存中。
当用户再次查询时,仍旧生成cacheKey,通过key从一级缓存中获取值,如果有值此时将直接返回不再查询数据库。
如果执行增删改会清空二级缓存
二级缓存是跨session的缓存。
默认二级缓存关闭。
实体类必须序列化。
<cache>
//读取配置文件转换为流 InputStream is = Resources.getResourceAsStream("Mybatis.xml"); //创建ssf对象 SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is); SqlSession session = ssf.openSession(true); SqlSession session2 = ssf.openSession(true); SqlSession session3 = ssf.openSession(true); //根据mapper接口生成实现类对象 BookMapper mapper = session.getMapper(BookMapper.class); BookMapper mapper2 = session2.getMapper(BookMapper.class); BookMapper mapper3 = session3.getMapper(BookMapper.class); System.out.println(mapper.queryAll()); session.close(); System.out.println(mapper2.queryAll()); session2.close(); System.out.println(mapper3.queryAll()); session3.close();