Mybatis学习总结

Mybatis学习总结

1. 框架概述

1.1 三层框架

  1. 三层架构包含的三层:
  • 界面层(User Interface layer)SpringMVC
  • 业务逻辑层(Business Logic Layer)Spring
  • 数据访问层(Data access layer)Mybatis
  1. 三层框架的功能:
  • 界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
  • 业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
  • 数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交
    给业务层,同时将业务层处理的数据保存到数据库.

1.2 框架是什么

  • 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板。简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。框架是安全的,可复用的,不断升级的软件。

1.3 MyBatis 框架

1.3.1概述:
  • MyBatis 框架:
    MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。
    iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)
1.3.2 Mybaits框架的功能
  1. 减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳。
  2. 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))
  3. 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象
  4. 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象
  5. 关闭资源

2. Mybatis环境

1.下载

Github地址

2.准备

2.1 创建mysql的数据库和表
2.2 创建maven工程
2.3 并且加入maven坐标

pom.xml 加入 maven 坐标:

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>

  </dependencies>
  
2.4 加入maven插件
 <build>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
2.5 编写实体类

实体类:
在这里插入图片描述

框架目录结构:
在这里插入图片描述

2.6 编写 Dao 接口 StudentDao

在这里插入图片描述

2.7 编写 Dao 接口 Mapper 映射文件 StudentDao.xml

要求:

  1. 在 dao 包中创建文件 StudentDao.xml
  2. StudentDao.xml 文件名称需要和接口 StudentDao 一样(区分大小写)
    文件内容:
<?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="org.example.dao.Studentdao">
    <select id="selectStudent" parameterType="java.lang.Integer" resultType="Stu">
        select * from student where sno = #{s}
    </select>
</mapper>
  • namespace:必须有值,自定义的唯一字符串 推荐使用:dao 接口的全限定名称
  • select 查询数据, 标签中必须是 select 语句
    id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称, 使用名称表示要执行的 sql 语句
    resultType: 查询语句的返回结果数据类型,使用全限定类名
2.8 创建 MyBatis 主配置文件
  • 项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root
  • 创建主配置文件:名称为 mybatis.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>
    <!--
    环境配置:数据库的配置信息
    -->
    <!--
    生成查询日志
-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <typeAliases>
        <typeAlias type="org.example.domain.Student" alias="Stu"></typeAlias>
        
    </typeAliases>

    <environments default="development">
        <!--
        environment:一个数据库信息的配置
        id:唯一值,自定义的,表示环境的名称
        transactionManager :mybatis的事务类型
        type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
        default:必须和某个environment的id值一样。
        告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
        -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--
            dataSource:表示数据源,连接数据库的
            type:表示数据源的类型, POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/school"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--访问数据库的密码-->
                <property name="password" value="qsc13579"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--一个mapper标签指定一个文件的位置。
        从类路径开始的路径信息。  target/classes(类路径)

        <mapper resource="org/example/dao/Studentdao.xml"/>


        第二种方式,<package>
                -->
        <package name="org.example.dao"/>
    </mappers>
</configuration>

加入日志输出的功能:
mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数

<settings>
 <setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
2.9 创建test类

在这里插入图片描述
例如:

public class test {
    /*
    测试插入
    注意:mybatis是没有自动提交事务的,需要自己提交。
    注意:mybatis是没有自动提交事务的,需要自己提交。
     */
    @Test
    public void testSelectStudent(){
        /*
         * 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
         * getMapper能获取dao接口对应的实现类对象。
         */
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        /*
             创建SqlSessionFactory对象
             会产生一个SqlSessionFactory,这个SqlSessionFactory携带着一个由Mybatis配置文件生解析而成的配置类(Configuration.java),
             这个配置类里就包含着已注册Mapper的信息。
        */
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        //在调用getMapper()方法的时候会传一个Class类进去,这时,Configuration就会根据类型来匹配Mapper,这样就返回了相应的接口。
        Student student = studentdao.selectStudent(3);
        System.out.println("Student = " + student);
    }

2.10 总结
  1. mapper文件
  • dao包中的StudentDao.xml就是mapper文件。是sql映射文件,是用来写sql语句的,Mybatis会执行这些sql语句
  • 约束文件的作用:限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求
  • mapper:是当前文件的根标签,是必须的
    namespace:命名空间,值是唯一的,可以是自定义的字符串,但是最好使用dao接口的全限定名称
    2. 对象分析:
   @Test
    public void testInsert() throws IOException {
        //1.定义mybatis主配置文件的名称,从类路径的根开始
        String config = "mybatis.xml";
        //2.读取config表示的文件
        InputStream inputStream = Resources.getResourceAsStream(config);
        //3.创建sqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //4.创建sqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //5.获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //6.指定要执行的sql语句的标识,namespace + . +标签的id
        String SqlId = "org.example.dao.Studentdao" + "." + "insertStudent";
        //7.通过SqlId执行sql语句(重要)
        Student student = new Student();
        student.setSno(7);
        student.setSname("ycx");
        student.setClassno(69);
        int number = sqlSession.insert(SqlId,student);
        //8.输出结果
        //studentList.forEach( stu -> System.out.println(stu));
        System.out.println("输出结果:" + number);
        sqlSession.commit();
        //9.关闭SqlSession对象
        sqlSession.close();
    }
}

其中

  1. Resources 类
    Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
  2. SqlSessionFactoryBuilder 类
    SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
  3. SqlSessionFactory 接口
    SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
    openSession(true):创建一个有自动提交功能的 SqlSession
    openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
    openSession():同 openSession(false)
  4. SqlSession 接口
    SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭
  5. 其中指定要执行的sql语句的标识,namespace + . +标签的id.通过SqlId的值找到接口
 String SqlId = "org.example.dao.Studentdao" + "." + "SelectStudents";

疑问: SqlId中的 “org.example.dao.Studentdao” + “.” + “SelectStudents”;对应的是mapper文件和其中的Id还是StudentDao和其中的方法

3 工具类

3.1创建 MyBatisUtil 类

  1. 路径:
    在这里插入图片描述
  2. 将可以重复利用的代码写进工具类中
public class Mybatisutils {
    private static SqlSessionFactory sqlSessionFactory = null;

    static {
        String config = "mybatis.xml";//需要和项目中文件名一样
        try {
            InputStream inputStream = Resources.getResourceAsStream(config);
            /*
             创建SqlSessionFactory对象
             会产生一个SqlSessionFactory,这个SqlSessionFactory携带着一个由Mybatis配置文件生解析而成的配置类(Configuration.java),
             这个配置类里就包含着已注册Mapper的信息。
             */
             sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SqlSession的方法
    public static SqlSession getSqlSession(){
        SqlSession sqlSession = null;
        if(sqlSessionFactory != null){
            sqlSession = sqlSessionFactory.openSession();//非自动提交事务
        }
        return sqlSession;
    }

  1. 源码分析(重点 难点)
  • 静态代码块的内容只需要调用一次类就可以一直使用并且创建
  • 创建SqlSessionFactory对象会产生一个SqlSessionFactory,这个SqlSessionFactory携带着一个由Mybatis配置文件生解析而成的配置类(Configuration.java),这个配置类里就包含着已注册Mapper的信息。
  • 我们在调用getMapper()方法的时候会传一个Class类进去,这时,Configuration就会根据类型来匹配Mapper,这样就返回了相应的接口。(这就是对应)

4 基本的 CURD步骤

select insert update delete 操作

  1. 在StudentDao接口中增加相应方法
  • public Student selectStudent(Integer sno);
    
  • public Student insertStudent(Integer sno);
    
  • public Student updateStudent(Integer sno);
    
  • public Student deleteStudent(Integer sno);
    
  1. 在StudentDao.xml中加入sql语句,以查找为例
<select id="selectStudent" parameterType="java.lang.Integer" resultType="Stu">
        select * from student where sno = #{s}
</select>
  1. 增加测试方法,以查询为例
    @Test
    public void testSelectStudent(){
        /*
         * 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
         * getMapper能获取dao接口对应的实现类对象。
         */
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        /*
             创建SqlSessionFactory对象
             会产生一个SqlSessionFactory,这个SqlSessionFactory携带着一个由Mybatis配置文件生解析而成的配置类(Configuration.java),
             这个配置类里就包含着已注册Mapper的信息。
        */
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        //在调用getMapper()方法的时候会传一个Class类进去,这时,Configuration就会根据类型来匹配Mapper,这样就返回了相应的接口。
        Student student = studentdao.selectStudent(3);
        System.out.println("Student = " + student);
    }

5. 动态代理

5.1 传统Dao开发的缺点

  • 在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。
  • 所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。
  • Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的

5.2 使用Dao代理

  1. 去掉 Dao 接口实现类
  2. 使用getMapper() 获取代理对象,并且执行操作(以查询为例)
		//工具类
        SqlSession sqlSession = Mybatisutils.getSqlSession();
       //getMapper()方法
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        Student student = studentdao.selectStudent(3);
        System.out.println("Student = " + student);
  • 执行原理在工具类中说明了
  • 创建SqlSessionFactory对象会产生一个SqlSessionFactory,这个SqlSessionFactory携带着一个由Mybatis配置文件生解析而成的配置类(Configuration.java),这个配置类里就包含着已注册Mapper的信息。
  • 我们在调用getMapper()方法的时候会传一个Class类进去,这时,Configuration就会根据类型来匹配Mapper,这样就返回了相应的接口。(这就是对应)
    更多例子:
 @Test
    public void testSelectMore(){
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        List<Student> studentList = studentdao.selectMore(3,"aaa");
        for(Student s:studentList){
            System.out.println("Student = " + s);
        }
        sqlSession.close();
    }
    @Test
    public void testSelectLike(){
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        String name = "%a%";
        List<Student> studentList =studentdao.selectLike(name);
        for(Student s:studentList){
            System.out.println("Student = " + s);
        }
        sqlSession.close();
    }
    @Test
    public void testSelectIf(){
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        Student student = new Student();
        student.setSname("aaa");
        List<Student> studentList = studentdao.selectStudentIf(student);
        for (Student s: studentList){
            System.out.println("Student:" + student);
        }
    }

5.3 使用动态代理的要求:

  1. dao接口和mapper文件放在一起,同一个目录
  2. dao接口和mapper文件名称一致
  3. mapper文件中的namespace的值是dao接口的全限定名称
  4. mapper文件中的等标签的id是接口中的方法名称

6. Mybatis参数传递

  • 从 java 代码中把参数传递到 mapper.xml 文件。

6.1 传递一个简单参数

  • 简单类型:java的基本类型数据和String都叫简单类型
  • 在mapper文件获取简单类型的一个参数的值,使用#{任意字符}

例如:

    List<Student> selectLike(String name);

对应的mapper文件中的语句:

 select * from student where sname like #{name}

6.2 多个参数-使用@Param

  • 当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),
  • mapper 文件使用#{自定义参数名}。

接口方法:

    <select id="selectLike" resultType="org.example.domain.Student">
        select * from student where sname like #{name}
    </select>

mapper文件:

    <select id="selectMore" resultType="org.example.domain.Student">
         select * from student where sname = #{myname} or sno = #{mysno}
    </select>

6.3 多个参数-使用对象

  • 使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
  • 语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
    javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }

  • 接口方法:
List<Student> selectStudentIf(Student student);
  • mapper文件
 <select id="selectStudentIf" resultType="org.example.domain.Student">
        <!--主sql-->
        select * from student where
        <if test="sname != null  ">
            sname = #{sname}
        </if>
    </select>
  • 测试方法:
@Test
    public void testSelectIf(){
        SqlSession sqlSession = Mybatisutils.getSqlSession();
        Studentdao studentdao = sqlSession.getMapper(Studentdao.class);
        Student student = new Student();
        student.setSname("aaa");
        List<Student> studentList = studentdao.selectStudentIf(student);
        for (Student s: studentList){
            System.out.println("Student:" + student);
        }
    }

注意
selectStudentIf方法中的参数是一个Student对象,mapper文件中的参数传递是sname = #{sname},所以就不能像简单传入一个参数那样在#{}里面随意的更改名称,而是要和对应的Student属性名称一样,这样才能将参数传递进去,否则会报错
Student类(部分):

public class Student {
    private int sno;
    private String sname;
    private int classno;
    }

简单来说,就是通过值传对象的时候#{}里面可以是任意的字符串,而通过对象传参的时候#{}里面需要是对象的属性名

6.4 #和¥

  • #:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法
  • $ 字符串替换,告诉 mybatis 包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。


通用方法,使用不同列作为查询条件
接口方法:

Student findByDiffField(@Param("col") String colunName,@Param("cval") Object 
value);

mapper 文件:

<select id="findByDiffField" resultType="com.bjpowernode.domain.Student">
 select * from student where ${col} = #{cval}
</select>

测试方法:

@Test
public void testFindDiffField(){
 Student student1 = studentDao.findByDiffField("id",1002);
 System.out.println("按 id 列查询:"+student1);
 Student student2 = studentDao.findByDiffField("email","zhou@126.net");
 System.out.println("按 email 列查询:"+student2);

总结

  1. #的结果: select * from student where sno = ?
    $的结果: select * from student where sno = 100
  2. #做的是JDBC中preparedStatement = connection.prepareStatement(sql);的
  3. ¥做的是字符串的替换,使用Statement对象执行sql效率低且不安全,用户可能通过表单传入影响数据库的语句。一般用来替换列名
    1.#是占位符 ¥是字符串连接方式
    2.#是preparedStatement效率高安全性高 ¥是Statement效率低,有安全隐患(sql注入的风险)
    3。#sql可以解决sql注入问题 ¥可以替换列名/表名

7. 动态SQL

7.1 动态SQL——if

  • 对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。
    语法:<if test=”条件”> sql 语句的部分 </if>
  • 接口方法:List<Student> selectStudentIf(Student student);
  • mapper文件:
<select id="selectStudentIf" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 where 1=1
 <if test="name != null and name !='' ">
 and name = #{name}
 </if>
 <if test="age > 0 ">
 and age &gt; #{age}
 </if>
</select>

7.2 动态SQL——where

 <if/>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后
的所有<if/>条件均为 false,而 where 后若又没有 1=1 子句,则 SQL 中就会只剩下一个空的 where,SQL
出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。但当数据量很大时,会
严重影响查询效率。
使用<where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加
where 子句。需要注意的是,第一个<if/>标签中的 SQL 片断,可以不包含 and。不过,写上 and 也不错,
系统会将多出的 and 去掉。但其它<if/>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student北京动力节点 www.bjpowernode.com
 <where>
 <if test="name != null and name !='' ">
 and name = #{name}
 </if>
 <if test="age > 0 ">
 and age &gt; #{age}
 </if>
 </where>
</select>

7.3 动态SQL——foreach

签用于实现对于数组与集合的遍历。对其使用,需要注意:

  • collection 表示要遍历的集合类型, list ,array 等。
  • open、close、separator 为对遍历内容的 SQL 拼接。
    语法:
<foreach collection="集合类型" open="开始的字符" close="结束的字符" 
item="集合中的成员" separator="集合成员之间的分隔符">
 #{item 的值}
</foreach>

mapper文件:

<select id="selectStudentForList" 
resultType="com.bjpowernode.domain.Student">
 select id,name,email,age from student
 <if test="list !=null and list.size > 0 ">
 where id in
 <foreach collection="list" open="(" close=")" 
item="stuid" separator=",">
 #{stuid}
 </foreach>
 </if>
</select>

7.4 数据库中列名和java类中列名不一样时

方法1:在mapper文件中使用resultMap标签来指定对应的列名和属性名

<resultMap>
	<id column ="id" property = "stuId" >(主键用ID)
	<result column ="name" property = "stuname" >
	<result column ="classno" property = "stuclassno" >

 			列名		属性名
	</resultMap>

方法2:在select中使用别名

select sname as stuname from student	
					列名		属性名

8. Mybatis配置文件

8.1 主配置文件: mybatis.xml

  1. 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">

  1. 根元素,<configuration>包含:
  • 定义别名
  • 数据源
  • mapper文件
  1. dataSource
    Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis.xml配置文件中,通过来实现 Mybatis 中连接池的配置。
  • dataSource分为三类:
    • UNPOOLED : 不使用连接池的数据源
    • POOLED :使用连接池的数据源
    • JNDI :使用 JNDI 实现的数据源
      dataSource的配置:
 <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/school"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--访问数据库的密码-->
                <property name="password" value="qsc13579"/>
            </dataSource>

8.2 mapper文件:

  • 一个mapper标签指定一个文件的位置。从类路径开始的路径信息。 target/classes(类路径)
    1)使用相对于类路径的资源,从 classpath 路径查找文件
    例如:
    2)指定包下的所有 Dao 接口
    如:
    注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中

8.3 事务

  • 默认是需要手动提交的
  • 设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
    有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。
    session = factory.openSession(true);
    再执行 insert 操作,无需执行 session.commit(),事务是自动提交的

8.4 使用数据库属性配置文件

8.4.1 在 resources 目录创建 jdbc.properties 文件

在这里插入图片描述

8.4.2 使用 properties 标签

在主配置文件中加入
在这里插入图片描述

8.4.3 使用 key 指定值

在这里插入图片描述

8.5 类型别名

  1. 第一种方式:在mybatis主配置文件中定义,使定义别名。typeAlias中type:自定义类型的全限定名称,alias:别名
<typeAliases>
    <typeAlias type="org.example.domain.Student" alias="Stu"></typeAlias>
</typeAliases>
  1. 第二种方式: name是包名,这个包中的所有类,类名就是别名 (推荐代码量多类名多的时候使用
    批量定义别名,扫描整个包下的类,别名为类名(首字母大写或小写都可以)
<package name="com.bjpowernode.domain"/>
<package name="...其他包"/>

9 细节以及源码分析

9.1 SqlSessionFactoryBuilder

我们以xml的形式创建了一个配置了数据库的基本信息,Mybatis的解析程序会将这个 mybatis-config.xml文件配置的信息解析到 Configuration类对象里面,然后利用SqlSessionFactoryBulider读取这个对象创建SqlSessionFactory

  1. 我们的xml配置文件 mybatis-config.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>
    <!--
    环境配置:数据库的配置信息
    -->
    <!--
    生成查询日志
    -->

<!--    <settings>-->
<!--        <setting name="logImpl" value="STDOUT_LOGGING"/>-->

<!--    </settings>-->
    <typeAliases>
        <typeAlias type="org.example.domain.Student" alias="Stu"></typeAlias>
    </typeAliases>
    <environments default="development">
        <!--
        environment:一个数据库信息的配置
        id:唯一值,自定义的,表示环境的名称
        transactionManager :mybatis的事务类型
        type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
        default:必须和某个environment的id值一样。
        告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
        -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--
            dataSource:表示数据源,连接数据库的
            type:表示数据源的类型, POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--访问数据库的密码-->
                <property name="password" value="qsc13579"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--一个mapper标签指定一个文件的位置。
        从类路径开始的路径信息。  target/classes(类路径)
        -->
        <mapper resource="org/example/dao/Studentdao.xml"/>
        <mapper resource="org/example/dao/StudentClassdao.xml"/>
    </mappers>
</configuration>

2.通过Resource中的getResourceAsReader方法底层使用IO流方式兑取配置文件
在这里插入图片描述
3.通过SqlSessionFactoryBuilder获取SqlSessionFactory对象。
(build方法)

sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

这里插一下 SqlSessionFactoryBuilder 的源码,可以看到build有很多重载的build方法,参数不全的build都会直接return调用那个参数全的build,也就是说参数全的那个build是入口,注意看最后一个build方法的参数是一个Configuration 类型的参数

public class SqlSessionFactoryBuilder {
//参数不完整的build方法
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
//参数不完整的build方法
  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }
//参数不完整的build方法
  public SqlSessionFactory build(Reader reader, Properties properties) {
    return build(reader, null, properties);
  }
//参数完整的build方法
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
//参数不完整的build方法
  public SqlSessionFactory build(InputStream inputStream) {
    return build(inputStream, null, null);
  }
//参数不完整的build方法
  public SqlSessionFactory build(InputStream inputStream, String environment) {
    return build(inputStream, environment, null);
  }
//参数不完整的build方法
  public SqlSessionFactory build(InputStream inputStream, Properties properties) {
    return build(inputStream, null, properties);
  }

  public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

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

}

4.build 方法源码:

//SqlSessionFactoryBuilder.class
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
       //4.1进入解析XMLConfigBuilder的有参构造
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      //4.2 进入parse方法 
      //4.3进入build方法中
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

4.1 进入解析XMLConfigBuilder的有参构造
这一步的作用是new出了一个XMLConfigBuilder 的对象 parser

 private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;//设置parsed为false,目的为了只让Xml文件只加载一次
    this.environment = environment;
    this.parser = parser;
  }

4.2 根据上一步new出的对象parser ,调用其parse()方法,在parse()中,调用了parseConfiguration 方法,之后返回一个Configuration 类型的对象

  public Configuration parse() {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }

parseConfiguration:解析xml文件节点信息,将信息封装到Configuration对象中

//解析xml文件节点信息,将信息封装到Configuration对象中
private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectionFactoryElement(root.evalNode("reflectionFactory"));
      settingsElement(root.evalNode("settings"));
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

4.3 进入build方法中,也就是把上一步的Configuration 对象带入,调用的就是


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

这个build方法了,返回了一个DefaultSqlSessionFactory,将其返回给SqlSessionFactory就完成了流程。
补充:
SqlSessionFactory在Mybatis中有两个实现类,分别是DefaultSqlSessionFactorySqlSessionManager这里我们使用的是DefaultSqlSessionFactory
流程图
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值