mybatis小结4
多表查询创建两张表,添加相关属性
表与表之间建立关联靠字段
在java中,它是一个面向对象的语言,表明关系时,肯定是对象和对象,不能再是属性。
案例:
class Room{
//要和person产生关联 此处写为:
private List<Person> persons;
}
class Person{
//要和Room产生关系
private Room room;
//不能写成 private Integer roomId;
}
上面room和person的实例
room
package com.kang.model;
import java.util.List;
public class Room {
//房间的编号
private Integer id;
//房间的名称
private String name;
//房间关联的人,由于一个房间可以关联多个人,此处需要是一个集合
private List<Person> persons;
public Room() {
}
public Room(Integer id, String name, List<Person> persons) {
super();
this.id = id;
this.name = name;
this.persons = persons;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Person> getPersons() {
return persons;
}
public void setPersons(List<Person> persons) {
this.persons = persons;
}
@Override
public String toString() {
return "Room [id=" + id + ", name=" + name + ", persons=" + persons + "]";
}
}
person
package com.kang.model;
public class Person {
//人员编号
private Integer id;
//人员姓名
private String name;
//关联的房间,由于一个人只关联一个房间,所以此处给Room对象即可
private Room room;
public Person() {
super();
}
public Person(Integer id, String name, Room room) {
super();
this.id = id;
this.name = name;
this.room = room;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", room=" + room + "]";
}
}
映射文件
<?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.kang.dao.RPDao">
<!--我们查person时,需要关联查询room,此处就要通过resultMap建立结果映射
-->
<resultMap type="person" id="personMap">
<!-- person自己的属性映射 -->
<id column="personId" property="id"/>
<result column="personName" property="name"/>
<!-- 自己关联对象的映射
如果关联的对象是一方,需要使用association标签
property:对应的成员变量名
-->
<association property="room" javaType="com.kang.model.Room">
<!-- 配置room的字段和属性名的对应关系 -->
<id column="roomId" property="id"/>
<result column="roomName" property="name"/>
</association>
</resultMap>
<!-- mybatis中多表联查时,通过resultMap进行结果映射时,
如果不同表中的字段名有一样的,通过别名区分 -->
<select id="queryById" resultMap="personMap">
select
person.id as personId,
person.name as personName,
room.id as roomId,
room.name as roomName
from person
left join room
on person.roomId=room.id
where person.id=#{id}
</select>
<!-- 建立room的结果映射 -->
<resultMap type="room" id="RoomMap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<!-- 关联的对象的映射 由于一个room可以关联多个person
此处需要使用collection标签
property:对应的成员变量名
ofType:指定集合中的元素类型
-->
<collection property="persons" ofType="person">
<id column="personId" property="id"/>
<result column="personName" property="name"/>
</collection>
</resultMap>
<select id="queryRoomById" resultMap="RoomMap">
select
room.*,
person.id as personId,
person.name as personName
from
room
left join
person
on room.id=person.roomId
where
room.id=#{id}
</select>
<!--
useGeneratedKeys:是否需要获取自增主键生成的值,true就是需要
keyProperty:指定将获取到的主键值存到那个属性中
要使用到该功能,方法的参数必须是实体类对象。因为拿到的主键值只能存放到
方法参数的对象的成员变量中!!
例如:当前例子中,方法的参数是room对象,一会就会把主键值存放到room.id中
获取自增主键值的方案只能用于insert和update
-->
<!--
#:会先用?占位,然后将获取到的值,赋值给?位置
$:会直接将值填充到对应位置,但如果是字符串类型,它不会帮我们添加单引号
或双引号,需要手动添加
使用场景:#一般用在具体的字段值上
$:一般用在表名、库名、字段名
-->
<insert id="addRoom" useGeneratedKeys="true" keyProperty="id">
<!-- insert into room (name) values (#{name}) -->
insert into room (name) values (${name})
</insert>
</mapper>
测试
package com.kang.test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.kang.dao.RPDao;
import com.kang.dao.StudentDao;
import com.kang.model.Person;
import com.kang.model.Student;
public class MyTest2{
//由于我们使用的是Session对象,所以SessionFactory值需要一个,
//让sessionFactory对象只创建一个
private static SqlSessionFactory sqlsessionFactory;
private SqlSession sqlSession;
@BeforeAll
public static void createFactory() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
sqlsessionFactory = new SqlSessionFactoryBuilder().build(in);
}
@BeforeEach
public void createSession() {
sqlSession = sqlsessionFactory.openSession();
}
@AfterEach
public void releaseSession() {
sqlSession.commit();
sqlSession.close();
}
@AfterAll
public static void releaseFactory() {
sqlsessionFactory=null;
}
@Test
public void queryById() {
RPDao dao = sqlSession.getMapper(RPDao.class);
Person person = dao.queryById(1);
System.out.println(person);
}
}
mybatis的注解:用来替代映射文件,将映射文件的配置内容,通过注解的方式,直接加到接口的方法上。
官方不推荐使用注解:原因是这种方式,会将sql语句和java语句混在一起,不方便维护。
package com.kang.dao;
import org.apache.ibatis.annotations.Insert;
import com.kang.model.Room;
//mybatis的注解式开发
public interface RoomDao {
/*
* @Insert:修饰方法的注解,作用就等同于
* 映射文件中的insert标签
* value:该属性就是当前方法绑定的sql语句
* 当sql语句比较长,一行写不下时,也可以写成数组的形式
*/
//@Insert(value ="insert into room(name) values (#{name})" )
@Insert(value= {
"insert into room",
"(name) values (#{name})"
})
public int add(Room room);
}