在看完mybatis简单入门之后,了解了mybatis程序的环境搭建和完整流程,紧接着就是功能的应用,本篇文章主要讲解了mybatis的常见应用场景
mybatis入门文章链接:mybatis入门
通常我们会将数据库表的主键id设为自增。在插入一条记录时,我们不设置其主键id,而让数据库自动生成该条记录的主键id,那么在插入一条记录后,如何得到数据库自动生成的这条记录的主键id呢?有两种方式
<mapper namespace="chen.mapper.StudentMapper">
<insert id="addStudent" parameterType="chen.pojo.Student" useGeneratedKeys="true" keyProperty="id">
insert into Student(name,age) values(#{name},#{age})
</insert>
</mapper>
其实< selectKey就是一条sql语句,我们把它放在主sql语句执行之后,将其执行得到的结果封装到java对象的指定属性上,只能用在insert和update中,下面代码中的LAST_INSERT_ID()实际上是MySQL提供的一个函数,用来获得最近插入或更新的主键id
<insert id="addStudent2" parameterType="chen.pojo.Student">
insert into Student(name,age) values(#{name},#{age})
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID();
</selectKey>
</insert>
测试代码
@Test
public void addStudent(){
SqlSession sqlSession = MybatisUtils.getSqlSession(); //已经封装好的mybatis工具类的调用
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = new Student(-1, "huang", 18);
studentMapper.addStudent(student);
sqlSession.commit();
sqlSession.close();
}
主要是动态SQL标签的使用,如果parameterType是List的话,则在标签体内用List;如果parameterType是数组的话,那么只能用变量名array
<select id="findStudent" resultType="chen.pojo.Student" parameterType="java.util.List">
select * from Student
<where>
<if test="list != null and list.size() > 0">
and id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</where>
</select>
@Test
public void findStudent(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.findStudent(Arrays.asList(1,2));
students.forEach(System.out::println);
sqlSession.commit();
sqlSession.close();
}
只有当满足条件的时候,才会执行if标签里的语句,该例子实现模糊查询,模糊查询用&{}
<select id="find" resultType="chen.pojo.Student">
select * from Student where age >= 18
<if test="name!=null and name!=''">
and name like '%${name}%'
</if>
</select>
choose和wen,otherwise 是配套标签,类似于java中的switch,只会选择满足条件的一个
<select id="find2" resultType="chen.pojo.Student" parameterType="int">
select * from Student where age > #{age}
<choose>
<when test="age>=20">
and name = "chen"
</when>
<otherwise>
and name = "lin"
</otherwise>
</choose>
</select>
使用来做迭代连接的,通常会与sql语句中的in做连接查询条件结合使用,其中foreach标签的属性,collection是看你是数组害死List,item指明哪一列,open即开头,close即结尾,separartor是以什么分隔
<select id="findStudent" resultType="chen.pojo.Student" parameterType="java.util.List">
select * from Student
<where>
<if test="list != null and list.size() > 0">
and id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</if>
</where>
</select>
可以将重复的sql片段提取出来,然后在需要的地方,使用< include >标签进行引用
<select id="find3" parameterType="chen.pojo.Student" resultType="chen.pojo.Student">
select * from Student
<include refid="whereName"/>
</select>
<sql id="whereName">
<where>
name like '%${name}%'
</where>
</sql>
- 一级缓存
默认开启,同一个SqlSession级别共享的缓存,在一个SqlSession的生命周期内,执行两次相同的SQL查询,则第二次查询会直接取缓存的数据,而不走数据库。当然,若第一次和第二次相同的SQL查询之间,执行了DML(增删改),则第一缓存会被清空,第二次查询仍然会走数据库
一级缓存在下面清空下会被清空:
(1)在同一个SqlSession中执行增删改操作(不必提交)会清除一级缓存
(2)SqlSession在关闭时,会清除一级缓存
(3)在mapper.xml中某个crud标签,设置属性flushCache=true,这样一级和二级缓存都会失效
(4)在全局配置文件中设置< setting name=“localCacheScope” value=“STATEMENT”>,这样一级魂村会失效,二级缓存不受影响- 二级缓存
默认关闭,可以通过全局配置文件中的< setting name=“cacheEnabled” value=“true”>开启二级缓存总开关,然后在某个mapper.xml中增加< cache />,即开启了二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个sqlSession中可以共享一个二级缓存,开启二级缓存后, 需要提交sqlSession,查询的数据才会被刷新到二级缓存中
使用< resultMap > 标签(一对多)以及 < assocaition> (一对一)和 < collection>子标签(多对多),进行关联查询
文章链接:关联查询详解
延时加载和关联查询是结合进行应用的,也就是说,只在< assocaition> 和 < collection> 标签上起作用:对于延时加载的作用可以这么理解,如果我们不采用延时加载的话,比如用户和订单的信息是一对多的关系,在查询用户信息时设置了关联查询订单,若不采用延时加载策略,我们查这一百个用户的信息只需要一个sql查询;若开启了关联查询且不是延时加载,则对于这一百个用户,我们会发出100条sql语句去查询订单信息,而我们可能只关心id=3的订单信息,所以很多关联信息是没有用的
开启:< setting name=“lazyLoadingEnabled” value=“true”/>
<!-- StudentMapper.xml -->
<resultMap id="studentExt" type="com.yogurt.po.StudentExt">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="score" column="score"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<!-- 当延迟加载总开关开启时,resultMap下的association和collection标签中,若通过select属性指定嵌套查询的SQL,则其fetchType默认是lazy的,当在延迟加载总开关开启时,需要对个别的关联查询禁用延迟加载时,才有必要配置fetchType = eager -->
<!--
column用于指定用于关联查询的列
property用于指定要封装到StudentExt中的哪个属性
javaType用于指定关联查询得到的对象
select用于指定关联查询时,调用的是哪一个DQL
-->
<association property="clazz" javaType="com.yogurt.po.Clazz" column="class_id"
select="com.yogurt.mapper.ClassMapper.findById" fetchType="lazy"/>
</resultMap>
<select id="findLazy" parameterType="string" resultMap="studentExt">
SELECT * FROM student WHERE name like '%${value}%';
</select>
<!-- com.yogurt.mapper.ClassMapper -->
<select id="findById" parameterType="int" resultType="com.yogurt.po.Clazz">
SELECT * FROM class WHERE id = #{id}
</select>
/** 用于封装关联查询的对象 **/
public class StudentExt{
private Integer id;
private String name;
private Integer score;
private Integer age;
private Integer gender;
/** 关联对象 **/
private Clazz clazz;
//getter/setter
}