小白学习java之mybatis第一天

第一章:MyBatis

第1节:阶段内容

本章节介绍我们框架阶段分为核心框架基础和核心框架高级两部分
核心框架基础:     
    1. Mybatis持久层技术
    2. Spring逻辑控制技术
    3. SpringMVC Web交互技术
    4. SSM整合进行单体项目开发
核心框架高级
    1. zookeeper 注册中心 
    2. Dubbo     分布式技术
    3. SpringBoot Spring框架整合
    4. Mybatis-Plus Mybatis封装工具
    5. Redis&Nginx  非关系型数据库与负载均衡工具 
分布式项目     
 		基于springBoot+Mybatis+Zookeeper+Dubbo 的综合健康项目。

第2节:学习方法

1. 认真听讲,重点听取框架的基础语法和设计思想。
    
   俗话说,内行看门道,外行看热闹。学习也是一样,首先要认真听讲,对于重点内容要聚精汇神,了解框架结构和设计思想,这样才能阔宽自己的视野,领悟知识的精髓。
    
2. 注重实践
    
    我们都知道理论与实践是相脱节的,也就是说听懂和学会知识是两个概念,它们之间是有一条鸿沟的,想要跨过鸿沟,把理论知识变成自己的知识,唯一的途径就是不断的练习即实践。
    
3. 不断提升自我学习能力
    
    在学习过程中不要机械化的学习,对框架来讲其实很简单,首先要看官方文档,从文档入手,根据文档所提示步聚一步一步进行实践,总结和探讨为什么框架要这么做,分析其原理,不断提高自己的学习能力。
    
4. 不断提升自主解决问题的能力
    
    在练习过程中,不出错的人是不存在,其实出错是一件好事,因为我们都是从错误中吸取教训和总结,但是,一定要戒骄戒燥,遇到问题要令静分析问题出现的原因,不断的进行总结增加自己的经验,这样解决问题的能力才能有提升。

第3节:框架概述

3.1 框架介绍
		框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。

总结: 
框架把重复利用的单独抽取, 形成项目的半成品, 半成品就是我们所说的框架。
程序员在框架基础之上,进行开发。
提升了开发效率,减少了重复性代码~ 

		我们是由于效率和易用性的考虑使用框架。框架能节省开发时间。框架强制使用公共的约定,因此它能有效地解决一些共有的问题,它能让决定更连贯,避免我们写一大堆自定义模块来实现这些性能,框架节省了我们不少的时间和精力,并且让扩展变得更容易。

在这里插入图片描述

3.2 框架解决的问题
3.2.1 技术整合问题
   		框架要解决的最重要的一个问题是技术整合的问题,在 J2EE 的 框架中,有着各种各样的技术,不同的软件企业需要从 J2EE 中选择不同的技术,这就使得软件企业最终的应用依赖于这些技术,技术自身的复杂性和技术的风险性将会直接对应用造成冲击。而应用是软件企业的核心,是竞争力的关键所在,因此应该将应用自身的设计和具体的实现技术解耦。这样,软件企业的研发将集中在应用的设计上,而不是具体的技术实现,技术实现是应用的底层支撑,它不应该直接对应用产生影响。框架一般处在低层应用平台(如 J2EE )和高层业务逻辑之间的中间层。
3.2.2 三层架构
   分层后的优势:
     	 1.避免了表示层直接访问数据访问层,表示层只和业务逻辑层有联系,提高了数据安全性。 
        2.有利于系统的分散开发,每一个层可以由不同的人员来开发,只要遵循接口标准,利用相同的对象模型实体类就可以了,这样就可以           大大提高系统的开发速度。
        3.方便系统的移植,如果要把一个 C/S 的系统变成 B/S 系统,只要修改三层架构的表示层就可以了,业务逻辑层和数据访问层几乎           不用修改就可以轻松的把系统移植到网络上。
        4.项目结构更清楚,分工更明确,有利于后期的维护和升级。
        

在这里插入图片描述

在这里插入图片描述

3.3 常见框架
1. 持久化框架
       1) 持久化框架Mybatis
         MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了googlecode,       并且改名为MyBatis201311月迁移到Github。
         iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL MapsData Access ObjectsDAOs)。

       2) 持久化框架Hibernate 
        Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是      一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数库。      Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意      义的是,Hibernate可以在应用EJB的JavaEE架构中取代CMP,完成数据持久化的重任。但是,这个框架因为各种原因目前在国内的流行      程度下降太多,现在公司开发也越来越少使用。目前使用 Spring Data 来实现数据持久化也是一种趋势。

2. Web层MVC框架

     Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的     全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用SpringSpring MVC框架     或集成其他MVC开发框架,如Struts1(现在一般不用)Struts 2(一般老项目使用)等等。

3. 技术整合框架
   SpringJava EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。

第4节:Mybatis

4.1 概述
【重点】
		mybatis是一个优秀的基于 java 满足orm思想的的持久层框架,它内部封装了 jdbc,屏蔽了javaapi的访问细节,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

总结: 
优秀的 orm思想  jdbc封装的 持久层框架:  
    
    Mybatis是一个半自动的orm框架


【重要】
ORM思想: Object Relational Mapping 
object:对象 java 对象
Relational:关系型数据库 mysql  oracle db2 SQLServer
Mapping: java对象和关系型数据库的映射:
java     mysql 
类        表名
属性      字段
对象      记录


mybatis的特点:
(1) 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
(2) 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
(3) 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
(4)提供映射标签,支持对象与数据库的orm字段关系映射
(5) 提供xml标签,支持编写动态sql。
(6) 支持数据缓存和注解开发。
	
mybatis的官方网址: https://www.mybatis.org/
4.2 准备
4.2.1 创建数据库

   create table user(
      id int not null auto_increment,
      name varchar(30),
      gender varchar(6),
      age int,
      birthday date,
       primary key(id)
   ); 
4.2.2 创建maven Java项目
 打开Idear-->选择File-->选择new-->选择project

在这里插入图片描述

4.2.3 导入依赖
     <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
4.3 使用
4.3.1 编写实体类
package cn.offcn.entity;
import java.io.Serializable;
import java.util.Date;

public class User  implements Serializable {

     private Integer id;
     private String name;
     private String gender;
     private Integer age;
     private Date birthday;

    public User() {}

    public User(String name, String gender, Integer age, Date birthday) {
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}
4.3.2 编写持久层接口
public interface UserDao {

    /**
     * 查询所有User对象
     * @return 返回List集合
     */
    public List<User> queryAllUsers();
}

4.3.3 编写映射文件
编写:UserDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.offcn.dao.UserDao">

 <!--配置查询的sql语句-->
 <select id="queryAllUsers" resultType="cn.offcn.entity.User">
      select * from user
 </select>

</mapper>
4.3.4 编写主配置文件
编写:SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
     PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
 <!-- 配置 mybatis的环境 -->
 <environments default="development">
     <!-- 配置环境 -->
     <environment id="development">
         <!-- 配置事务的类型 -->
         <transactionManager type="JDBC"></transactionManager>
         <!-- 配置连接数据库的信息:用的是数据源【连接池】-->
         <dataSource type="POOLED">
             <property name="driver" value="com.mysql.jdbc.Driver"/>
             <property name="url" value="jdbc:mysql://localhost:3306/mybatis001"/>
             <property name="username" value="root"/>
             <property name="password" value="root"/>
         </dataSource>
     </environment>
 </environments>
 <!--  注册UserDao接品映射文件位置 -->
 <mappers>
     <mapper resource="cn/offcn/dao/UserDao.xml"/>
 </mappers>
</configuration>
4.4 注意事项
1. 接口的映射文件需要与接口文件名称对应: 
   UserMapper 接口
   UserMapper.xml  映射文件
   
2. 接口的映射文件需要与接口文件需要在同一个位置: 
   
3. 总配置文件中引入映射文件时,如果使用了mapper标签的resource属性,必须使用"/"表示分隔符。
案例: 
  <mapper resource="com/offcn/mapper/UserMapper.xml"/>
  
4. UserMapper.xml映射文件中mapper标签中namespace属性必须填写UserMapper接口的完全限定名。


5. select标签中的id属性与UserMapper接口中的方法名必须一致。


 通过快速入门示例,我们发现使用 mybatis 是非常容易的一件事情,因为只需要编写 Dao 接口并且按照mybatis 要求编写两个配置文件,就可以实现功能。远比我们之前的 jdbc 方便多了。【我们使用注解之后,将变得更为简单,只需要编写一个 mybatis 接口文件就够了】但是,这里面包含了许多细节,比如为什么会有工厂对象

第5节:入门案例

5.1 编写工具类
利用Mybatis对数据库进行操作时,都需要产生Mybatis总配置文件的输入流对象、构建SqlSessionFactoryBuilder对象、调用build方法进产生SqlSessionFactory工厂对象、调用工厂类openSession()方法创建SqlSession对象,代码冗余量大,步聚颇有繁琐,所以我们对产生SqlSession对象利用工具类进行优化。
package cn.offcn;
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.InputStream; 

public class MyBatisUtils {

    //定义静态变量sqlSessionFactory
    private static  SqlSessionFactory sqlSessionFactory;

    //创建静态块,当MyBatisUtils类被加载时,自动执行该静态块,初始化数据。
    static{
        try{
            //获取mybatis主配置文件SqlMapperConfig.xml的输入流
            InputStream inputStream= Resources.getResourceAsStream("SqlMapperConfig.xml");
            //创建SqlSessionFactoryBuilder构建者对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            //调用build方法返回SqlSessionFactory工厂对象
            sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        }catch (Exception e){
             e.printStackTrace();
            System.out.println("初始化数据失失败"+e.getMessage());
        }
    }

    //创建getSqlSessionFactory方法返回SqlSessionFactory对象
    public static SqlSessionFactory getSqlSessionFactory(){
        return sqlSessionFactory;
    }

    //创建一个SqlSession对象并返回
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }

    //关闭SqlSession方法
    public static void close(SqlSession session){
        if(session!=null) session.close();
    }
}
5.2 操作数据库
public class UserTest {

    @Test
    public void testQueryAllUsers() throws  Exception{
        //1.获取mybatis主配置文件SqlMapperConfig.xml的输入流
        InputStream inputStream=Resources.getResourceAsStream("SqlMapperConfig.xml");
        //2.创建SqlSessionFactoryBuilder构建者对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //3.调用build方法返回SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //4.调用sqlSessionFactory的openSession方法返回一个Session对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //5.调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        //6.调用代理对象的queryAllUsers方法查询所有User
        List<User> users = userDao.queryAllUsers();
        users.forEach(System.out::print);
        //7.释放资源
        sqlSession.close();
        inputStream.close();
    }
    
    @Test
    public void testQueryAllUsers2() throws  Exception{
       //调用MyBatisUtils工具创建SqlSession对象
        SqlSession sqlSession = MyBatisUtils.getSession();
        //调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        //调用代理对象的queryAllUsers方法查询所有User
        List<User> users = userDao.queryAllUsers();
        users.forEach(System.out::print);
        //释放资源
        sqlSession.close();
        inputStream.close();
    }
}
5.3 设计模式解析

(单例模式:单个实例—对象,要保证一个类在内存中只能有一个对象

适配者模式:Adapter—io转换流

装饰者模式:能够做到增强—buffered

策略模式:比较器)

5.3.1 工厂模式
    		工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

在这里插入图片描述

5.3.2 代理模式
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的三要素:
抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

代理模式的优点:
1.职责清晰
   真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
2.代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
3.高扩展性

在这里插入图片描述

5.3.3 构建者模式
    		创建者模式是java23种设计模式之一,英文叫Builder Pattern。其核心思想是将一个“复杂对象的构建算法”与它的“部件及组装方式”分离,使得构件算法和组装方式可以独立应对变化;复用同样的构建算法可以创建不同的表示,不同的构建过程可以复用相同的部件组装方式。
    
    	  在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端只负责对象的调用,从而明确了各个类的职责。虽然利用创建者模式可以创建出不同类型的产品,但是如果产品之间的差异巨大,则需要编写多个创建者类才能实现,如果这是结合工厂模式更好。
    
   创建者模式主要由五个部分构成:组装类,抽象创建者类,实现抽象创建者类的具体创建者类,抽象产品和实现抽象产品的具体产品类。

在这里插入图片描述

从图中我们可以看出,创建者模式由四部分组成。

	 抽象创建者角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体创建者角色。具体创建者必须实现这个接口的两种方法:一是建造方法,比如图中的 buildPart1 和 buildPart2 方法;另一种是结果返回方法,即图中的 getProduct 方法。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少零件,就有多少相应的建造方法。
	具体创建者角色:他们在应用程序中负责创建产品的实例。这个角色要完成的任务包括:
		1、实现抽象创建者所声明的抽象方法,给出一步一步的完成产品创建实例的操作。
		2、在创建完成后,提供产品的实例。
	导演者角色:这个类调用具体创建者角色以创建产品对象。但是导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体创建者角色。
	产品角色:产品便是建造中的复杂对象。一般说来一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以使不相关的。

第6节:原理分析

6.1 配置文件分析
1. 核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置 mybatis 的环境 -->
    <environments default="development">
        <!-- 配置的环境 -->
        <environment id="development">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源【连接池)-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis001"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--  注册UserDao接品映射文件位置 -->
    <mappers>
        <mapper resource="cn/offcn/dao/UserDao.xml"/>
    </mappers>
</configuration>

核心配置文件参数详解: 
    (1)environments标签中的id属性值必须和environments标签中的default属性一致。
    (2)事务管理器:
    第一种采用JDBC事务类型,直接使用了 JDBC的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
    第二种采用MANAGED事务类型,它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如: 
    <transactionManager type="MANAGED">
       <property name="closeConnection" value="false"/>
    </transactionManager>
    (3) 数据源(dataSource)
    dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源。大多数 MyBatis 应用程序会按示例中的例子来配置数据源。     虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
    有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")

    UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。

    POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

    JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。
    
    (4) mapper中的resource属性用于指定映射文件的位置。mapper中有多个属性可以描述映射文件,分别为:
        resource=“cn/offcn/dao/UserDao.xml” 文件在多级目录中要用分隔符“/”隔开。
        class="cn.offcn.dao.UserDao"  指定UserDao接口文件位置,但此时UserDao.xml必须和接口处在同一个包中并且文件名要         相同。
        
2. 映射文件
<mapper namespace="cn.offcn.dao.UserDao">
<!--配置查询的sql语句-->
<select id="queryAllUsers" resultType="cn.offcn.entity.User">
         select * from user
</select>
</mapper>

映射文件参数详解: 
(1) namespace必须为接口的完全限定名(即包名+类名的格式)。
(2) select标签中的id必须和接口中声明的方法同名。
(3) 如果接口中方法有返回值,resyultType必须跟方法返回值一致并采用返回值的完全限定名来表示。

6.2 底层源码分析
1.利用Resources的getResourceAsStream方法读取mybatis核心配置文件,该配置文件中注册数据源【dataSource】和映射文件的位置【mappers标签中的mapper子标签的resource属性】。
<dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis001"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
</dataSource>
<mappers>
   <mapper resource="cn/offcn/dao/UserDao.xml"/>
</mappers>
    
2.展开映射文件【UserDao.xml】中定义了查询方法、查询时所封装结果类型和所要执行的sql语句。
<select id="queryAllUsers" resultType="cn.offcn.entity.User">
         select * from user
</select>
    
3.使用构建者模式SqlSessionFactoryBuilder类的build方法创建SqlSessionFactory对象,在build方法中从字节输入流中解析数据。
  SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
  sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);

  //SqlSessionFactoryBuilder源码:
 //SqlSessionFactoryBuilder的build方法
  public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
  }
 
  public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();

            try {
                inputStream.close();
            } catch (IOException var13) {
                ;
            }

        }

        return var5;
    }

public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
}



 //XMLConfigBuilder类的构造方法
 public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
   this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment,props);
 }

 public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
        this.commonConstructor(validation, variables, entityResolver);
        this.document = this.createDocument(new InputSource(inputStream));
    }


上述代码中我们可以看到创建了一个XMLConfigBuilder对象用来解析XML,把配置文件中所有标签及标签中属性值放封装到Configuration对象中并返回DefaultSqlSessionFactory对象。

4.调用SqlSessionFactory对象的openSession方法返回一个SqlSession对象,SqlSessionFactory是一个接口,我们找到它的实现类
  DefaultSqlSessionFactory类,点击它的openSession方法,打开openSessionFromDataSource方法。
    
    //DefaultSqlSessionFactory源码:
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level,      boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            //创建一个新事务,从环境中找到数据源。
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            //创建一个DefaultSqlSession对象
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

5.调用sqlSession.getMapper(UserDao.class)方法返回一个UserDao接口的代理类对象。
    
  //DefaultSqlSession源码:
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
 }
  
  //Configuration类源码:
   public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }
 
  //MapperRegistry类源码:
   public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }
    
  //MapperProxyFactory类源码:
 public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
//通过Proxy的newProxyInstance方法创建代理对象
 protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

 //MapperProxy类源码:
//invoke回调方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //调用执行器excute方法
    return mapperMethod.execute(sqlSession, args);
  }


//MapperMethod类源码:
public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
      Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName() 
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }
  
6.3 执行原理图

在这里插入图片描述

第7节:实现CRUD操作

7.1 数据保存

(手动提交,sqlSession.commit(),需要在代码中添加

​ 自动提交,sqlSessionFactory.openSession()参数改为true)

7.1.1 定义接口方法
public class UserDao{
    /**
         新增添加用户方法
    */
    public void addUser(User user);
}
7.1.2 配置对应的sql
<insert id="addUser" parameterType="cn.offcn.entity.User">
     insert into user(name,gender,age,birthday) values (#{name},#{gender},#{age},#{birthday})
</insert>

#{}为mybatis的占位符,如果方法中传递的参数为实体类类型,#{实体类属性}
7.1.3 添加测试方法
@Test
    public void testAddUser() throws  Exception{
        //获取SqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        //创建User对象
        User user=new User("何晓","男",22,new Date());
        //调用addUser方法进行保存
        userDao.addUser(user);
        //关闭连接
        MyBatisUtils.close(session);
    }
7.2 数据更新
7.2.1 定义接口方法
   /**
     * 更新user对象
     * @param user
     */
    public void updateUser(User user);
7.2.2 配置对应的sql
 <update id="updateUser" parameterType="cn.offcn.entity.User">
         update user set name=#{name},gender=#{gender},age=#{age},birthday=#{birthday}  where id=#{id}
 </update>
7.2.3 添加测试方法
    @Test
    public void testUpdateUser() throws  Exception{
        //获取SqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        //创建User对象
        User user=new User("何晓飞","女",21,new Date());
        //指定要更新id
        user.setId(1);
        //调用updateUser方法进行修改
        userDao.updateUser(user);
        //关闭连接
        MyBatisUtils.close(session);
    }
7.3 数据删除
7.3.1 定义接口方法
   /**
     * 根据id删除指定user
     * @param id
     */
    public void deleteUser(Integer id);
7.3.2 配置对应的sql
<delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
</delete>
7.3.3 添加测试方法
    @Test
    public void testDeleteUser() throws  Exception{
        //获取SqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        //调用deleteUser方法进行删除
        userDao.deleteUser(2);
        //关闭连接
        MyBatisUtils.close(session);
    }
7.4 #{}和${}的区别
1.#{}是预编译处理,${}是字符串替换。
2.Mybatis在处理${}时,就是把${}替换成变量的值。
3.Mybatis在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋值。
4.使用#{}可以有效的防止 SQL 注入,提高系统安全性。
7.5 模糊查询
7.5.1 添加接口方法
   /**
     * 根据name模糊查询
     * @param name
     * @return
     */
    public List<User> likeSearcherUsers(String name);
7.5.2 配置对应sql
1)配置占位符方式#{}
<select id="likeSearcherUsers" parameterType="String" resultType="cn.offcn.entity.User">
        select * from user where name like #{name}
</select>
2)配置拼接字符串方式${}
<select id="likeSearcherUsers" parameterType="String" resultType="cn.offcn.entity.User">
        select * from user where name like '%${value}%'
</select>

我们在上面将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。
3)配置mysql函数方式concat
<select id="likeSearcherUsers" parameterType="String" resultType="cn.offcn.entity.User">
        select * from user where name like concat('%',#{name},'%')
</select>
7.5.3 模糊查询测试
    @Test
    public void testSearcherUser() throws  Exception{
        //获取SqlSession对象
        SqlSession session = MyBatisUtils.getSession();
        //调用SqlSession 创建 UserDao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        //调用likeSearcherUsersr方法进行模糊查询
        List<User> userList = userDao.likeSearcherUsers("张");
        //遍历输出
        userList.forEach(System.out::print);
        //关闭连接
        MyBatisUtils.close(session);
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值