0
点赞
收藏
分享

微信扫一扫

深入理解mybatis原理(七) MyBatis的架构设计以及实例分析


MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单、优雅。本文主要讲述MyBatis的​​架构​​设计思路,并且讨论MyBatis的几个核心部件,然后结合一个select查询实例,深入代码,来探究MyBatis的实现。

一、MyBatis的框架设计

                   

深入理解mybatis原理(七) MyBatis的架构设计以及实例分析_List_02

      上述使用MyBatis的方法,是创建一个和数据库打交道的SqlSession对象,然后根据Statement Id 和参数来操作数据库,这种方式固然很简单和实用,但是它不符合面向对象语言的概念和面向接口编程的编程习惯。由于面向接口的编程是面向对象的大趋势,MyBatis为了适应这一趋势,增加了第二种使用MyBatis支持接口(Interface)调用方式。

1.2. 使用Mapper接口

 MyBatis将配置文件中的每一个<mapper>节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟<mapper>节点中的<select|update|delete|insert>节点项对应,即<select|update|delete|insert>节点的id值为Mapper接口中的方法名称,parameterType值表示Mapper对应方法的入参类型,而resultMap值则对应了Mapper接口表示的返回值类型或者返回结果集的元素类型。

二、MyBatis的主要构件及其相互关系

  从MyBatis代码实现的角度来看,MyBatis的主要的核心部件有以下几个:

  • SqlSession           作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
  • Executor             MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
  • StatementHandler  封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
  • ParameterHandler  负责对用户传递的参数转换成JDBC Statement 所需要的参数,
  • ResultSetHandler   负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
  • TypeHandler         负责java数据类型和jdbc数据类型之间的映射和转换
  • MappedStatement  MappedStatement维护了一条<select|update|delete|insert>节点的封装, 
  • SqlSource           负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
  • BoundSql            表示动态生成的SQL语句以及相应的参数信息
  • Configuration       MyBatis所有的配置信息都维持在Configuration对象之中。

(注:这里只是列出了我个人认为属于核心的部件,请读者不要先入为主,认为MyBatis就只有这些部件哦!每个人对MyBatis的理解不同,分析出的结果自然会有所不同,欢迎读者提出质疑和不同的意见,我们共同探讨~)

它们的关系如下图所示:


深入理解mybatis原理(七) MyBatis的架构设计以及实例分析_mybatis_04

三、从MyBatis一次select 查询语句来分析MyBatis的架构设计

一、数据准备(非常熟悉和应用过MyBatis 的读者可以迅速浏览此节即可)

    1. 准备数据库数据,创建EMPLOYEES表,插入数据:      



[sql]  ​​view plain​​  ​​copy​​

 



  1.     
  2. --创建一个员工基本信息表  
  3. create  table "EMPLOYEES"(  
  4. "EMPLOYEE_ID" NUMBER(6) not null,  
  5. "FIRST_NAME" VARCHAR2(20),  
  6. "LAST_NAME" VARCHAR2(25) not null,  
  7. "EMAIL" VARCHAR2(25) not null unique,  
  8. "SALARY" NUMBER(8,2),  
  9. constraint "EMP_EMP_ID_PK" primary key ("EMPLOYEE_ID")  
  10.    );  
  11. on table EMPLOYEES is '员工信息表';  
  12. on column EMPLOYEES.EMPLOYEE_ID is '员工id';  
  13. on column EMPLOYEES.FIRST_NAME is 'first name';  
  14. on column EMPLOYEES.LAST_NAME is 'last name';  
  15. on column EMPLOYEES.EMAIL is 'email address';  
  16. on column EMPLOYEES.SALARY is 'salary';  
  17.      
  18. --添加数据  
  19. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  20. values (100, 'Steven', 'King', 'SKING', 24000.00);  
  21.   
  22. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  23. values (101, 'Neena', 'Kochhar', 'NKOCHHAR', 17000.00);  
  24.   
  25. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  26. values (102, 'Lex', 'De Haan', 'LDEHAAN', 17000.00);  
  27.   
  28. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  29. values (103, 'Alexander', 'Hunold', 'AHUNOLD', 9000.00);  
  30.   
  31. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  32. values (104, 'Bruce', 'Ernst', 'BERNST', 6000.00);  
  33.   
  34. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  35. values (105, 'David', 'Austin', 'DAUSTIN', 4800.00);  
  36.   
  37. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  38. values (106, 'Valli', 'Pataballa', 'VPATABAL', 4800.00);  
  39.   
  40. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  41. values (107, 'Diana', 'Lorentz', 'DLORENTZ', 4200.00);      




[sql]  ​​view plain​​  ​​copy​​



  1.     
  2. --创建一个员工基本信息表  
  3. create  table "EMPLOYEES"(  
  4. "EMPLOYEE_ID" NUMBER(6) not null,  
  5. "FIRST_NAME" VARCHAR2(20),  
  6. "LAST_NAME" VARCHAR2(25) not null,  
  7. "EMAIL" VARCHAR2(25) not null unique,  
  8. "SALARY" NUMBER(8,2),  
  9. constraint "EMP_EMP_ID_PK" primary key ("EMPLOYEE_ID")  
  10.    );  
  11. on table EMPLOYEES is '员工信息表';  
  12. on column EMPLOYEES.EMPLOYEE_ID is '员工id';  
  13. on column EMPLOYEES.FIRST_NAME is 'first name';  
  14. on column EMPLOYEES.LAST_NAME is 'last name';  
  15. on column EMPLOYEES.EMAIL is 'email address';  
  16. on column EMPLOYEES.SALARY is 'salary';  
  17.      
  18. --添加数据  
  19. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  20. values (100, 'Steven', 'King', 'SKING', 24000.00);  
  21.   
  22. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  23. values (101, 'Neena', 'Kochhar', 'NKOCHHAR', 17000.00);  
  24.   
  25. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  26. values (102, 'Lex', 'De Haan', 'LDEHAAN', 17000.00);  
  27.   
  28. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  29. values (103, 'Alexander', 'Hunold', 'AHUNOLD', 9000.00);  
  30.   
  31. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  32. values (104, 'Bruce', 'Ernst', 'BERNST', 6000.00);  
  33.   
  34. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  35. values (105, 'David', 'Austin', 'DAUSTIN', 4800.00);  
  36.   
  37. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  38. values (106, 'Valli', 'Pataballa', 'VPATABAL', 4800.00);  
  39.   
  40. insert into EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY)  
  41. values (107, 'Diana', 'Lorentz', 'DLORENTZ', 4200.00);      


  

2. 配置Mybatis的配置文件,命名为mybatisConfig.xml:



[html]  ​​view plain​​  ​​copy​​

 



  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  4. <configuration>  
  5. <environments default="development">  
  6. <environment id="development">  
  7. <transactionManager type="JDBC" />  
  8. <dataSource type="POOLED">  
  9. <property name="driver" value="oracle.jdbc.driver.OracleDriver" />    
  10. <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />    
  11. <property name="username" value="louis" />    
  12. <property name="password" value="123456" />  
  13. </dataSource>  
  14. </environment>  
  15. </environments>  
  16. <mappers>  
  17. <mapper  resource="com/louis/mybatis/domain/EmployeesMapper.xml"/>  
  18. </mappers>  
  19. </configuration>  




[html]  ​​view plain​​  ​​copy​​



  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  4. <configuration>  
  5. <environments default="development">  
  6. <environment id="development">  
  7. <transactionManager type="JDBC" />  
  8. <dataSource type="POOLED">  
  9. <property name="driver" value="oracle.jdbc.driver.OracleDriver" />    
  10. <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />    
  11. <property name="username" value="louis" />    
  12. <property name="password" value="123456" />  
  13. </dataSource>  
  14. </environment>  
  15. </environments>  
  16. <mappers>  
  17. <mapper  resource="com/louis/mybatis/domain/EmployeesMapper.xml"/>  
  18. </mappers>  
  19. </configuration>  


3.     创建Employee实体Bean 以及配置Mapper配置文件



[java]  ​​view plain​​  ​​copy​​

 



  1. package com.louis.mybatis.model;  
  2.   
  3. import java.math.BigDecimal;  
  4.   
  5. public class Employee {  
  6. private Integer employeeId;  
  7.   
  8. private String firstName;  
  9.   
  10. private String lastName;  
  11.   
  12. private String email;  
  13.   
  14. private BigDecimal salary;  
  15.   
  16. public Integer getEmployeeId() {  
  17. return employeeId;  
  18.     }  
  19.   
  20. public void setEmployeeId(Integer employeeId) {  
  21. this.employeeId = employeeId;  
  22.     }  
  23.   
  24. public String getFirstName() {  
  25. return firstName;  
  26.     }  
  27.   
  28. public void setFirstName(String firstName) {  
  29. this.firstName = firstName;  
  30.     }  
  31.   
  32. public String getLastName() {  
  33. return lastName;  
  34.     }  
  35.   
  36. public void setLastName(String lastName) {  
  37. this.lastName = lastName;  
  38.     }  
  39.   
  40. public String getEmail() {  
  41. return email;  
  42.     }  
  43.   
  44. public void setEmail(String email) {  
  45. this.email = email;  
  46.     }  
  47.   
  48. public BigDecimal getSalary() {  
  49. return salary;  
  50.     }  
  51.   
  52. public void setSalary(BigDecimal salary) {  
  53. this.salary = salary;  
  54.     }  
  55. }  




[java]  ​​view plain​​  ​​copy​​



  1. package com.louis.mybatis.model;  
  2.   
  3. import java.math.BigDecimal;  
  4.   
  5. public class Employee {  
  6. private Integer employeeId;  
  7.   
  8. private String firstName;  
  9.   
  10. private String lastName;  
  11.   
  12. private String email;  
  13.   
  14. private BigDecimal salary;  
  15.   
  16. public Integer getEmployeeId() {  
  17. return employeeId;  
  18.     }  
  19.   
  20. public void setEmployeeId(Integer employeeId) {  
  21. this.employeeId = employeeId;  
  22.     }  
  23.   
  24. public String getFirstName() {  
  25. return firstName;  
  26.     }  
  27.   
  28. public void setFirstName(String firstName) {  
  29. this.firstName = firstName;  
  30.     }  
  31.   
  32. public String getLastName() {  
  33. return lastName;  
  34.     }  
  35.   
  36. public void setLastName(String lastName) {  
  37. this.lastName = lastName;  
  38.     }  
  39.   
  40. public String getEmail() {  
  41. return email;  
  42.     }  
  43.   
  44. public void setEmail(String email) {  
  45. this.email = email;  
  46.     }  
  47.   
  48. public BigDecimal getSalary() {  
  49. return salary;  
  50.     }  
  51.   
  52. public void setSalary(BigDecimal salary) {  
  53. this.salary = salary;  
  54.     }  
  55. }  




[html]  ​​view plain​​  ​​copy​​

 



  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
  3. <mapper namespace="com.louis.mybatis.dao.EmployeesMapper" >  
  4.   
  5. <resultMap id="BaseResultMap" type="com.louis.mybatis.model.Employee" >  
  6. <id column="EMPLOYEE_ID" property="employeeId" jdbcType="DECIMAL" />  
  7. <result column="FIRST_NAME" property="firstName" jdbcType="VARCHAR" />  
  8. <result column="LAST_NAME" property="lastName" jdbcType="VARCHAR" />  
  9. <result column="EMAIL" property="email" jdbcType="VARCHAR" />  
  10. <result column="SALARY" property="salary" jdbcType="DECIMAL" />  
  11. </resultMap>  
  12.     
  13. <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >  
  14.     select   
  15.         EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY  
  16.         from LOUIS.EMPLOYEES  
  17. EMPLOYEE_ID = #{employeeId,jdbcType=DECIMAL}  
  18. </select>  
  19. </mapper>  




[html]  ​​view plain​​  ​​copy​​



  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
  3. <mapper namespace="com.louis.mybatis.dao.EmployeesMapper" >  
  4.   
  5. <resultMap id="BaseResultMap" type="com.louis.mybatis.model.Employee" >  
  6. <id column="EMPLOYEE_ID" property="employeeId" jdbcType="DECIMAL" />  
  7. <result column="FIRST_NAME" property="firstName" jdbcType="VARCHAR" />  
  8. <result column="LAST_NAME" property="lastName" jdbcType="VARCHAR" />  
  9. <result column="EMAIL" property="email" jdbcType="VARCHAR" />  
  10. <result column="SALARY" property="salary" jdbcType="DECIMAL" />  
  11. </resultMap>  
  12.     
  13. <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >  
  14.     select   
  15.         EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL, SALARY  
  16.         from LOUIS.EMPLOYEES  
  17. EMPLOYEE_ID = #{employeeId,jdbcType=DECIMAL}  
  18. </select>  
  19. </mapper>  


4. 创建eclipse 或者myeclipse 的maven项目,maven配置如下:



[html]  ​​view plain​​  ​​copy​​

 



  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3. <modelVersion>4.0.0</modelVersion>  
  4.   
  5. <groupId>batis</groupId>  
  6. <artifactId>batis</artifactId>  
  7. <version>0.0.1-SNAPSHOT</version>  
  8. <packaging>jar</packaging>  
  9.   
  10. <name>batis</name>  
  11. <url>http://maven.apache.org</url>  
  12.   
  13. <properties>  
  14. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15. </properties>  
  16.   
  17. <dependencies>  
  18. <dependency>  
  19. <groupId>junit</groupId>  
  20. <artifactId>junit</artifactId>  
  21. <version>3.8.1</version>  
  22. <scope>test</scope>  
  23. </dependency>  
  24.   
  25. <dependency>  
  26. <groupId>org.mybatis</groupId>  
  27. <artifactId>mybatis</artifactId>  
  28. <version>3.2.7</version>  
  29. </dependency>  
  30.       
  31. <dependency>  
  32. <groupId>com.oracle</groupId>  
  33. <artifactId>ojdbc14</artifactId>  
  34. <version>10.2.0.4.0</version>  
  35. </dependency>  
  36.       
  37. </dependencies>  
  38. </project>  




[html]  ​​view plain​​  ​​copy​​



  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3. <modelVersion>4.0.0</modelVersion>  
  4.   
  5. <groupId>batis</groupId>  
  6. <artifactId>batis</artifactId>  
  7. <version>0.0.1-SNAPSHOT</version>  
  8. <packaging>jar</packaging>  
  9.   
  10. <name>batis</name>  
  11. <url>http://maven.apache.org</url>  
  12.   
  13. <properties>  
  14. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15. </properties>  
  16.   
  17. <dependencies>  
  18. <dependency>  
  19. <groupId>junit</groupId>  
  20. <artifactId>junit</artifactId>  
  21. <version>3.8.1</version>  
  22. <scope>test</scope>  
  23. </dependency>  
  24.   
  25. <dependency>  
  26. <groupId>org.mybatis</groupId>  
  27. <artifactId>mybatis</artifactId>  
  28. <version>3.2.7</version>  
  29. </dependency>  
  30.       
  31. <dependency>  
  32. <groupId>com.oracle</groupId>  
  33. <artifactId>ojdbc14</artifactId>  
  34. <version>10.2.0.4.0</version>  
  35. </dependency>  
  36.       
  37. </dependencies>  
  38. </project>  


 5. 客户端代码:



[java]  ​​view plain​​  ​​copy​​

 



  1. package com.louis.mybatis.test;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import org.apache.ibatis.io.Resources;  
  9. import org.apache.ibatis.session.SqlSession;  
  10. import org.apache.ibatis.session.SqlSessionFactory;  
  11. import org.apache.ibatis.session.SqlSessionFactoryBuilder;  
  12.   
  13. import com.louis.mybatis.model.Employee;  
  14.   
  15. /**
  16.  * SqlSession 简单查询演示类
  17.  * @author louluan
  18.  */  
  19. public class SelectDemo {  
  20.   
  21. public static void main(String[] args) throws Exception {  
  22. /*
  23.          * 1.加载mybatis的配置文件,初始化mybatis,创建出SqlSessionFactory,是创建SqlSession的工厂
  24.          * 这里只是为了演示的需要,SqlSessionFactory临时创建出来,在实际的使用中,SqlSessionFactory只需要创建一次,当作单例来使用
  25.          */  
  26. "mybatisConfig.xml");  
  27. new SqlSessionFactoryBuilder();  
  28.         SqlSessionFactory factory = builder.build(inputStream);  
  29.           
  30. //2. 从SqlSession工厂 SqlSessionFactory中创建一个SqlSession,进行数据库操作  
  31.         SqlSession sqlSession = factory.openSession();  
  32.       
  33. //3.使用SqlSession查询  
  34. new HashMap<String,Object>();  
  35.           
  36. "min_salary",10000);  
  37. //a.查询工资低于10000的员工  
  38. "com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary",params);  
  39. //b.未传最低工资,查所有员工  
  40. "com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary");  
  41. "薪资低于10000的员工数:"+result.size());  
  42. //~output :   查询到的数据总数:5    
  43. "所有员工数: "+result1.size());  
  44. //~output :  所有员工数: 8  
  45.     }  
  46.   
  47. }  




[java]  ​​view plain​​  ​​copy​​



  1. package com.louis.mybatis.test;  
  2.   
  3. import java.io.InputStream;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import org.apache.ibatis.io.Resources;  
  9. import org.apache.ibatis.session.SqlSession;  
  10. import org.apache.ibatis.session.SqlSessionFactory;  
  11. import org.apache.ibatis.session.SqlSessionFactoryBuilder;  
  12.   
  13. import com.louis.mybatis.model.Employee;  
  14.   
  15. /**
  16.  * SqlSession 简单查询演示类
  17.  * @author louluan
  18.  */  
  19. public class SelectDemo {  
  20.   
  21. public static void main(String[] args) throws Exception {  
  22. /*
  23.          * 1.加载mybatis的配置文件,初始化mybatis,创建出SqlSessionFactory,是创建SqlSession的工厂
  24.          * 这里只是为了演示的需要,SqlSessionFactory临时创建出来,在实际的使用中,SqlSessionFactory只需要创建一次,当作单例来使用
  25.          */  
  26. "mybatisConfig.xml");  
  27. new SqlSessionFactoryBuilder();  
  28.         SqlSessionFactory factory = builder.build(inputStream);  
  29.           
  30. //2. 从SqlSession工厂 SqlSessionFactory中创建一个SqlSession,进行数据库操作  
  31.         SqlSession sqlSession = factory.openSession();  
  32.       
  33. //3.使用SqlSession查询  
  34. new HashMap<String,Object>();  
  35.           
  36. "min_salary",10000);  
  37. //a.查询工资低于10000的员工  
  38. "com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary",params);  
  39. //b.未传最低工资,查所有员工  
  40. "com.louis.mybatis.dao.EmployeesMapper.selectByMinSalary");  
  41. "薪资低于10000的员工数:"+result.size());  
  42. //~output :   查询到的数据总数:5    
  43. "所有员工数: "+result1.size());  
  44. //~output :  所有员工数: 8  
  45.     }  
  46.   
  47. }  



二、SqlSession 的工作过程分析:

1. 开启一个数据库访问会话---创建SqlSession对象:



[java]  ​​view plain​​  ​​copy​​

 



  1. SqlSession sqlSession = factory.openSession();  




[java]  ​​view plain​​  ​​copy​​



  1. SqlSession sqlSession = factory.openSession();  


 MyBatis封装了对数据库的访问,把对数据库的会话和事务控制放到了SqlSession对象中。

举报

相关推荐

0 条评论