# Mybatis_notes **Repository Path**: trying326/Mybatis_notes ## Basic Information - **Project Name**: Mybatis_notes - **Description**: 记录MyBatis的学习记录,练习实例。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-05-28 - **Last Updated**: 2024-11-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Mybatis_notes #### 介绍 ​ MyBatis的学习记录,实例练习,对于MyBatis的使用做了一些详细的介绍,并附带示例,以及详细的注释,能够快速入门。 ​ 这些都是我个人学习MyBatis的经验,最近做了一些整理,并不涉及深层次的原理,只能作为MyBatis的基础入门级别的参考,如果有错误的地方,欢迎指正。 ​ 笔记如果不够详尽,或者有表述不清楚,逻辑混乱的地方,希望看到的人能够包含,并且希望能够给出修改意见。 ​ 不胜感激!!! ## Mybatis--【入门示例】 1)导包 2)可新配置文件,configuration.xml ​ 配置和数据库相关的信息,driver / url / username / password ... 3)提供SqlSession对象,对数据库进行操作 4)传递参数,实现增删改查。 MyBatis默认手动提交事务 5)配置--mybatis核心配置文件 ```xml ``` 6)配置--mapper文件 ```xml sql : insert sql : update sql : delete ``` 7)MyBatis--新增[简单示例--静态参数] ```java package cn.qzbook.dao.Student; import cn.qzbook.domain.Student; 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 java.io.IOException; import java.io.InputStream; public class StudentDao { //新增 [简单实现,没有传递参数,只在配置文件中写死sql] public void insert() throws IOException { //将核心配置文件读取到输入流 InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml"); //获取SqlSessionFactoryBuilder[sql会话工厂建造者] SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //通过builder获取SqlSessionFactory[sql会话工厂] 并加载核心配置文件[输入流] SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream); //获取一个sql连接[会话] MyBatis默认开启事务,并且需要手动提交,可以改为自动提交[arg == true] SqlSession sqlSession = sqlSessionFactory.openSession(true); //sqlSession 执行insert方法 [arg == mapper中insert标签的id] sqlSession.insert("insert"); //如果没有修改MyBatis的手动提交事务,手动提交[sqlSession.commit()] } ``` ## MyBatis--【初始化 / 获取连接】 ```java //将核心配置文件读取到输入流 InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml"); //获取SqlSessionFactoryBuilder[sql会话工厂建造者] SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //通过builder获取SqlSessionFactory[sql会话工厂] 并加载核心配置文件[输入流] SqlSessionFactory sqlSessionFactory = builder.build(resourceAsStream); //获取一个sql连接[会话] MyBatis默认开启事务,并且需要手动提交,可以改为自动提交[arg == true] SqlSession sqlSession = sqlSessionFactory.openSession(true); ``` ##MyBatis--【增/ 删 / 改 / 静态参数】 ##MyBatis--【增/ 删 / 改 / 动态参数】 ##MyBatis--【简单查询 / 静态参数】 1)单条查询 配置文件--添加select标签 [简单实现,不传递参数] ```xml ``` 实现--java代码 ```java public Student selectOne() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml"); SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sfb.build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(true); //前面流程一样 //查询单条记录,调用selectOne方法 [多条selectList] Student student = sqlSession.selectOne("selectOne"); return student; } ``` 2)多条查询 配置文件--添加select标签 [简单实现,无条件参数] ```xml ``` 实现--java代码 ```java public List selectList() throws IOException { InputStream resourceAsStream = Resources.getResourceAsStream("configuration.xml"); SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory = sfb.build(resourceAsStream); SqlSession sqlSession = sqlSessionFactory.openSession(true); //前面流程一样 //查询多条记录,调用selectList [单条selectOne方法] List students = sqlSession.selectList("selectList"); return students; } ``` 3)自定义查询[统计查询] 配置文件----添加select标签 [简单实现,无条件参数,查询记录条数,返回值为基本数据类型] ```xml ``` 实现--java代码 ```java public int selectCount(){ //获取session对象省略 ... int num = sqlSession.selectOne("selectCount"); return num; } ``` MyBatis支持对象,也支持基本数据类型,只需要在select标签的resultType中填写sql结果集对应的数据类型即可。 4)自定义查询[拼接的结果集] 配置文件--添加select标签[无参,结果集没有对应的domain实体,且不止一个,使用map作为结果集容器] ```xml ``` 实现--java代码 ```java /** 查询一个结果还是多个结果,取决于调用selectOne还是selectList 这里是调用selectList,所以返回结果是List结合,hashMap则表示其中单行记录 list是一个结果集,map是一行的记录 */ public List> selectNameAndNum(){ //获取session对象省略 ... List> result = sqlSession.selectList("selectNameAndNum"); return result; } ``` 补充小记 ```text 操作SQL语句执行时 携带动态参数 sqlSession调用方法时候 增删改查都提供了两个重载 insert("sqlid"); insert("sqlId",object); 执行sql语句的时候 SQL语句中使用 #{key}取值 如果SQL语句只有一个#{key} key是可以随便写的 如果sql语句中有两个或以上的#{key} 需要key与传递参数的值对应 domain对象 map ``` ##MyBatis--【增删改 / 动态参数】 ##MyBatis--【新增 / 单表 / 动态参数】 配置文件--添加insert标签[有参:参数类型对应sqlSession.insert(“标签id”,Object)方法的中第二个参数] ```xml insert into student(name,age) values(#{name},#{age}) ``` 实现--Java代码 ```java public void insertByObj(Student student){ sqlSession.insert("insertByObj",student); } ``` 动态参数--[#{key} / ${key} 的区别 ] 1) #{key} :表示类型和值,同时代表两个特性。在MyBatis底层,JDBC下prepareStatement(),预处理sql语句时候,sql语句中通常有【?】作为占位符,这里的【?】即表示一个值,同时也能表示这个值得类型,在ps.setXXX()的过程中,能够成功的完成SQL的拼接。#{} --- > 在MyBatis中做了同样的处理,通常用来做SQL语句中条件的取值,能够识别数据类型,在拼接SQL的时候,如果是varchar类型,会加上单引号 [‘ xxx ’]。 ​ 【通常用来取的值为 条件参数 列的值 作为sql执行的条件参数】 2)${kye} : 不会判断类型,在sql拼接的时候,会原封不动的将【获取的值】放到对应的位置 ​ 【通常用来取的值为 表名 / 列明 / mysql的关键字】 ​ 例: ```xml ``` ##MyBatis--【嵌套查询 / 一对一 / 一表一SQL】 实体对象关系【Person----IDcard】,一个人[person]对应一张身份证号[外键] 数据库表 ```sql create table idcard( cardid varchar(18), address varchar(20) )character set utf8; alter table idcard add constraint pk_idcard primary key(cardid); create table person( pid int(15), pname varchar(30), cardid varchar(18) )character set utf8; alter table person add constraint pk_person primary key(pid); alter table person add constraint fk_person_idcard foreign key(cardid) references idcard(cardid); alter table person add constraint uk_person unique(cardid); ``` 实体类【一】person ```java package cn.qzbook.domain; import lombok.Data; //实体类Person @Data public class Person { //自有属性 private int pid; //自有属性 private String pname; //关联外键对象 private Idcard idcard; } ``` 实体类【二】idcard ```java package cn.qzbook.domain; import lombok.Data; //实体类Idcard @Data public class Idcard { //自有属性 private String idcardid; //自有属性 private String address; //为了根据身份证号查询 身份证和人的信息 //多添加一个关联属性 private Person person; } ``` 需求:根据pid,查询一个person对象 配置文件 ```xml ``` 实现---java代码 ```java //根据一个人的pid,查询人+身份证的所有信息 public void selectOnePerson(int pid){ Person person = sqlSession.selectOne("selectOnePersonAndIdcard", pid); System.out.println(person);; } ``` 一对一嵌套查询--表关系映射[单表] resultMap[标签]:表关系声明,id属性唯一,标识当前配置信息,type当前表对应的实体对象的全类名。 ​ id[子标签]:对应表主键,property[实体类属性名],column[主键字段名],做关系映射。 ​ result[子标签]:对应表普通字段,property[实体类属性名],column[表字段名],做关系映射。 ​ association[子标签]:建立外键对应的实体对象与当前对象的映射关系 ​ property[实体类属性名], ​ javaType[属性对应的java应用类型,类全名] ​ select [实体对象的数据来源,对应一条select语句的id] ​ column[select语句中的查询条件,当前表中的外键值,相当于需要传递的参数] resultMap的作用:MyBatis在查询后,返回的结果集,通常使用resultType,如果属性是基本数据类型,或者String类型,MyBatis可以自动的将结果装入到resultType既定的类型对象中。如果表存在关联关系,在实体对象中会包含另一个实体对象,作为联合属性,MyBatis是不能自动的将结果集装入联合属性中,这里就需要对应关联属性进行声明,然后MyBatis根据声明,将结果装入映射的联合属性对象中。 一对一嵌套查询--执行过程[单表] ​ MyBatis做了两件事情,首先根据pid查询到person对象,然后根据外键,使用当前person对象的外键cardid值,到idcard表中查询满足条件的idcard,将结果集封装到idcard对象,最后赋值给person的关联属性[idcard]。 ​ 在这个过程中,MyBatis执行了两条SQL语句,一共做了两次查询。 ​ 出现了SQL执行的n+1问题,避免这个问题,可以在核心配置文件中,添加两个设置标签 ```xml ``` ##MyBatis--【嵌套查询 / 一对一 / SQL联合查询 / 方案一】 实体对象关系【同上】 需求:根据pid,查询一个person对象【同上】 配置文件 ```xml ``` 一对一嵌套查询--表关系映射[联合] ​ resultMap[标签]:基本上与上面的示例相同,去除掉了附加的select语句[select属性],添加autoMapping属性,并复赋值为true。 一对一嵌套查询--执行过程[联合] ​ 在【id为selectOnePersonAndIdcard】的select语句中,直接使用了联合查询,结果集为两个表字段拼接的临时表结果集,不需要在额外的查询一次,使用autoMapping,自动将结果集中的字段,匹配到关联属性,然后赋值。 两者的区别在于: ​ 第一种是两次查询,先查询出Person的普通字段,然后通过外键字段的值,去查询idcard,最后将结果赋值到Person的关联属性idcard中。 ​ 第二种,只有一条SQL语句,使用联合查询,只查询了一次,MyBatis先解析结果集,将person的普通属性赋值,然后递归关联属性idcard的属性,从结果集中拿到,并且赋值给idcard[自动映射] Log4j.jar 日志打印工具 需要一个小工具,在执行底层数据库查询的时候,希望打印SQL语句。 ## MyBatis--【嵌套查询 / 一对一 / SQL联合查询 / 方案二】 实体对象关系【同上】 需求:根据pid,查询一个person对象【同上】 配置文件 ```xml ``` ## MyBatis--【嵌套查询 / 一对多】 表结构与关系映射 ```sql #部门表 create table dept ( deptno int(10), dname varchar(20), loc varchar(20) )character set utf8; alter table dept add constraint pk_dept primary key(deptno); commit; insert into dept values(10,'ACCOUNTING','NEW YOKR'); insert into dept values(20,'DESEARCH','DALLAS'); insert into dept values(30,'SALES','CHICAGO'); #员工表 create table emp( empno int(4), ename varchar(20), sal float(10,2), deptno int(10) )character set utf8; alter table emp add constraint pk_emp primary key(empno); alter table emp add constraint fk_emp_dept foreign key(deptno) references dept(deptno); insert into emp values(7369,'SMITH',800,20); insert into emp values(7499,'ALLEN',1600,30); insert into emp values(7521,'WARD',1250,30); insert into emp values(7566,'JONSE',2975,20); insert into emp values(7782,'CLARK',2450,10); insert into emp values(7839,'KING',5000,10); insert into emp values(7788,'SCOTT',3000,20); ``` 实例:如下两个需求 emp[员工数据] dept[部门数据] 1)提供empno -- 查询emp的数据+对应的dept数据 ​ 一对一查询:设置resultMap,添加association标签,嵌套声明关联属性与数据库表的关系。 2)提供deptno -- 查询dept的数据+部门下所有的员工数据 ​ 一对多查询:设置resultMap,添加collection ```xml ``` collection[标签]:映射返回结果的关联属性[一对多的关系],一个部门对应多个员工,所以关联属性是一个集合,泛型是员工对象[emp]。 ​ [属性一:property] 关联属性名。 ​ [属性二:javaType] 关联属性的类型[集合]。 ​ [属性三:ofType] 关联属性泛型类型[对象映射数据表]。 【数据库表一对一关系】-- > 一个java对象作为另一个对象的属性,聚合关系 has-a。 【数据库表多对多关系】--> 一个java对象作为作为泛型,存在于另一个对象的集合属性 【association】 --> 在resultMap中声明一个对象嵌套另一个对象,使用collection能够达到同样的效果,只是内存占用较大。 【collection】 --> 在resultMap中声明一个对象中嵌套一个集合<对象>,不能使用association替代。 ## MyBatis--【嵌套查询 / 多对多 / SQL联合查询】 数据库表多对多关系。 ```sql #老师信息与学生信息[一个学生对应多个老师,一个老师也可以对应多个学生] #老师表 create table teacher( tid int(8), tname varchar(20), tsex varchar(4), tage int(3) )character set utf8; alter table teacher add constraint pk_tacher primary key(tid); #学生表 create table stu( sid int(10), sname varchar(20), ssex varchar(4), sage int(3) )character set utf8; alter table stu add constraint pk_tacher primary key(sid); #中间表,映射老师与学生的多对多关系 create table tea_stu( tid int(10), sid int(10) )character set utf8; alter table tea_stu add constraint fk_treacher foreign key(tid) references teacher(tid); alter table tea_stu add constraint fk_stu foreign key(sid) references stu(sid); alter table tea_stu add constraint pk_tea_stu primary key(tid,sid); #测试数据 begin; #添加测试数据--l老师表 insert into teacher values(1,'mr-li','男',22); insert into teacher values(2,'mr-qian','男',24); insert into teacher values(3,'mr-liu','女',25); insert into teacher values(4,'ms-han','女',20); #添加测试数据--学生表 insert into stu values(1,'xiaozhao','男',12);insert into stu values(2,'xiaozhou','女',11); insert into stu values(3,'xiaowu','男',9);insert into stu values(4,'xiaozhang','女',10); insert into stu values(5,'xiaohuang','男',14);insert into stu values(6,'xiaozheng','女',17); insert into stu values(7,'xiaofeng','男',13);insert into stu values(8,'xiaocheng','女',7); insert into stu values(9,'xiaojiang','男',7);insert into stu values(10,'xiaosheng','女',7); #添加测试数据--映射表 insert into tea_stu values(1,1);insert into tea_stu values(1,5); insert into tea_stu values(1,7);insert into tea_stu values(2,3); insert into tea_stu values(2,5);insert into tea_stu values(3,4); insert into tea_stu values(3,7);insert into tea_stu values(4,2); insert into tea_stu values(4,9);insert into tea_stu values(3,8); insert into tea_stu values(2,1);insert into tea_stu values(4,1); insert into tea_stu values(3,1);insert into tea_stu values(2,2); insert into tea_stu values(3,2);insert into tea_stu values(1,3); insert into tea_stu values(4,3);insert into tea_stu values(1,4); insert into tea_stu values(2,4);insert into tea_stu values(4,6); insert into tea_stu values(1,6);insert into tea_stu values(2,6); insert into tea_stu values(1,8);insert into tea_stu values(2,8); insert into tea_stu values(1,9);insert into tea_stu values(3,9); insert into tea_stu values(3,10); commit; ``` ​ 多对多关系三个表格,由于中间表只存储了关系,没有必要存储这个domain对象,在最后查询的结果集中也不需要做展示,所以关系映射表,不需要创建实体类。 ​ 可以理解为双向的一对多的关系,在两个表格对应的实体类中,分别添加一个[集合]属性来存放关联的另一个实体类[数据表],在业务查询的时候,通常都是通过一方去查询另一方,所以基本上还是一对一的关系,只是中间多了一个记录关系的映射表,在查询的时候,需要使用到。 1)需求一【基于上述数据表的实例】 ​ 给定老师的tid -- > 查询老师的信息 + 选了当前老师课程的学生 ```xml ``` 实现 ```java package cn.qzbook.dao.ManyToMany; import cn.qzbook.MybatisTool; import cn.qzbook.domain.Teacher; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class TeacherDao { private SqlSession sqlSession = MybatisTool.sqlSessionFactory().openSession(true); @Test public void test(){ TeacherDao dao = new TeacherDao(); // dao.selectTeacherAndInnerStu(2); dao.selectTeacherAndInnerStuList(); } //给定老师的tid -- > 查询老师的信息 + 选了当前老师课程的学生 public void selectTeacherAndInnerStu(int id){ Teacher teacher = sqlSession.selectOne("selectTeacherAndInnerStu", id); System.out.println(teacher); } //查询所有老师的信息 + 选了当前老师课程的所有学生 public void selectTeacherAndInnerStuList(){ List teachers = sqlSession.selectList("selectTeacherAndInnerStuList"); for (Teacher teacher : teachers){ System.out.println(teacher); } } } ``` 2)需求二【基于上述数据表的实例】 ​ 给定学生的sid -- > 查询学生的信息 + 所有课程的老师的信息 ```xml ``` 实现 ```java package cn.qzbook.dao.ManyToMany; import cn.qzbook.MybatisTool; import cn.qzbook.domain.Stu; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class StuDao { private SqlSession sqlSession = MybatisTool.sqlSessionFactory().openSession(true); @Test public void test(){ StuDao dao = new StuDao(); // dao.selectStuAndAllTeachers(2); dao.selectStuAndAllTeachersList(); } //给定学生的sid -- > 查询学生的信息 + 所有课程的老师的信息 public void selectStuAndAllTeachers(int id){ Stu stus = sqlSession.selectOne("selectStuAndAllTeachers", id); System.out.println(stus); } //全表通查 查询学生所有的的信息 + 学生对应的所有课程老师的信息 public void selectStuAndAllTeachersList(){ List stus = sqlSession.selectList("selectStuAndAllTeachersList"); for (Stu stu : stus){ System.out.println(stu); } } } ``` ##MyBatis--【常用标签 / 核心配置文件标签】 properties[标签]:通常是为了引入一个外部的文件信息。 ​ 1)好处是可以在configuration中通过${key}方式引入一个真正的配置信息,可以隐藏真实的信息 ​ 2)可以在跟新现有环境,新引入其他框架是,可以直接引入现有的信息 示例: ```xml ``` ## MyBatis--【常用标签 / mapper配置文件标签】 实例: ```xml ``` ## MyBatis--【动态SQL--Dynamic SQL】 ## MyBatis--【基于Mapper执行 / 代理对象】 ​ 前面所有的示例,都是基于MyBatis提供的SqlSession对象,来为业务提供服务的,当初始化MyBatis,[加载核心配置文件,并且创建sqlSessionFactory对象,将sqlSession对象作为dao层的属性完成之后,所有的dao层方法内部,基本上可以简化成一条语句执行。 ​ 实际上MyBatis提供了两种方法来实现数据库的增删改查,第一种当然就是一直在使用的SqlSession对象,另一种就是基于mapper[代理对象]的方式来对数据库操作。 1)普通方式[SqlSession对象] - dao普通类中的普通方法[含有sqlSession对象作为属性]----->Mapper文件(SQL)。 - 通过sqlSession对象执行。 - dao方法中的参数基本上都是调用者传递过来。 - dao方法中的执行过程,也是调用MyBatis的sqlSession对象来完成的。 2)基于Mapper执行方式 ​ 示例中没有考虑到MVC的分层架构,所以这里所说的调用者实际上就是service层。在代码中,dao层简化后,每个方法中,实际上只有一行代码有效,就是调用sqlSession来处理数据库操作。 ​ 虽然Dao层似乎只是做了一个功能的传递,并没有做实际上的逻辑处理,但是MVC的分层架构思想,必须沿用下来,方便后续的业务拓展和维护,比如换掉了数据库产品,Dao层不需要做改变[小代价的更改],改变MyBatis的配置文件,就可以更新数据库连接等等。 ​ Dao层仍要保留,确实显得有些多余,那么这个时候,基于Mapper的方式执行,就更进一步的简化了Dao层的代码。 ​ Dao层不再进行功能传递,只有一个类似声明的作用,Dao层进一步简化,抽象成一个接口,声明返回值类型,参数类型,Mapper会根据这些信息,生成代理对象调用sqlSession来完成对数据库的操作。 ​ 基于Mapper方式执行,需要遵循的几个条件 1)Dao 层保留,Dao中的方法结构,参数、返回值,均保留。 2)Dao层下,类中的具体方法改为抽象方法。 2)Dao层下,类改为接口。 代理对象的获取 ​ dao层的类改为了接口,意味着到层的类不能真正的去处理数据库的操作,需要生成一个代理对象来对数据库进行操作,也就是说,当service层调用dao层的时候,实际是代理对象来完成数据库的操作。 ​ 生成代理对象的条件,同样需要初始化MyBatis,首先创建SqlSessionFactoryBuilder,调用builde方法,并将核心配置文件已文件流的方式作为参数,生成sqlSessionFactory对象,由sqlSessionFactory创建sqlSession对象[openSession方法],sqlSession.getMapper(Class class),传递对应的dao接口calss类型作为参数,来获取dao下类的代理对象。 ​ 使用Mapper的方式[代理对象]执行的时候,在对应的Mapper文件中,跟标签mapper的namespace属性,必须是dao接口的全限定名[全类名] ​ 代理对象继承接口,实现了方法,最后还是调用sqlSession对象来对数据库进行操作,这个过程是动态的,在程序运行的过程中,生成对象。 ​ 示例: mapper文件 ```xml ``` dao类 ```java package cn.qzbook.dao.ManyToMany; import cn.qzbook.domain.Stu; public interface StuDaoMapper { //通过id查询stu表中的学生和所有对其授课的老师 Stu selectStuAndAllTeachs(int id); } ``` service中实现 ```java package cn.qzbook.service; import cn.qzbook.MybatisTool; import cn.qzbook.dao.ManyToMany.StuDaoMapper; import cn.qzbook.domain.Stu; import org.junit.Test; public class StuService { //通过sqlSession.getMapper(Class class)方法生成代理对象 private StuDaoMapper dao = MybatisTool.sqlSessionFactory() .openSession(true) .getMapper(StuDaoMapper.class); //直接调用方法 public void selectStuService(int id){ Stu stu = dao.selectStuAndAllTeachs(id); System.out.println(stu); } //单元测试 @Test public void test(){ new StuService().selectStuService(2); } } ``` 工具类[初始化MyBatis] ```java package cn.qzbook; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; //饱汉 单利模式 public class MybatisTool { private static final SqlSessionFactory sqlSessionFactory; private MybatisTool(){} static { InputStream resourceAsStream = null; try {//读取核心配置文件 resourceAsStream = Resources.getResourceAsStream("configuration.xml"); } catch (IOException e) { e.printStackTrace(); }//创建工厂建造者对象 SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder(); sqlSessionFactory = sfb.build(resourceAsStream);//通过工厂建造者,创建工厂,解析文件 }//返回sql会话工厂 public static SqlSessionFactory sqlSessionFactory(){ return sqlSessionFactory; } } ``` 小结: 普通的方式执行数据库操作的条件[查询为例 / 都需要传递参数] 1)编写核心配置文件 2)创建mapper文件 / 编写select标签[指定id名称,SQL语句] / 嵌套查询需要创建resultMap[查询结果集的装载] 3)加载核心配置文件 / 创建sqlSession对象 / 4)调用selectOne[或者selectList] / 指定selectid / 指定参数类型 ​ sqlSession最终解析mapper文件中的那一条SQL语句,需要指定id,也需要指定参数类型,两个必不可少的条件。 ​ 使用Mapper[动态代理]的方式执行 1)编写核心配置文件 2)创建mapper文件 / 编写select标签[指定id名称,SQL语句] / 嵌套查询需要创建resultMap[查询结果集的装载] 3)加载核心配置文件 / 创建sqlSession对象 / 4)创建接口,声明方法[返回值 / 传递的参数类型] 5)使用sqlSession对象获取代理对象 比较普通的方式执行,缺少了两个必不可少的参数: ​ sql最终解析mapper文件中的那一条SQL? ​ 查询中需要的参数类型是什么? 结合示例中的配置信息,可以得出一个浅显的结论: ​ 生成代理对象的接口,必须对应一个mapper文件,在mapper文件的根标签的namespace,指定接口的全类名,将最终解析的SQL范围缩小到一个mapper文件。 ​ 查询语句最后结果集的装载,在配置文件resultMap中声明,接口对应这个文件,就能解析到。 ​ 接口中的方法名,必须与SQL标签的id保持一致。相当于普通的方式执行里面,sqlSession调用方法指定SQL标签id,接口方法中的参数信息,也能被代理对象获悉,与之对应起来。 ## MyBatis--【动态代理机制】 ## MyBatis--【基于注解开发--增删改】 ## MyBatis--【基于注解开发--查询】 #### 码云特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目 5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)