【Mybatis 】续章! 什么是mybatis?如何整合springboot使用?(超详细建议收藏)

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

image-20230614105954275

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

一对多

3

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

image-20230614165358085

证件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();
    }
  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

arjunna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值