1、本篇博客的背景和目的
目前我本人正在学习MyBatis框架,在原先了解并且懵懵懂懂使用的基础上,开始系统正式的学习。目前已经阐述了MVC架构模式和三层架构,明晰了在Web项目中的普遍编码层次,认识了框架,回顾了JDBC连接数据库,介绍了MyBatis框架,初步建立了使用MyBatis和MySQL的Maven项目,简单解释了STDOUT_LOGGING日志和INSERT语句手动提交事务,记录了MyBatis中#占位符的使用方法,回顾了MyBatis执行SQL语句的过程和使用到的一些重要类和接口,记录了将固定化的代码整合到一个工具类MyBatisUtil中,以减少代码量。记录了dao层接口的实现以及为什么要实现它。本篇博客说明一下MyBatis动态代理和使用动态代理的要求以及初步使用一下动态代理生成的实现类。
2、我的上一篇博文
我的上一篇博文记录的是dao层接口的手动实现。也就是手写dao接口的实现类,链接如下:
3、MyBatis为什么引入了动态代理
其实简单的说,还是因为程序员的 懒!!!
上一篇博文中,我们手写了dao接口的实现类,然后调用实现类的某一个方法就可以执行某一个SQL语句。
但是:当我们有很多张表,每一张表都对应一个mapper.xml文件,那就都有一个dao层的接口,那我们是不是要写很多的实现类呢??是不是要累死,要无聊枯燥死了!!!
我们就想,能不能使用一个方法,让dao层的某一个接口默认直接和某一个mapper.xml文件对应;让dao层接口中的每一个方法都完全正确的对应mapper.xml文件中的一个SQL语句(也就是一个select或者insert,update,delete标签)。换句话说:就是让MyBatis框架给我们自动生成dao层接口的实现类。
这完全是可以实现的,称为MyBatis的动态代理。这就需要使用到反射,并且还有一定的条件。
4、能够实现MyBatis动态代理的依据
分析一下写完dao层接口的实现类以后MyBatis的执行过程吧:
StudentDao dao=new StudentDaoImpl(); List<Student> students = dao.selectStudents();
1、这个dao(也就是dao层的接口对象,这里使用了上转型):我们通过反射能够得到 它的全限定类型名称;这个dao是StudentDao类型的,所以它的全限定名称就是:
com.dcy.dao.StudentDao

2、selectStudents( ); 这个就是dao层接口中的方法名称,这方法的名称也是mapper文件中select标签的id属性值 通过dao.selectStudents()能得到
String SqlId="com.dcy.dao.StudentDao"+"."+"selectStudents";
3、确定去调用SqlSession的那一个方法:首先可以根据dao接口中的方法的返回值,如果返回的是一个JAVA对象,比如说Student,那么调用的就是SqlSession.SelectOne();如果dao接口中的方法返回的是一个LIst,那么调用的就应该是selectList()方法;还可以根据mapper文件中的标签,如果标签是insert,那么调用的肯定就是 insert()方法了;
MyBatis框架也发现使用Dao的方法调用也能确定执行SQL语句的必要的信息,所以MyBatis可以简化dao对象的实现。
由myBatis框架在程序执行期间,根据你的Dao接口,创建一个内存中的接口的实现类对象。MyBatis把这个技术叫做 dao 的动态代理,或者是dao的代理技术;
dao代理技术:由MyBatis创建StudentDao接口的实现类StudentDaoImpl,使用这个框架创建的实现类来代替你自己手工实现的 实现类的功能;那么这样就不需要开发人员自己写实现类了;但是框架实际创建的并不是就叫这个名字, 框架创建的实现类的真正名字是 proxy。
5、使用MyBatis动态代理技术的要求
上面的依据里面,最重要的就是SqlId字符串值的确定,也就是SQL语句“地址”的确定。我们需要将SQL语句的地址同每一个方法对应起来。
在mapper.xml文件中,<mapper>标签有一个namespace属性,这个属性的属性值在整个项目中是惟一的。每一个SQL语句的标签,select,insert,delete等,都有一个id属性值,这个id属性值在这个mapper.xml文件中又是唯一的。这样根据这个字符串地址就能唯一确定一个SQL语句。
虽然namespace属性值和id属性值可以是任何的字符串,只要保证唯一就行,
但是:按照编码规范,namespace属性值必须是这个mapper.xml文件对应的全限定路径名称。id属性值必须是这个SQL语句对应的方法名。
只有这样,MyBatis才能自动生成dao层接口对应的实现类。才能实现dao层接口的动态代理。利用的是反射机制!!!
上面的也就是 实现MyBatis动态代理技术的要求!!
6、使用MyBatis动态代理自动生成的实现类
按照要求编写代码,MyBatis已经为我们自动生成了实现类,但是我们怎么获得并使用这个实现类的对象呢?
多说一下:如果后端使用SpringBoot框架的话,那么两者结合,在接口上面使用注解将生成的实现类交给SpringIOC容器管理,再直接将接口注入到业务逻辑类中,然后就可以调用方法执行SQL语句了。
目前没有使用SpringBoot框架。
那么就需要使用下面的一行关键代码:
StudentDao dao= session.getMapper(StudentDao.class);
举现在项目的例子:有 StudentDao的接口,首先需要使用我们自己编写的工具类:
SqlSession session=MyBatisUtils.getSqlSession(); 得到SqlSession对象。
然后,StudentDao dao= session.getMapper(StudentDao.class);
StudentDao dao= session.getMapper(StudentDao.class);
//上面这一行代码就是获取代理对象
上面的这一行代码与: StudentDao dao=new StudentDaoImpl()是一样的性质;
在Main方法中测试一下,先看一下项目结构:
其中的impl文件夹中是我上一篇博文中写的dao层接口的实现类,由于已经使用了动态代理,所以这个文件夹可以不用了。
main方法中测试代码如下所示:
package com.dcy;
import com.dcy.dao.StudentDao;
import com.dcy.domain.Student;
import com.dcy.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class starter03 {
public static void main(String[] args) {
SqlSession sqlSession= MyBatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);//利用了MyBatis的动态代理技术
List<Student> students = studentDao.selectStudents();
System.out.println(students);
}
}
可以顺利查出结果。