博客目录
1.Mybatis工作流程
2.封装方法
3.采用映射方法实现接口查询
4.接口配置文件 讲述增删改查(源代码)
(1)模糊查询的方法
(2)Mapper生命周期
5.pojo实体类中的字段和数据库中的字段不一样
(1)换一个别名
(2)、使用返回类型 resultMap
6.Mybatis分页查询
(1).通过UserMapper.xml配置来实现,UserMapper.xml配置:
(2).通过Java代码实现分页 (不建议使用,但是快)
(3)分页可以使用其他方法
7.按照查询嵌套处理(多对一复杂查询)
(1).通过子查询来完成
(2).按照结果嵌套查询--联表查询
8.类似于联表查询 一对多
联表查询 小结
10.二级缓存
注意:采用了二级缓存会出现序列化的问题
缓存工作流程图
结论
1.Mybatis工作流程
2.封装方法
SqlSessionFactoryUtils 里面的openSession
1 public class SqlSessionFactoryUtil { 2 //创建SqlSessionFactory对象 3 private static SqlSessionFactory sqlSessionFactory =null; 4 //类线程死锁 5 private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class; 6 7 /** 8 * 私有化构造参数 9 */ 10 private SqlSessionFactoryUtil(){ 11 } 12 13 /** 14 * @return 15 * 单例模式,构造函数要私有化,并且需要用线程锁住,保证所有对象都使用一个SqlSessionFactory 16 */ 17 public static SqlSessionFactory initSqlSessionFactory() { 18 String resource ="mybatis-config.xml"; 19 InputStream inputStream = null; 20 try{ 21 inputStream = Resources.getResourceAsStream(resource); 22 }catch(IOException ex) { 23 Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, 24 null,ex); 25 } 26 synchronized(CLASS_LOCK) { 27 if(sqlSessionFactory==null) { 28 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 29 } 30 } 31 return sqlSessionFactory; 32 } 33 34 public static SqlSession openSqlSession() { 35 if(sqlSessionFactory==null) { 36 initSqlSessionFactory(); 37 } 38 return sqlSessionFactory.openSession(); 39 } 40 }
3.采用映射方法实现接口查询
UserMapper userMapper =session.getMapper(UserMapper.class); List<User> userList =userMapper.getList();
4.接口配置文件 讲述增删改查(源代码)
(1)模糊查询的方法
<!-- 模糊查询 需要:同时满足 3 个参数,不然失败,所以需要动态SQL方法--> <select id="selectByMap" parameterType="map" resultType="User"> select * from user where sex=#{sex} and address like concat("%",#{address},"%") and username like concat("%",#{username},"%d") </select> <!-- 改进版的模糊查询--> <select id="selectByMap1" parameterType="map" resultType="user"> select * from user <where> <if test="sex !=null and sex !=''">sex=#{sex}</if> <if test="address !=null and address !=''">address=#{address}</if> <if test="username !=null and username !=''">username=#{username}</if> </where> </select>
(2)Mapper生命周期
5.pojo实体类中的字段和数据库中的字段不一样
(1)换一个别名
(2)、使用返回类型 resultMap
结果集映射
只需要映射需要修改的
6.Mybatis分页查询
(1).通过UserMapper.xml配置来实现
UserMapper.xml配置:
<resultMap id="LimitType" type="User"> <result column="address" property="addes"/> </resultMap> <select id="getUserByLimit" parameterType="map" resultMap="LimitType"> select * from user limit #{startIndex},#{pageSize} </select>
测试类:
@Test public void getUserByLimit(){ SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Map map = new HashMap<String , Integer>(); map.put("startIndex", 0); map.put("pageSize",2); List <User> list=userMapper.getUserByLimit(map); for (User s :list) { System.out.println(s); } sqlSession.close(); }
(2).通过Java代码实现分页 (不建议使用,但是快)
RowBounds rowBoun RowBounds rowBounds= new RowBounds(0,5); List<User> list = sqlSession.selectList("com.ybzn.dao.UserMapper.getUserByLimit", null,rowBounds);
两行代码即可查询出分页,在UserMapper.xml配置中:仅需如下
<resultMap id="LimitType" type="User"> <result column="address" property="addes"/> </resultMap> <select id="getUserByLimit" parameterType="map" resultMap="LimitType"> select * from user </select>
(3)分页可以使用其他方法
7.按照查询嵌套处理(多对一复杂查询)
(1).通过子查询来完成
StudentMapper.xml配置
思路:
1.查询所有学生信息
2.根据查询出来的学生tid,寻找对应的老师! 类似于子查询
<select id="getStudent" resultMap="StudentTeacher"> select * from new_user; </select> <resultMap id="StudentTeacher" type="Student"> <result column="id" property="id"></result> <result column="stuname" property="stuname"></result> <result column="id" property="id"></result> <!-- 复杂的属性 需要单独处理 对象:association 集合:collection --> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from teacher where tid=#{tid} </select>
(2).按照结果嵌套查询--联表查询
类似于联表查询 多对一
StudentMapper.xml
<select id="getStudent2" resultMap="StudentTeacher2"> select s.id sid,s.stuname sname,s.stuclass sclass,t.teaname tname from new_user s,teacher t where s.tid=t.tid; </select> <resultMap id="StudentTeacher2" type="Student"> <result column="sid" property="id"></result> <result column="sname" property="stuname"></result> <result column="sclass" property="stuclass"></result> <association property="teacher" javaType="Teacher"> <result property="teaname" column="tname"></result> </association> //其中association 里面的property对应Pojo中的字段名 //javaType 对应pojo中的字段名类型 //配置中所有property 表示数据库中的字段名,Column表示程序中的别名或者字段名 </resultMap>
POJO下的:Student.java
@Data public class Student { private int id; private String stuname; private String stuclass; private Teacher teacher; }
8.类似于联表查询 一对多
1 <!--按照结果来嵌套查询--> 2 <select id="getTeacher" resultMap="TeacherStudent"> 3 select s.id sid, s.stuname sname, s.stuclass sclass, t.teaname tname , t.tid tid 4 from new_user s , teacher t 5 where s.tid = t.tid and t.tid = #{tid}; 6 </select> 7 <resultMap id="TeacherStudent" type="Teacher"> 8 <result column="tname" property="teaname"></result> 9 <!-- 复杂的属性 需要单独处理 对象:association 集合:collection 10 javaType="" 指定属性的类型 11 集合中的泛型信息 ,我们可以通过ofType获取 12 --> 13 <collection property="student" ofType="Student"> 14 <result property="id" column="sid"></result> 15 <result property="stuname" column="sname"></result> 16 <result property="tid" column="tid"></result> 17 <result property="stuclass" column="sclass"></result> 18 </collection> 19 </resultMap>
POJO下的:Teacher.java
@Data public class Teacher{ private int tid; private String teaname; private List<Student> student; }
联表查询 小结
1. 关联:- association 【多对一】
2. 集合: -collection 【一对多】
3. javaType && ofType
- javaType 用来指定实体类中属性的类
- ofType 用来指定映射到LIst《ofType=""》或者集合中的pojo类型,泛型中的约束类型
9.动态SQL查询
- 利用IF 来完成查询
BlogMapper.xml 配置 通过传递map 的方式来完成查询
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where> </select>
- 利用Choose来完成查询
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from blog <where> <choose> <when test="title !=null"> title=#{title} </when> <when test="author != null"> and author=#{author} </when> <otherwise> and views=#{views} </otherwise> </choose> </where> </select>
- 利用Set来完成更新操作
<update id="updateBlog" parameterType="map"> update blog <set> <if test="title !=null"> title = #{title}, </if> <if test="author !=null "> author = #{author}, </if> </set> where id= #{id} </update>
- SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。
提取SQL片段:
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>
引用SQL片段:
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from blog <where> <!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace --> <include refid="if-title-author"></include> <!-- 在这里还可以引用其他的 sql 片段 --> </where> </select>
注意:
①、最好基于 单表来定义 sql 片段,提高片段的可重用性
②、在 sql 片段中不要包括 where
- 利用Foreach 完成动态SQL的拼接
BlogMapper.xml 配置
<!-- 传递一个万能的map, 这个Map可以存在一个集合--> <select id="queryBlogForeach" parameterType="map" resultType="Blog"> select * from blog <where> <foreach collection="ids" item="flagid" open="and (" close=")" separator="or"> id=#{flagid} </foreach> </where> </select>
测试 如下
@Test public void sqlSelect(){ SqlSession session = SqlSessionFactoryUtil.openSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); HashMap map = new HashMap(); ArrayList <String> ids = new ArrayList <>(); ids.add("1"); ids.add("2"); ids.add("3"); ids.add("4"); map.put("ids", ids); List <Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } }
10.二级缓存
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
使用步骤
- 开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
2.去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
<cache/> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,
注意:采用了二级缓存会出现序列化的问题
应该令POJO中的实体类 实现Serializable 接口
public class Blog implements Serializable {}
缓存工作流程图
结论
- 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
- 查出的数据都会被默认先放在一级缓存中
- 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中