mybatis
第四章
mybatis的关联查询
mybatis的注解
1、mybatis的关联查询
数据库中的表如果存在关联,通过mybatis可以进行关联查询
mybatis中的关联结构主要有四种:
1、一对多
ag:省份与城市-----一个省份包含多个城市
2、多对一
ag:多个城市隶属于同一个省份
3、一对一
ag:人员与身份证----一个人对应一个身份证
4、多对多
ag:学生与老师----一个老师可以教多个学生
一个学生也可以被多个老师教
通过mybatis的关联查询,可以在查询一个对象时,同时将与它相关联的对象同时查询出来
关联查询的方式
1、进行二次查询(查询两次数据库)
如:一对多及多对一示例
2、只查询一次数据库(通过表连接查询)
这种方式只需要查询一次,即可将当前对象的数据,以及关联属性的数据一起查询出来
【只需要修改citymapper.xml文件】
<!-- 优化版
只查询一次数据库(其实就是把查询两次的语句合并成一句,进行联表查询)
-->
<!-- 封装返回类型-->
<resultMap id="cityMap" type="city">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
<!--关联属性 多对一使用association -->
<!--多对一的关联使用javaType指定关联属性的数据类型-->
<!--property="province" 代表city类中的province属性-->
<!--javaType="province" 代表的是province省份类的别名-->
<association property="province" javaType="province">
<id column="pid" property="pid"/>
<result column="pname" property="pname"/>
</association>
</resultMap>
<!-- 只查询一次就查询出关联的省份-->
<select id="selectByPrimaryKey" parameterType="int" resultMap="cityMap">
select a.cid,a.cname,b.pid,b.pname from city a,province b where a.pid=b.pid and a.cid=#{cid}
</select>
<!-- 查询所有城市关联的身份-->
<select id="selectByPrimary" resultMap="cityMap">
select a.cid,a.cname,b.pid,b.pname from city a,province b where a.pid=b.pid
</select>
【上面是城市的优化,省份同理】
<!-- 只查询一次就查询出省份的所有城市-->
<!--创建resultMap封装返回结果-->
<resultMap id="provinceMap" type="province">
<id column="pid" property="pid"/>
<result column="pname" property="pname"/>
<!--关联属性配置,一对多的关联属性使用Collection进行配置-->
<!--一对多的关联,需要用ofType指定集合中存放的是什么类型的数据-->
<collection property="cities" ofType="city">
<id column="cid" property="cid"/>
<result column="cname" property="cname"/>
</collection>
</resultMap>
<select id="findProvinceByPid" parameterType="int" resultMap="provinceMap">
SELECT p.pid,p.pname,c.cid,c.cname FROM province p,city c WHERE p.pid = c.pid AND p.pid=#{pid}
</select>
【注意:】
延迟加载只要在进行二次查询时才有用,如果只查询一次数据库,延迟加载就没有意义了,可以删除对应的代码
2、一对一的关联查询
例如: 人员与身份证
一个人对应一个身份证
一个身份证对应一个人
【根据人员表的id找身份证号】
1、创建数据表
创建数据表,在外键表引用主键表的数据时,在外键字段上加上唯一约束unique保证它引用的字段只能出现一次
#创建证件表
CREATE TABLE idCard
(
id INT PRIMARY KEY AUTO_INCREMENT,#证件编号
card_no VARCHAR(18) #身份证号码
)
INSERT INTO idCard VALUES(1,'654321654321654321');
INSERT INTO idCard VALUES(2,'123456123456123456');
#创建人员表
CREATE TABLE person
(
pid INT PRIMARY KEY AUTO_INCREMENT,#人员编号
pname VARCHAR(20),#人员名称
card_id INT UNIQUE ,#证件编号,Unique表示值是唯一的
FOREIGN KEY (card_id) REFERENCES idCard(id) #外键,关联到证件表
)
INSERT INTO person VALUES(1,'张三',1);
INSERT INTO person VALUES(2,'李四',2);
SELECT * FROM idcard;
SELECT * FROM person;
2、编写项目结构及实体类
@Data
public class IdCard implements Serializable {
private Integer id;//证件编号
private String cardNo;//证件号码
//配置关联属性,标识当前证件对应的是哪一个人
private Person person;
}
@Data
public class Person implements Serializable {
private Integer pid;//人员编号
private String pname;//人员名称
//关联属性,用于关联到证件
private IdCard idCard;
}
【注意】如果是一对一的配置,在实体类可以配置一个关联属性,类型为对方的类型
另一个实体类即使没有外键,也可以配置关联属性,类型也是对方的类型
3、编写Personmapper.xml文件
<!-- 手动封装返回类型-->
<resultMap id="PersonMap" type="person">
<id column="pid" property="pid"/>
<result column="pname" property="pname"/>
<!--一对一、以及多对一的关联属性都是使用 association声明-->
<!--一对一、以及多对一的关联属性都要使用javaType指定对方的数据类型-->
<association property="idCard" javaType="idCard">
<id column="id" property="id"/>
<result column="card_no" property="cardNo"/>
</association>
</resultMap>
根据id查
<select id="findByid" resultMap="PersonMap">
select a.pid,a.pname,b.card_no from person a,idcard b where a.card_id=b.id and a.pid=#{pid}
</select>
查询所有人员
<select id="findAll" resultMap="PersonMap">
select a.pid,a.pname,b.card_no from person a,idcard b where a.card_id=b.id
</select>
4、编写service
@Test
//根据id查询人员
public void findById(){
SqlSession session= MyBatisUtil.getSqlSession();
PersonMapper mapper=session.getMapper(PersonMapper.class);
Person person=mapper.findByid(2);
System.out.println("人员编号:"+person.getPid());
System.out.println("人员姓名:"+person.getPname());
System.out.println("证件编号:"+person.getIdCard().getCardNo());
session.close();
}
@Test
//查询所有人员
public void findAll(){
SqlSession session= MyBatisUtil.getSqlSession();
PersonMapper mapper=session.getMapper(PersonMapper.class);
List<Person> list=mapper.findAll();
list.forEach(person -> {
System.out.println("人员编号:"+person.getPid());
System.out.println("人员姓名:"+person.getPname());
System.out.println("证件编号:"+person.getIdCard().getCardNo());
System.out.println("----------------------------------------------------");
});
session.close();
}
【根据证件表的id找人员姓名】
idcardMapper.xml
<!-- 手动封装-->
<resultMap id="idCardMap" type="idCard">
<id column="id" property="id"/>
<result column="card_no" property="cardNo"/>
<!--一对一、以及多对一的关联属性都是使用 association声明-->
<!--一对一、以及多对一的关联属性都要使用javaType指定对方的数据类型-->
<association property="person" javaType="person">
<id column="pid" property="pid"/>
<result column="pname" property="pname"/>
</association>
</resultMap>
<select id="findById" resultMap="idCardMap">
select a.id,a.card_no,b.pname from person b,idcard a where a.id=b.card_id and a.id=#{id}
</select>
<select id="findAll" resultMap="idCardMap">
select a.id,a.card_no,b.pname from person b,idcard a where a.id=b.card_id
</select>
service
@Test
//根据id查询人员
public void findById(){
SqlSession session= MyBatisUtil.getSqlSession();
idCardMapper mapper=session.getMapper(idCardMapper.class);
idCard card=mapper.findById(1);
System.out.println("证件编号:"+card.getId());
System.out.println("证件号码:"+card.getCardNo());
System.out.println("证件持有人:"+card.getPerson().getPname());
session.close();
}
@Test
public void findAll(){
SqlSession session= MyBatisUtil.getSqlSession();
idCardMapper mapper=session.getMapper(idCardMapper.class);
List<idCard> list=mapper.findAll();
list.forEach(i -> {
System.out.println("证件编号:"+i.getId());
System.out.println("证件号码:"+i.getCardNo());
System.out.println("证件持有人:"+i.getPerson().getPname());
System.out.println("----------------------------------------------------");
});
session.close();
5、本质
一对一的本质,就是两个多对一
3、多对多的关联查询
多对多:many-to-many
例如: 学生与老师
一个学生可以被多个老师教
一个老师可以教多个学生
多对多的本质就是两个一对多,站在谁的立场,谁就是一,对方就是多
1、创建数据表
CREATE TABLE teacher
(
tid INT PRIMARY KEY AUTO_INCREMENT,#老师编号
tname VARCHAR(20) #老师名称
);
INSERT INTO teacher VALUES(1,'张老师');
INSERT INTO teacher VALUES(2,'李老师');
CREATE TABLE student
(
sid INT PRIMARY KEY AUTO_INCREMENT,#学生编号
sname VARCHAR(20) #学生名称
);
INSERT INTO student VALUES(1,'张三');
INSERT INTO student VALUES(2,'李四');
【注意】:多对多的关系,不需要通过主外键体现,而是要通过一张“关系表”进行描述两张表的关系
#创建老师与学生的关系表
CREATE TABLE teacher_student
(
tid INT,#老师编号
sid INT #学生编号
);
INSERT INTO teacher_student VALUES(1,1);
INSERT INTO teacher_student VALUES(1,2);
INSERT INTO teacher_student VALUES(2,1);
2、创建项目及实体类
只需要编写Teacher,Student对应的实体类,关系表对应的实体类无须编写
@Data
public class Teacher implements Serializable {
private Integer tid;//老师的编号
private String tname;//老师的名称
//关联属性
private List<Student> list = new ArrayList<>();
}
@Data
public class Student implements Serializable {
private Integer sid;//学生编号
private String sname;//学生名称
//关联属性
private List<Teacher> list = new ArrayList<>();
}
//如果是多对多的配置,在两个实体类都会有一个关联属性,类型是一个List集合类型,集合中放的是对方的类型
3、编写mapper文件
【根据老师查学生】
<resultMap id="teacherMap" type="teacher">
<id column="tid" property="tid"/>
<result column="tname" property="tname"/>
<!-- 一对多以及多对一使用collection声明关联属性,并且用ofType指定集合存放的数据类型-->
<collection property="list" ofType="student">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
</collection>
</resultMap>
<!-- 根据老师的编号查询出老师的信息,同时查询该老师教过的学生-->
<select id="findById" resultMap="teacherMap">
select t.tid,t.tname,s.sid,s.sname from teacher t,teacher_student ts,student s where t.tid=ts.tid and ts.sid=s.sid and t.tid=#{id}
</select>
<!-- 查询所有老师的信息-->
<select id="findAll" resultMap="teacherMap">
select t.tid,t.tname,s.sid,s.sname from teacher t,teacher_student ts,student s where t.tid=ts.tid and ts.sid=s.sid
</select>
【问题】:在多对多关联查询时,如果使用的内连接,会导致如果找不到关联的数据,本身的数据也无法查询
内连接的表是平级关系,必须数据表都有的数据才能关联
【解决】:左外连接,老师表是主表
select t.tid,t.tname,s.sid,s.sname from
teacher t left join teacher_student ts on t.tid = ts.tid
left join student s on ts.sid = s.sid
where t.tid=#{id}
4、编写service测试类
@Test
public void findById(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
TeacherMapper mapper=sqlSession.getMapper(TeacherMapper.class);
//查询老师信息
Teacher t = mapper.findById(1);
System.out.println("老师编号:"+t.getTid());
System.out.println("老师姓名:"+t.getTname());
if (t.getList().isEmpty()){
System.out.println("该老师还没有教过学生");
}else{
System.out.print("所教的学生:");
t.getList().forEach(s-> System.out.print(s.getSname()+" "));
System.out.println("");
}
sqlSession.close();
}
@Test
public void findAll(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
TeacherMapper mapper=sqlSession.getMapper(TeacherMapper.class);
//所有老师信息
List<Teacher> list = mapper.findAll();
for (Teacher t:list){
System.out.println("老师编号:"+t.getTid());
System.out.println("老师姓名:"+t.getTname());
if (t.getList().isEmpty()){
System.out.println("该老师还没有教过学生");
}else{
System.out.print("所教的学生:");
t.getList().forEach(s-> System.out.print(s.getSname()+" "));
System.out.println("");
}
System.out.println("----------------------------------------------------------");
}
sqlSession.close();
第五章
mybatis注解
mybatis缓存
1、mybatis注解
使用mybatis注解后,可以不用编写mapper.xml文件,对应的sql语句,使用注解在接口声明即可
注意:使用mapper配置,就不能使用注解配置,二者只能任选一个
使用步骤
1、创建工程
2、导入依赖
3、删除resources下面的mapper.xml文件
如果采用注解就需要删除这个文件,删除以后将maven重新构建一下工程清除之前的文件
Maven-->Lifeecycle-->clean 然后再点击compile构建
4、编写mybatis-config.xml,db.properties,log4j.properties
6、编写Mapper接口,并且在接口上编写对应的sql语句(此时不用写Mapper.xml)
public interface InfMapper {
@Insert("insert into inf values(null,#{name},#{score})")
public void add(Inf inf);
}
7、编写测试类,进行测试(直接在service中测试)
public class InfService {
//添加数据的测试方法
@Test
public void add(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
InfMapper mapper = sqlSession.getMapper(InfMapper.class);
Inf inf = new Inf();
inf.setName("christina");
inf.setScore(100);
mapper.add(inf);
//增删改,需要提交事务
sqlSession.commit();
sqlSession.close();
}
}
【测试】执行的操作
我们要在测试类中测试其他方法,每一个方法都要执行下列操作
@@@在执行数据库操作之前,需要先执行下列操作
1、获得sqlsession
2、需要获得mapper接口
@@@在执行数据库操作之后,需要执行下列操作
1、提交事务
2、关闭sqlsession
【为了使用junit测试代码方便,我们可以使用两个注解】
@Before
public void before(){
此处编写的代码,将会自动在junit测试方法之前自动调用
}
@After
public void after(){
此处编写的代码,将会自动在junit测试方法之后自动调用
}
/*方法名称可以任意指定*/
注意:@Before与@After这两个注解,只能在使用junit进行方法的单元测试时才能使用。在正式运行的代码中无法使用
优化之后的mapper文件
public interface Scoresmapper {
/*
* 使用注解,不创建mapper.xml映射文件,也可以操作sql语句
*
* */
//添加
@Insert("insert into scores values (null,#{sid},#{score})")
void add(Scores score);
//删除
@Delete("delete from scores where id=#{id}")
void del(int id);
//修改
@Update("update scores set score=#{score} where id=#{id} ")
void update(Scores score);
//根据id查询
@Select("select * from scores where sid=#{id}")
Scores findByid(int id);
//查询全部
@Select("select * from scores")
List<Scores> findAll();
}
优化之后的service文件
public class ScoresService {
/*
* 使用junit注解
* */
private SqlSession sqlSession;
private Scoresmapper mapper;
@Test
public void add(){//添加
Scores s=new Scores();
s.setSid(2);
s.setScore(80.0);
mapper.add(s);
}
@Test
public void del(){//删除
mapper.del(4);
}
@Test
public void update(){//修改
Scores s=new Scores();
s.setScore(80.5);
s.setId(1);
mapper.update(s);
}
@Test
public void findByid(){//id查询
System.out.println(mapper.findByid(1));
}
@Test
public void findAll(){//查询所有
mapper.findAll().forEach(s-> System.out.println(s));
}
@Before
public void before(){//测试方法执行之前调用
//获取session
sqlSession= MyBatisUtil.getSqlSession();
mapper=sqlSession.getMapper(Scoresmapper.class);
}
@After
public void after(){//测试方法执行之后调用
//提交事务
sqlSession.commit();
sqlSession.close();
}
}
手动封装返回类型
自动封装(单表操作)
//这种方式是自动封装返回类型,相当于resultType
@Select("select * from scores where sid=#{id}")
Scores findByid(int id);
手动封装(多表操作)
//手动封装返回类型
@Select("select * from scores where sid=#{id}")
@Results(id ="scoreMap",value = {
@Result(id = true,column = "id",property = "id"),
@Result(column = "sid",property = "sid"),
@Result(column = "score",property = "score")
})
Scores findByid2(int id);
id:这个id就是封装名称,后面如果也要手动封装,直接引用id就行
例如:手动封装返回集合类型
//查询全部
@Select("select * from scores")
@ResultMap("scoreMap")//直接引用已经封装过的id名称
List<Scores> findAll();
复杂查询
//成绩成绩范围查询 降序排列
@Select("select * from scores where score between #{bengin} and #{end} order by score desc")
List<Scores> findByScore(@Param("bengin") int bengin,@Param("end") int end);
//聚合查询
@Select("select count(*) from scores")
int getCount();
//模糊查询
// @Select("select * from scores where name like concat('',#{name},'')")
// List<Scores> findByName(String name);
//分页查询
@Select("select * from scores limit #{start},#{rows}")
List<Scores> findPage(@Param("start") int start,@Param("rows") int rows);
动态查询语句
//根据条件动态查询(不确定有几个条件)
@SelectProvider(type= ScoreProvider.class,method = "findByCondition1")
List<Scores> findByContion(Scores scores);
type:是哪一个提供封装号的SQL语句类
method:是哪一个方法
新建一个provider包,在里面新建一个要执行封装语句的provider类
package org.java.provider;
/*
* 该类用于动态组装查询语句
* */
import org.java.entity.Scores;
public class ScoreProvider {
//该方法用于根据条件组装要执行的SQL查询,并且将组装好的SQL语句返回
public String findByCondition1(Scores scores){
StringBuffer sf=new StringBuffer("select * from scores where 1=1");
if (scores.getId()!=null){
sf.append(" and id="+scores.getId());
}
if (scores.getScore()!=null && !scores.getScore().equals("")){
sf.append(" and score like concat('%',"+scores.getScore()+",'%')");
}
return sf.toString();
}
}
/*这里的类名与方法,与mapper里的查询语句想对应*/
多条件分页查询
普通动态查询
要根据参数动态组装查询语句,我们一般使用SelectProvider来执行语句的组装
@SelectProvider(type = InfProvider.class,method = "findByCondition1") public List<Inf> findByCondition(Inf inf);
此代码表示,根据参数Inf对象的信息,调用InfProvider类中的findByCondition1这个方法,组装查询语句
分页查询
【问题】:如果我们的方法有多个参数(例如:不仅要多条件查询,同时还要分页 )
此时会出现错误
【错误原因】:因为导入的到mybatis的版本不匹配
一、通常情况下我们使用实体类或者vo类来传递参数,这样可以在provider中直接使用#{param}来获取参数
二、在mybatis3.3以下版本只能传递一个参数,所以如果要传递多个参数必须封装成Map方式或者通过实体类来调用
public List<Inf> findByCondition(Inf inf);
三、在mybatis3.4以上可以支持多个参数直接传递,
public List<Inf> findByCondition2(Inf inf,@Param("start") int start,@Param("row") int rows);
【解决方案】:如果有多个参数,只需要把mybatis的版本更改3.4以上
3.5.4推荐
成绩表mapper中的代码
//根据条件分页查询
@SelectProvider(type= ScoreProvider.class,method = "findByCondition2")
List<Scores> findByContion2(Scores scores, @Param("start") int start, @Param("rows") int rows);
provider中的代码
//分页查询
public String findByCondition2(Scores scores){
StringBuffer sf=new StringBuffer("select * from scores where 1=1");
if (scores.getId()!=null){
sf.append(" and id="+scores.getId());
}
if (scores.getScore()!=null && !scores.getScore().equals("")){
sf.append(" and score like concat('%',"+scores.getScore()+",'%')");
}
sf.append(" limit #{start},#{rows}");
return sf.toString();
}
service中的代码
@Test
public void findByContion2(){//动态分页查询
Scores scores=new Scores();
scores.setId(1);
int page=1;
int rows=3;
//计算开始下标
int start =(page-1)*rows;
mapper.findByContion2(scores,start,rows).forEach(s-> System.out.println(s));
关联查询
通过注解实现mybatis的关联查询
一对多,多对一,一对一,多对多
最核心是: 一对多,多对一
一对一,多对多都是在它们的基本上演变而来
1、多对一(一对一)
@@@@多对一
查询城市时,同时查询出省份
Province-----省份表 (1)
City---------城市表 (多)
城市mapper代码
@Select("select * from city where cid=#{cid}")
@Results(id = "cityMap",value = {
@Result(id = true,column ="cid",property ="cid"),
@Result(column = "cname",property = "cname"),
//查询关联属性
//多对一,以及一对一都使用one这个标记进行关联查询
@Result(property ="province",column ="pid",one = @One(select = "findProvinceByPid",fetchType = FetchType.EAGER))
})
public City findCityByCid(int cid);
//关联查询---根据省份编号,查询省份对象
@Select("select * from province where pid=#{pid}")
public Province findProvinceByPid(int pid);
【代码解释】
fetchType = FetchType.EAGER
此代码用于指定关联属性的加载方式
FetchType.EAGER-----关联属性立即加载
只要查询对象,就马上加载它的关联属性
FetchType.LAZY------关联属性延迟加载
关联属性什么时候用,什么时候查询,不用就不查询
一般建议:如果是多对一或者是一对一的查询,可以配置成FetchType.EAGER
如果是一对多或者是多对多,可以配置成FetchType.LAZY
2、一对多(多对多)
原理跟多对一 一样
查询城市时,同时查询出省份
Province-----省份表 (1)
City---------城市表 (多)
省份mapper代码
//根据省份编号查询省份信息
@Select("select * from province where pid=#{pid}")
@Results(id = "provinceMap",value = {
@Result(id = true,column = "pid",property = "pid"),
@Result(column = "pname",property = "pname"),
//关联属性
//一对多、多对多使用 many 这个标记
@Result(property = "list",column = "pid",many = @Many(select = "findCity2Id",fetchType = FetchType.LAZY))
})
Province2 findById(int pid);
//关联查询----根据省份编号查询城市信息
@Select("select * from city where pid=#{pid}")
List<City2> findCity2Id(int pid);
service代码
@Test
public void findId(){
SqlSession session= MyBatisUtil.getSqlSession();
Province2Mapper mapper=session.getMapper(Province2Mapper.class);
Province2 p= mapper.findById(3);
System.out.println("省份编号:"+p.getPid());
System.out.println("省份名称:"+p.getPname());
System.out.print("管辖城市:");
p.getList().forEach(k-> System.out.print(k.getCname()+" "));
session.close();
}
第六章
mybatis注解配置一对一 以及多对多
spring
1、mybatis注解
在mybatis中这种关联查询中最为核心的是:一对多,多对一
(一对一以及多对多都是在它们的基础上演变而来)
@@@@@@@@@@基于注解的方式配置一对一
注意:要使用注解的方式配置Mybatis就需要将它的mapper.xml删除,否则会有冲突
一对一的本质,就是两个多对一
@@@@@@@@@基于注解的方式配置多对多
多对多的本质,就是两个一对多
多对一
一对多
1、一对一的注解配置
一对一的本质就是两个多对一
人员--->证件号
人员实体类
private Integer pid;//人员编号
private String pname;//人员名称
//关联属性,用于关联到证件
private idCard2 idCard;
人员mapper的代码
//根据id查询人员信息
@Select("select pid,pname,card_id from person where pid=#{id}")
@Results(id = "personMap",value = {
@Result(id = true, column = "pid",property = "pid"),
@Result(column = "pname",property = "pname"),
//声明关联属性
@Result(property = "idCard",column = "card_id",one =@One(select = "findCardId",fetchType = FetchType.EAGER))
})
Person2 findByid(int id);
@Select("select id,card_no CardNo from idcard where id=#{id}")
idCard2 findCardId(int id);
//查询所有人员的信息
@Select("select * from person")
@ResultMap("personMap")//调用手动封装的返回类型
List<Person2> findAll();
人员的service代码
@Test
//根据id查询人员
public void findById(){
SqlSession session= MyBatisUtil.getSqlSession();
Person2Mapper mapper=session.getMapper(Person2Mapper.class);
Person2 person=mapper.findByid(1);
System.out.println("人员编号:"+person.getPid());
System.out.println("人员姓名:"+person.getPname());
System.out.println("证件编号:"+person.getIdCard().getCardNo());
session.close();
}
@Test
//查询所有人员
public void findAll(){
SqlSession session= MyBatisUtil.getSqlSession();
Person2Mapper mapper=session.getMapper(Person2Mapper.class);
List<Person2> list=mapper.findAll();
list.forEach(person -> {
System.out.println("人员编号:"+person.getPid());
System.out.println("人员姓名:"+person.getPname());
System.out.println("证件编号:"+person.getIdCard().getCardNo());
System.out.println("----------------------------------------------------");
});
session.close();
}
基本是是一模一样,只是获取的mapper不同,执行的方法也就不一样
证件实体类
private Integer id;//证件编号
private String cardNo;//证件编号
//即使没有外键,也可以配置关联属性,对应的是哪一个人
private Person2 person;
证件mapper
证件service
@Test
//根据id查询人员
public void findById(){
SqlSession session= MyBatisUtil.getSqlSession();
idCard2Mapper mapper=session.getMapper(idCard2Mapper.class);
idCard2 card=mapper.findById(1);
System.out.println("证件编号:"+card.getId());
System.out.println("证件号码:"+card.getCardNo());
System.out.println("证件持有人:"+card.getPerson().getPname());
session.close();
}
2、多对多的注解配置
多对多的本质就是两个一对多
之前的写法是左外连接查询,此时就不能使用这种方法
老师-->学生
老师实体类
private Integer tid;
private String tname;
//关联属性
private List<Student2> list=new ArrayList<>();
老师的mapper
/*
* 根据老师的id,通过关系表找出他教过的所有学生(子查询)
* 1、首先查询关系表,找出该老师家教过所有学生的id
* select sid from teacher_student where tid=#{tid}
* 2、根据sid查询学生表,找出所有学生信息
* select *from student where sid in (select sid from teacher_student where tid=#{tid} )
* */
//根据id查询老师信息
@Select("select * from teacher where tid=#{id}")
@Results(id = "teacherMap",value = {
@Result(id = true,column = "tid",property = "tid"),
@Result(column = "tname",property = "tname"),
//关联属性
@Result(property = "list",column = "tid",many = @Many(select = "findStudentId",fetchType = FetchType.LAZY))
})
Teacher2 findById(int id);
@Select("select *from student where sid in (select sid from teacher_student where tid=#{tid} )")//子查询
List<Student2> findStudentId(int sid);
//查询所有老师信息
@Select("select * from teacher")
@ResultMap("teacherMap")
List<Teacher2> findAll();
老师的service
@Test
public void findById(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
Teacher2Mapper mapper=sqlSession.getMapper(Teacher2Mapper.class);
//查询老师信息
Teacher2 t = mapper.findById(2);
System.out.println("老师编号:"+t.getTid());
System.out.println("老师姓名:"+t.getTname());
if (t.getList().isEmpty()){
System.out.println("该老师还没有教过学生");
}else{
System.out.print("所教的学生:");
t.getList().forEach(s-> System.out.print(s.getSname()+" "));
System.out.println("");
}
sqlSession.close();
}
SqlSession session= MyBatisUtil.getSqlSession();
idCard2Mapper mapper=session.getMapper(idCard2Mapper.class);
idCard2 card=mapper.findById(1);
System.out.println("证件编号:"+card.getId());
System.out.println("证件号码:"+card.getCardNo());
System.out.println("证件持有人:"+card.getPerson().getPname());
session.close();
}
#### 2、多对多的注解配置
```vb
多对多的本质就是两个一对多
之前的写法是左外连接查询,此时就不能使用这种方法
老师-->学生
老师实体类
private Integer tid;
private String tname;
//关联属性
private List<Student2> list=new ArrayList<>();
老师的mapper
/*
* 根据老师的id,通过关系表找出他教过的所有学生(子查询)
* 1、首先查询关系表,找出该老师家教过所有学生的id
* select sid from teacher_student where tid=#{tid}
* 2、根据sid查询学生表,找出所有学生信息
* select *from student where sid in (select sid from teacher_student where tid=#{tid} )
* */
//根据id查询老师信息
@Select("select * from teacher where tid=#{id}")
@Results(id = "teacherMap",value = {
@Result(id = true,column = "tid",property = "tid"),
@Result(column = "tname",property = "tname"),
//关联属性
@Result(property = "list",column = "tid",many = @Many(select = "findStudentId",fetchType = FetchType.LAZY))
})
Teacher2 findById(int id);
@Select("select *from student where sid in (select sid from teacher_student where tid=#{tid} )")//子查询
List<Student2> findStudentId(int sid);
//查询所有老师信息
@Select("select * from teacher")
@ResultMap("teacherMap")
List<Teacher2> findAll();
老师的service
@Test
public void findById(){
SqlSession sqlSession= MyBatisUtil.getSqlSession();
Teacher2Mapper mapper=sqlSession.getMapper(Teacher2Mapper.class);
//查询老师信息
Teacher2 t = mapper.findById(2);
System.out.println("老师编号:"+t.getTid());
System.out.println("老师姓名:"+t.getTname());
if (t.getList().isEmpty()){
System.out.println("该老师还没有教过学生");
}else{
System.out.print("所教的学生:");
t.getList().forEach(s-> System.out.print(s.getSname()+" "));
System.out.println("");
}
sqlSession.close();
}