- 所谓的一对多就是一个对象对待多个对象,就如同我们的一个老师要教多个学生一样;
- 而所谓的多对一就是多个对象对待一个对象,就如同多个学生要和一个老师学习一样;
一对多应用需要用 collection 处理
1.创建编译环境
public class Teacher {
private int id;
private String name;
//一个老师对应对个学生
private List<Student> students;
}
2.编写接口
package com.zhang.dao;
import com.zhang.pojo.Teacher;
public interface TeacherDao {
//获得一个老师下的所有学生信息; 老师是包含学生的集合;
Teacher getTeacher(int id);
Teacher getTeacherTwo(int id);
}
3.编写对应的mapper配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhang.dao.TeacherDao">
<!--一对多的处理-->
<!--面向对象方式解决-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.name sname,s.id sid,t.id tid, t.name tname
from mybatis.student as s,mybatis.teacher as 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">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
</collection>
</resultMap>
<!--数据库思想-->
<select id="getTeacherTwo" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{id}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" column="id" select="T2"/>
</resultMap>
<select id="T2" resultType="Student">
select * from mybatis.student where tid = #{id}
</select>
</mapper>
4.编写测试类
package com.zhang.dao;
import com.zhang.pojo.Teacher;
import com.zhang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class TeacherDaoTest {
@Test
public void getTeacher(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher.getName());
System.out.println(teacher.getStudents());
}
@Test
public void getTeacherTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
TeacherDao mapper = sqlSession.getMapper(TeacherDao.class);
Teacher teacher = mapper.getTeacherTwo(1);
System.out.println(teacher.getName());
System.out.println(teacher.getStudents());
}
}
多对一处理需要使用 assocation 标签关联数据库处理
在mybatis中处理多对一的时候,使用的是关联映射的思想处理;一般使用数据库思想(联表查询),oop思想(关联对象)
处理方式一:
1.编写接口代码
List<Student> getStudents();
2.编写与数据库关联的查询
<!--遇到问题:学生类中关联老师: 多个学生对应一个老师 -->
<!--<select id="getStudents" resultType="Student">-->
<!--select s.id,s.name,t.name from mybatis.student as s,mybatis.teacher as t-->
<!--where s.tid = t.id-->
<!--</select>-->
<!--按查询结果嵌套处理,模拟数据库思想;
-->
<select id="getStudents" resultMap="StudentTeacher">
select * from mybatis.student
</select>
<resultMap id="StudentTeacher" type="Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!--属性和字段对应 , 类和表对应 , 对象和记录
关联一个字段
需求:拿到老师这个类的属性
association : 关联,多对一
column : 数据库对应的列名
property : 对应属性名
javaType : 多对一字段对应的Java类型
select : 关联一个语句
-->
<association column="tid" property="teacher" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from mybatis.teacher where id = #{id}
</select>
3.编写测试类
public void UserTest(){
@Test
public void getStudents(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.getStudents();
for (Student student : students) {
System.out.println("学生姓名:"+student.getName()+"\t老师姓名:"+student.getTeacher().getName());
}
}
}
处理方式二:
1.编写接口
List<Student> getStudentsTwo();
2.编写对应的配置文件
<!-- 一个resultMap解决 , 模拟面向对象的思想-->
<select id="getStudentsTwo" resultMap="StudentTeacher2">
select s.id,s.name,t.name as tname from mybatis.student as s, mybatis.teacher as t
where s.tid = t.id
</select>
<!--设置结果集映射ResultMap -->
<resultMap id="StudentTeacher2" type="Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<!--直接关联一个老师-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
3.编写测试类
public void UserTest(){
@Test
public void getStudentsTwo(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
List<Student> students = mapper.getStudentsTwo();
for (Student student : students) {
System.out.println("学生姓名:"+student.getName()+"\t老师姓名:"+student.getTeacher().getName());
}
}
}
动态SQL&缓存
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。
动态SQL就是指根据不同查询条件,生成不同的SQL语句
在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
if
参数test:里面的表达式如果为ture则执行,否则不执行
if(title != null)
<if test="title != null">
AND title like #{title}
</if>
choose
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
switch (exp){
case 1:
break;
case 2:
break;
}
</select>
trim[where,set]
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
foreach
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
编译代码测试
1.编写接口
//模糊查询,可以通过自定义条件查询
List<User> getUserByLike(Map<String,Object> map);
2.编写配置文件的映射文件
<select id="getUser" resultType="User">
select * from mybatis.user
</select>
<select id="getUserByLike" resultType="User" parameterType="Map">
select * from mybatis.user
<where>
<if test="name!=null">
name like CONCAT('%',#{name},'%')
</if>
<if test="id!=null">
and id = #{id}
</if>
</where>
</select>
3.编写测试类
@Test
public void getUserByLike(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String,Object> map = new HashMap<String,Object>();
map.put("name","秦");
map.put("id",1);
List<User> users = mapper.getUserByLike(map);
for (User user : users) {
System.out.println(user);
}
}
如果是太过复杂的逻辑不建议使用动态的SQL,
缓存
在开启缓存前需要在映射文件中 ,添加一个标签
<!--开启缓存-->
<cache/>
如果CRUD操作要结果需要缓存。可以使用useCache;
<!--
useCache: 是否开启缓存
使用缓存可以解决问题:
查询出来的结果暂时保存着,消耗内存资源;
如果短时间查询同样的语句比较多,可以提高速度;
-->
<select id="getUser" resultType="User" useCache="true">
select * from mybatis.user
</select>