目录
1.resultMap元素自定义结果集
? ? ? ? 1.1 要解决的问题:属性名和字段名不一致
????????????????1.1.1?数据库中的字段
? ? ? ? ? ? ? ? 1.1.2??Java中的实体类设计
? ? ? ? ? ? ? ? ?1.1.3?接口
? ? ? ? ? ? ? ? ?1.1.4?mapper映射文件
? ? ? ? ? ? ? ? 1.1.5?总结
2.一对多与多对一处理
? ? ? ? 2.1?数据库设计
? ? ? ? 2.2?多对一的处理
? ? ? ? ? ? ? ? 2.2.1?实体类编写
? ? ? ? ? ? ? ? 2.2.2??方式一:按查询嵌套处理
????????????????2.2.3? 方式二:按结果嵌套处理
????????????????2.2.4? 小结
? ? ? ? 2.3 一对多的处理
? ? ? ? ? ? ? ? 2.3.1?实体类编写
? ? ? ? ? ? ? ? 2.3.2?方式一:按结果嵌套处理?
?????????????????2.3.3?方式二:按查询嵌套处理?
? ? ? ? ? ? ? ? 2.3.4?小结
????????3.Mybatis注解增删改查
? ? ? ? 3.1?查询
? ? ? ? 3.2?增加
? ? ? ? 3.3?修改
? ? ? ? 3.4?删除
????????3.5?小结
? ? ? ? 3.6?关于@Param注解
????????3.7 #{}与${}的区别
4.Mybatis详细的执行流程
?5.Mybatis框架的缓存
? ? ? ? 5.1?缓存简介
? ? ? ? 5.2?Mybatis缓存?
? ? ? ? 5.3?一级缓存
? ? ? ? 5.4?一级缓存失效的四种情况
? ? ? ? 5.4 二级缓存
? ? ? ? 5.5?使用步骤
? ? ? ? ?5.6?结论
6.缓存原理?
?7.本章总结
1.resultMap元素自定义结果集
? ? ? ? 1.1 要解决的问题:属性名和字段名不一致
????????????????1.1.1?数据库中的字段
? ? ? ? ? ? ? ? 1.1.2??Java中的实体类设计
package entity;
public class Banana {
private int bd;
private String bn;
private String bc;
private Place p;
private Btype bt;
public Banana(int bd, String bn, String bc, Place p, Btype bt) {
this.bd = bd;
this.bn = bn;
this.bc = bc;
this.p = p;
this.bt = bt;
}
//get,set,构造
}
? ? ? ? ? ? ? ? ?1.1.3?接口
package dao;
import entity.Banana;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BananaMapper {
/*查询所有香蕉*/
List<Banana>getall();
/*双表查询*/
List<Banana>getdoubleall();
/*查询海南产地下的所有香蕉*/
List<Banana>getPlace(String pname);
/*动态Mybatissql使用案例 if where*/
/*按编号查,按名字查,按颜色查*/
List<Banana>getfh(@Param("bid") String bid, @Param("bname") String bname, @Param("bcolor") String bcolor);
/*动态Mybatissql使用案例 foreach*/
/*按多颜色in查询*/
List<Banana>getBycolor(@Param("colors")String[] colors);
/*动态Mybatissql使用案例 set if*/
/*多参数修改*/
int update(Banana b);
}
? ? ? ? ? ? ? ? ?1.1.4?mapper映射文件
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的Dao/mapper接口-->
<mapper namespace="dao.BananaMapper">
<resultMap id="BananaMapall" type="entity.Banana">
<id column="bid" property="bd"/>
<result column="bname" property="bn"></result>
<result column="bcolor" property="bc"></result>
</resultMap>
<select id="getall" resultMap="BananaMapall">
select * from banana
</select>
<resultMap id="BananaMapfh" type="entity.Banana">
<id column="bid" property="bd"/>
<result column="bname" property="bn"></result>
<result column="bcolor" property="bc"></result>
</resultMap>
<select id="getfh" resultMap="BananaMapfh">
select * from banana
<where>
<if test="bid!=null and bid!=''">
bid=#{bid}
</if>
<if test="bname!=null and bname!=''">
and bname=#{bname}
</if>
<if test="bcolor!=null and bcolor!=''">
and bcolor=#{bcolor}
</if>
</where>
</select>
<select id="getBycolor" resultMap="BananaMapfh">
select * from banana
where bcolor
in
<foreach collection="colors" item="p" open="(" separator="," close=")" >
#{p}
</foreach>
</select>
<update id="update">
update banana
<set>
<if test="bn!=null and bn!=''">
bname=#{bn}
</if>
<if test="bc!=null and bc!=''">
, bcolor=#{bc}
</if>
</set>
where bid=#{bd}
</update>
<!--如果需要使用结果集映射需要先定义对应的结果集-->
<!--mybatis默认的按照同名进行表字段映射 双表查询必须要用resultMap-->
<!--定义的结果集映射-->
<resultMap id="BananaMap" type="entity.Banana">
<!--column数据库中的字段,property实体类中的属性-->
<!--主键列用id标识-->
<!--property:实体类字段名 column:表字段名-->
<!--association 用于实体类中的对象的映射-->
<id column="bid" property="bd"/>
<result column="bname" property="bn"></result>
<result column="bcolor" property="bc"></result>
<association property="p" javaType="entity.Place">
<id column="pid" property="pid"/>
<result column="pname" property="pname"></result>
</association>
<association property="bt" javaType="entity.Btype">
<id column="tid" property="tid"/>
<result column="tname" property="tname"></result>
</association>
</resultMap>
<select id="getdoubleall" resultMap="BananaMap">
select * from banana b
inner join place p on (b.pid=p.pid)
inner join btype bt on (b.tid=bt.tid)
</select>
<select id="getPlace" resultMap="BananaMap">
select * from banana b
inner join place p on (b.pid=p.pid)
inner join btype bt on (b.tid=bt.tid)
where p.pname=#{pname}
</select>
</mapper>
? ? ? ? ? ? ? ? 1.1.5?总结
当实体类中的字段名称与数据库中的字段名不一致,或者实体类中存在对象时需要开启resultMap,手动映射字段,不然找不到对应的字段数据为空!
偷懒小技巧:可在mybatis-config.xml核心配置文件settings标签中设置?<setting name="autoMappingBehavior" value="FULL"/>开启自动映射,当实体类存在对象时需要手动配置resultMap
<settings>
<!--严格区分大小写,空格-->
<!--STDOUT_LOGGING标准的日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--autoMappingBehavior开启resultMap自动装配 普通列自动映射,对象列不自动映射-->
<setting name="autoMappingBehavior" value="FULL"/>
<!--开启二级缓存(Mapper)-->
<setting name="cacheEnabled" value="true"/>
</settings>
2.一对多与多对一处理
? ? ? ? 2.1?数据库设计
? ? ? ? 2.2?多对一的处理
多对一的理解:
- 多个学生对应一个老师
- 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师!
? ? ? ? ? ? ? ? 2.2.1?实体类编写
@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
? ?private int id;
? ?private String name;
}
@Data
public class Student {
? ?private int id;
? ?private String name;
? ?//多个学生可以是同一个老师,即多对一
? ?private Teacher teacher;
}
? ? ? ? ? ? ? ? 2.2.2??方式一:按查询嵌套处理
- 给StudentMapper接口增加方法
//获取所有学生及对应老师的信息
public List<Student> getStudents(); - 编写对应的Mapper文件
<?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">
<mapper namespace="com.kuang.mapper.StudentMapper">
? ?<!--
? ?需求:获取所有学生及对应老师的信息
? ?思路:
? ? ? ?1. 获取所有学生的信息
? ? ? ?2. 根据获取的学生信息的老师ID->获取该老师的信息
? ? ? ?3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般
使用关联查询?
? ? ? ? ? ?1. 做一个结果集映射:StudentTeacher
? ? ? ? ? ?2. StudentTeacher结果集的类型为 Student
? ? ? ? ? ?3. 学生中老师的属性为teacher,对应数据库中为tid。
? ? ? ? ? ? ? 多个 [1,...)学生关联一个老师=> 一对一,一对多
? ? ? ? ? ?4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查
询
? ?-->
? ?<select id="getStudents" resultMap="StudentTeacher">
? ? select * from student
? ?</select>
? ?<resultMap id="StudentTeacher" type="Student">
? ? ? ?<!--association关联属性 property属性名 javaType属性类型 column在多
的一方的表中的列名-->
? ? ? ?<association property="teacher" ?column="tid" javaType="Teacher"
select="getTeacher"/>
? ?</resultMap>
? ?<!--
? ?这里传递过来的id,只有一个属性的时候,下面可以写任何值
? ?association中column多参数配置:
? ? ? ?column="{key=value,key=value}"
? ? ? ?其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的
字段名。
? ?-->
? ?<select id="getTeacher" resultType="teacher">
? ? ? select * from teacher where id = #{id}
? ?</select>
</mapper> - 编写完毕去Mybatis配置文件中,注册Mapper
- 注意点说明
<resultMap id="StudentTeacher" type="Student">
? ?<!--association关联属性 property属性名 javaType属性类型 column在多的一方
的表中的列名-->
? ?<association property="teacher" ?column="{id=tid,name=tid}"
javaType="Teacher" select="getTeacher"/>
</resultMap>
<!--
这里传递过来的id,只有一个属性的时候,下面可以写任何值
association中column多参数配置:
? ?column="{key=value,key=value}"
? ?其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段
名。
-->
<select id="getTeacher" resultType="teacher">
? select * from teacher where id = #{id} and name = #{name}
</select>
????????????????2.2.3? 方式二:按结果嵌套处理
- 接口方法编写
public List<Student> getStudents2();
- 编写对应的mapper文件
<!--
按查询结果嵌套处理
思路:
? ?1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
? select s.id sid, s.name sname , t.name tname
? from student s,teacher t
? where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
? ?<id property="id" column="sid"/>
? ?<result property="name" column="sname"/>
? ?<!--关联对象property 关联对象在Student实体类中的属性-->
? ?<association property="teacher" javaType="Teacher">
? ? ? ?<result property="name" column="tname"/>
? ?</association>
</resultMap> - 去mybatis-config文件中注入【此处应该处理过了】
- 测试
@Test
public void testGetStudents2(){
? ?SqlSession session = MybatisUtils.getSession();
? ?StudentMapper mapper = session.getMapper(StudentMapper.class);
? ?List<Student> students = mapper.getStudents2();
? ?for (Student student : students){
? ? ? ?System.out.println(
? ? ? ? ? ? ? ?"学生名:"+ student.getName()
? ? ? ? ? ? ? ? ? ? ? ?+"\t老师:"+student.getTeacher().getName());
? }
}
????????????????2.2.4? 小结
- 按照查询进行嵌套处理就像SQL中的子查询
- 按照结果进行嵌套处理就像SQL中的联表查询
? ? ? ? 2.3 一对多的处理
一对多的理解:
- 一个老师拥有多个学生
- 如果对于老师这边,就是一个一对多的现象,即从一个老师下面拥有一群学生(集合)!
? ? ? ? ? ? ? ? 2.3.1?实体类编写
@Data
public class Student {
? ?private int id;
? ?private String name;
? ?private int tid;
}
@Data
public class Teacher {
? ?private int id;
? ?private String name;
? ?//一个老师多个学生
? ?private List<Student> students;
}
? ? ? ? ? ? ? ? 2.3.2?方式一:按结果嵌套处理?
- TeacherMapper接口编写方法
//获取指定老师,及老师下的所有学生
public Teacher getTeacher(int id); - 编写接口对应的Mapper配置文件
<mapper namespace="com.kuang.mapper.TeacherMapper">
? ?<!--
? ?思路:
? ? ? ?1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
? ? ? ?2. 对查询出来的操作做结果集映射
? ? ? ? ? ?1. 集合的话,使用collection!
? ? ? ? ? ? ? ?JavaType和ofType都是用来指定对象类型的
? ? ? ? ? ? ? ?JavaType是用来指定pojo中属性的类型
? ? ? ? ? ? ? ?ofType指定的是映射到list集合属性中pojo的类型。
? ?-->
? ?<select id="getTeacher" resultMap="TeacherStudent">
? ? ? select s.id sid, s.name sname , t.name tname, t.id tid
? ? ? from student s,teacher t
? ? ? where s.tid = t.id and t.id=#{id}
? ?</select>
? ?<resultMap id="TeacherStudent" type="Teacher">
? ? ? ?<result ?property="name" column="tname"/>
? ? ? ?<collection property="students" ofType="Student">
? ? ? ? ? ?<result property="id" column="sid" />
? ? ? ? ? ?<result property="name" column="sname" />
? ? ? ? ? ?<result property="tid" column="tid" />
? ? ? ?</collection>
? ?</resultMap>
</mapper> - 将Mapper文件注册到MyBatis-config文件中
<mappers>
? ?<mapper resource="mapper/TeacherMapper.xml"/>
</mappers> - 测试
@Test
public void testGetTeacher(){
? ?SqlSession session = MybatisUtils.getSession();
? ?TeacherMapper mapper = session.getMapper(TeacherMapper.class);
? ?Teacher teacher = mapper.getTeacher(1);
? ?System.out.println(teacher.getName());
? ?System.out.println(teacher.getStudents());
}
?????????????????2.3.3?方式二:按查询嵌套处理?
- TeacherMapper接口编写方法
public Teacher getTeacher2(int id); - 编写接口对应的Mapper配置文件
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
? ?<!--column是一对多的外键 , 写的是一的主键的列名-->
? ?<collection property="students" javaType="ArrayList"
ofType="Student" column="id" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
? select * from student where tid = #{id}
</select> - 将Mapper文件注册到MyBatis-config文件中
- 测试
@Test
public void testGetTeacher2(){
? ?SqlSession session = MybatisUtils.getSession();
? ?TeacherMapper mapper = session.getMapper(TeacherMapper.class);
? ?Teacher teacher = mapper.getTeacher2(1);
? ?System.out.println(teacher.getName());
? ?System.out.println(teacher.getStudents());
}
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? 2.3.4?小结
- 关联-association
- 集合-collection
- 所以association是用于一对一和多对一,而collection是用于一对多的关系
- JavaType和ofType都是用来指定对象类型的
- JavaType是用来指定pojo中属性的类型
- ofType指定的是映射到list集合属性中pojo的类型。
注意说明:
- 保证SQL的可读性,尽量通俗易懂
- 根据实际要求,尽量编写性能更高的SQL语句
- 注意属性名和字段不一致的问题
- 注意一对多和多对一 中:字段和属性对应的问题
- 尽量使用Log4j,通过日志来查看自己的错误
????????3.Mybatis注解增删改查
? ? ? ? 3.1?查询
//根据id查询用户
@Select("select * from user where id = #{id}")
User selectUserById(@Param("id") int id);
? ? ? ? 3.2?增加
//添加一个用户
@Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
? ? ? ? 3.3?修改
//修改一个用户
@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);
? ? ? ? 3.4?删除
//根据id删除用户
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id);
【注意点:增删改一定记得对事务的处理】?
????????3.5?小结
对于简单的sql语句推荐使用注解,更加方便快捷,如果是比较复杂的sql语句推荐使用映射文件。
? ? ? ? 3.6?关于@Param注解
@Param注解用于给方法参数起一个名字。以下是总结的使用原则:
- 在方法只接受一个参数的情况下,可以不使用@Param。
- 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
- 如果参数是 JavaBean , 则不能使用@Param。
- 不使用@Param注解时,参数只能有一个,并且是Javabean。
????????3.7 #{}与${}的区别
- #{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符? 【推荐使用】
INSERT INTO user (name) VALUES (#{name});
INSERT INTO user (name) VALUES (?);
INSERT INTO user (name) VALUES ('${name}');
INSERT INTO user (name) VALUES ('fangge');
4.Mybatis详细的执行流程
?5.Mybatis框架的缓存
? ? ? ? 5.1?缓存简介
- 什么是缓存 [ Cache ]?
- 存在内存中的临时数据。
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
- 为什么使用缓存?
- 减少和数据库的交互次数,减少系统开销,提高系统效率。
- 什么样的数据能使用缓存?
- 经常查询并且不经常改变的数据?
? ? ? ? 5.2?Mybatis缓存?
- MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
- MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
? ? ? ? 5.3?一级缓存
一级缓存也叫本地缓存:
- 与数据库同一次会话期间查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
? ? ? ? 5.4?一级缓存失效的四种情况
- 一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
- 一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求!
- ???????sqlSession不同
- sqlSession相同,查询条件不同
- sqlSession相同,两次查询之间执行了增删改操作!
- sqlSession相同,手动清除一级缓存
? ? ? ? 5.4 二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
- 工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中
? ? ? ? 5.5?使用步骤
官方文档:mybatis – MyBatis 3 | XML 映射器
- 开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
- 去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】
<cache/>
官方示例=====>查看官方文档
<cache
?eviction="FIFO"
?flushInterval="60000"
?size="512"
?readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的
512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者
产生冲突。 - 代码测试
- ??????????????所有的实体类先实现序列化接口
- 测试代码
@Test
public void testQueryUserById(){
? ?SqlSession session = MybatisUtils.getSession();
? ?SqlSession session2 = MybatisUtils.getSession();
? ?UserMapper mapper = session.getMapper(UserMapper.class);
? ?UserMapper mapper2 = session2.getMapper(UserMapper.class);
? ?User user = mapper.queryUserById(1);
? ?System.out.println(user);
? ?session.close();
? ?User user2 = mapper2.queryUserById(1);
? ?System.out.println(user2);
? ?System.out.println(user==user2);
? ?session2.close();
}
?
? ? ? ? ?5.6?结论
- 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
- 查出的数据都会被默认先放在一级缓存中
- 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中?
6.缓存原理?
?7.本章总结
- Mybatis框架的SQL映射文件提供select丶insert丶update丶delete等元素来实现SQL语句的映射。
- SQL映射文件的根节点是mapper元素,其namespace属性的值需要保证全局唯一,用于区分不同的mapper。
- 基于面向接口编程的理念,mapper元素的namespace属性值应指定为Mapper接口的完全限定类名。
- SQL映射文件select元素可以使用resultMap或resultType指定返回结果的类型,但是二者不能同时使用。
- 为Mapper接口方法传入多个简单类型的参数时,建议使用@Param注解为参数命名。
- 在resultMap元素中可以使用association元素和collection元素实现嵌套结果映射。
|