MyBatis的原理配置使用高级映射和代理机制和缓存机制

Posted 在炮火中前进

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis的原理配置使用高级映射和代理机制和缓存机制相关的知识,希望对你有一定的参考价值。

文章目录

一、MyBatis介绍

  1. 官网中给出的解释是:
    MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
  2. MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  3. MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

二、MyBatis原理

  1. 如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:
<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
  1. 从XML文件中构建SqlSessionFactory。每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
  2. 从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  1. 从 SqlSessionFactory 中获取 SqlSession;
try (SqlSession session = sqlSessionFactory.openSession()) 
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);

使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
例如:

try (SqlSession session = sqlSessionFactory.openSession()) 
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);

三、MyBatis的配置

  1. 除了给定MyBatis依赖之外,还要连接数据库,那就需要再导入数据库驱动:
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>

1、配置全局配置文件

  1. 首先在创建的项目中找到resource;

    如果没有那就创建一个新建一个包,包名设置为resource;然后鼠标右键点击依次点击如下图,将这个包设置为Resource Root;
  2. 在这个resource下新建一个xml类型的文件,

    打开文件在MyBatis官网中找到配置信息,然后再根据需要做出一点修改;
<?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>
    <!--配置数据源-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>
  1. 在main目录的java下创建POJO类,即创建一个包,命名为POJO,然后新建一个类为:Student.java,与数据库中的Student表数据映射为student对象,给定数据库中的属性名,注意属性名要与数据库中的属性要一一对应;
public class Student 
    private Integer SID;//学生ID
    private String Sname;//学生姓名
    private String Ssex;//学生性别
    private Integer Sage;//学生年龄
   //省略getter和setter方法

  1. 然后再POJO包同一位置上新建一个mapper包,这个包用来存放我们创建的Mapper接口的文件;
public interface StudentMapper 
    Student selectStudentById(Integer id);//通过学生的ID来进行检索

  1. 配置Mapper的xml文件,即在resource资源的目录下创建一个mapper包,在这个包下来存放我们创建的Mapper的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">
<!--根标签  namespace命令空间:给定接口文件的全路径-->
<mapper namespace="com.example.springBootDemo.TestMabits.mapper.StudentMapper">

<!--ResultType无法完成某些字段映射时,需要resultMap进行显性映射
        resultMap标签主要用来显性指定返回映射关系
        id:必填,表示去名称,可以随便取
        type:必填,指定显性映射的java类的全限定名
        id标签:指定主键映射关系,ID标签一般使用一次指定主键即可
        result:指定非主属性映射关系,可以多次使用
        property:指定java类中属性名(必填
        column:指定数据库中的属性名称(必填
        jdbcType:指定数据库中当前属性类型(选填
        typeHandler:如果是有自定义类型处理器需要在这里指定自定义类型处理器的

-->
    <resultMap id="studentMap" type="student">
        <id property="SID" column="SID"/>
        <result property="Sname" column="Sname"/>
        <result property="Ssex" column="Ssex"/>
        <result property="Sage" column="Sage"/>
    </resultMap>

    <!--
    select标签是查询操作标签
    id属性:(必填的)Statement的id,必填的,和接口文件中的方法名保持一致
    parameterType:表述输入参数的类型(String,pojo,Integer)
    resultType:(必填)表示输出参数的类型(String,pojo,Integer)还可以返回resultMap类型(返回的是hashmap)两种类型二选一
    #XXX:表示占位符  XXX:接口方法中的参数名称
    -->


    <select id="selectStudentById" parameterType="int" resultType="com.example.springBootDemo.TestMabits.pojo.StudentA">
        select * from Student where SID =#sid
    </select>

<!--    id:在空间命名具有唯一性,和方法名保持一致
        parameterType:指定入参的类型,可以是类的全限定名或者

-->
    <insert id="insertStudent" flushCache="true" parameterType="student"/>

    <select id="selectAllStudents" resultType="com.example.springBootDemo.TestMabits.pojo.Student">
        select * from Student;
    </select>

</mapper>
  1. 将mapper.xml文件的映射路径配置到全局配置文件中;
 <!--映射文件-->
    <mappers>
        <!--resource属性,指定mapper.xml文件的路径-->
        <mapper resource="mapper/StudentMapper.xml"/>
    </mappers>
  1. 然后再新建一个测试类,用来通过java代码执行查询操作;
  package com.example.springBootDemo.TestMabits;
import com.example.springBootDemo.TestMabits.mapper.StudentMapper;
import com.example.springBootDemo.TestMabits.pojo.Student;
import org.apache.ibatis.annotations.Delete;
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;
import java.util.List;
import java.util.Properties;
public class MybatisDemo 
    public static void main(String[] args) throws IOException 
        //1、创建SQLSessionFactory对象

        //1.读取全局配置文件
        String path="mybatis_config.xml";

        //通过Resource获取文件流
        InputStream resourceAsStream = Resources.getResourceAsStream(path);

        //创建会话工厂,通过SQLSessionFactoryBUilder来创建
        Properties properties = new Properties();
        properties.setProperty("username","root");
        properties.setProperty("password","123456");


        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream,properties);

        //        创建会话,会话工厂是用来读取全局配置文件,通过builder类来创建
//        通过读取配置文件来创建实例,一般配置文件读取依次即可
//        对数据库CRUD操作
//        SQLSession是线程不安全的,将其设置为方法的局部变量
//        以及缓存是基于SQLSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
//        通过代理模式创建代理类
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
//        Student student = studentMapper.selectStudentById(4);
//        System.out.println(student);
        List<Student> students=studentMapper.selectAllStudents();
        for (Student s:students) 
            System.out.println(s);

        

    


运行结果:

  1. MyBatis的操作流程
    1. 配置MyBatis的全局配置文件(数据源,mapper映射)
    2. 创建SQLSessionFactory对象;
    3. 通过SQLSessionFactory创建SQLSession对象;
    4. 通过SQLSession来操作数据库CRUD操作;
    5. 关闭SQLSession资源;

2、XML配置

  1. MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

1、Properties

  1. 这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
    <properties  resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </properties>
  1. 在其中对应的属性可以用来提花为需要的动态配置的属性值,比如:
 <dataSource type="POOLED">
         <property name="driver" value="com.mysql.jdbc.Driver"/>
         <property name="url" value="jdbc:mysql://localhost:3306/test"/>
         <property name="username" value="$username"/>
         <property name="password" value="$password"/>
 </dataSource>
  1. 这个例子中的 username 和 password 将会由 properties 元素中设置的相应值来替换
    如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
  • 首先读取在 properties 元素体内指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
    因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

2、setting

  1. 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。




3、typeAliases(类型别名)

  1. 类型别名是Java类型的短名称,和XML配置有关,存在是在于用来减少类全限定名的冗余,在mapper.xml中,会有很多的Statement,Statement需要的parameterType指定入参类型,需要resultType执行输出参数类型,如果是指定类型需要书写全限定名,不方便开发,可以通过类型别名,较少代码冗余
    <!--类型别名-->
    <typeAliases>
        <!--单个类型定义别名: type:pojo全路径  alias:别名的名称-->
        <typeAlias type="com.tulun.Mybatis.pojo.Student" alias="student"/>
        <!--批量的别名定义 package:指定包名,将包下的所有pojo类定义别名,别名是类型(首字母大写或者小写都可以)-->
        <package name="com.tulun.Mybatis.pojo"/>
    </typeAliases>

4、Mappers

  1. 映射器
    <mappers>
        <!--单个文件映射:resource属性一次加载一个文件,
        指定xml文件位置,通过namespace来查找mapper接口文件-->
        <mapper resource="mapper/StudentMapper.xml"/>

        <!--class方式映射:通过mapper接口映射单个文件,
        遵循规则:mapper.java和mapper.xml放在同一个目录下,且命名相同-->
        <!--<mapper class="com.tulun.Mybatis.mapper.StudentMapper"/>-->

        <!--批量mapper的接口扫描规则
         遵循规则:mapper.java和mapper.xml放在同一个目录下,且命名相同-->
        <!--<package name="com.tulun.Mybatis.mapper"/>-->
    </mappers>

  1. MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

3、标签详解

1、select标签

    <!--
    查询操作是select标签
    id属性:(必填的)Statement的id是唯一标识,和接口文件中的方法名保持一致
    parameterType:表示输入参数的类型(Pojo,Integer,String...)入参类型也可以是parameterMap(hashMap)两种类型二选1
    resultType(必填):表示输出参数的类型(Pojo,Integer,String) 返回类型也可以是resultMap(hashMap)两种类型二选1
    #XXX:表示占位符  XXX:接口方法中的参数名称
    -->
    <select id="selectStudentById"  parameterType="int" rresultType="student">
        select * from student where SID =#sid
    </select>

2、insert标签

<!--
    插入操作是insert标签
    id属性:(必填的)Statement的id是唯一标识,和接口文件中的方法名保持一致
    parameterType:(可选操作)表示输入参数的类型(Pojo,Integer,String...)入参类型也可以是parameterMap(hashMap)两种类型二选1
    useGeneratedKeys:开启主键回写  
    keyColumn:指定数据库的主键
    keyProperty:主键对应的pojo类属性名
    -->
    <insert id="testInsert" parameterMap="" useGeneratedKeys="true" keyColumn="" keyProperty=""

3、update标签

    <!--
    变更操作是update标签
    id属性:(必填的)Statement的id是唯一标识,和接口文件中的方法名保持一致
    parameterType:(可选操作)表示输入参数的类型(Pojo,Integer,String...)入参类型也可以是parameterMap(hashMap)两种类型二选1
    useGeneratedKeys:开启主键回写
    keyColumn:指定数据库的主键
    keyProperty:主键对应的pojo类属性名
    -->
    <update id="testUpdate" >
        
    </update>

4、delete标签

    <!--
    删除操作是delete标签
    id属性:(必填的)Statement的id是唯一标识,和接口文件中的方法名保持一致
    parameterType:(可选操作)表示输入参数的类型(Pojo,Integer,String...)入参类型也可以是parameterMap(hashMap)两种类型二选1

    -->
    <delete id="testdelete">
        
    </delete> 

四、MyBatis的使用

1、MyBatis中接口绑定的两种实现方式

  1. 通过注解绑定:就是在接口的方法上加上@Select、@update等注解,里面包含SQL语句进行绑定;
  2. 通过XML里面写SQL进行绑定,需要指定xml映射文件里的namespace必须为接口的全路径
    语句比较简单时,使用注解绑定,当SQL语句比较复杂是,用xml绑定,一般使用xml比较多;

2、XML方式(使用步骤)

MyBatis的强大之处在于自定义SQL语句,映射器的xml文件方式相比JDBC简单,节省代码量

1、创建Mapper.java接口文件

public interface StudentMapper 
    Student selectStudentById(Integer sid);

2、创建Mapper.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"&

Mybatis常用类原理

 

  • 功能:将java对象映射城sql语句,将结果集转化成java对象。将容易变化的放在配置文件中,不变的通过Mybatis管理。

  • 完成:1.根据JDBC规范建立数据库的连接;

    2.通过反射打通java对象与数据库参数转化的关系。

  • 原理:动态代理和反射机制。

动态代理中用到JDK动态代理和CGLIB代理。

这两者的区别是,JDK动态代理是接口的,CGLIB代理是对于类的。

Mybatis中这两种代理都用到过,Mapper中用到的是JDK动态代理在延迟加载的时候用到CGLIB代理

1.读取配置到Configuration对象,并使用相应对象去创建SqlSessionFactory;

2.通过SqlSessionFactory拿到SqlSession进行增删改查方法。

 

 

SqlSessionDaoSupport:

1、SqlSessionDaoSupport 是 一 个 抽象 的支 持 类, 用来 为你 提供 SqlSession 。 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
@Autowired
@Override
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    // TODO Auto-generated method stub
    super.setSqlSessionFactory(sqlSessionFactory);
}
 
//spring配置
    <!-- 配置sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis.cfg.xml"></property>
    </bean>
<wiz_tmp_tag class="wiz-block-scroll">
 

 

 

2、调 用 getSqlSession()方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法

3、持久层未继承SqlSessionDaoSupport,需要注入类

1
2
@Autowired
private SqlSessionTemplate sqlSession;

且配置

1
2
3
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

 

涉及涉及模式:

Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;

工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;

单例模式,例如ErrorContext和LogFactory;

代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;

组合模式,例如SqlNode和各个子类ChooseSqlNode等;

模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;

适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;

装饰者模式,例如Cache包中的cache.decorators子包中等各个装饰者的实现;

迭代器模式,例如迭代器模式PropertyTokenizer;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

以上是关于MyBatis的原理配置使用高级映射和代理机制和缓存机制的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis Mapper接口是如何找到实现类的-源码分析

Mybatis原理图

JavaLearn#(28)MyBatis高级:无级联查询级联查询(立即加载结果映射延迟加载)多表连接查询MyBatis注解MyBatis运行原理面试题

Mybatis学习---MyBatis知识原始Dao开发和mapper代理开发

MyBatis的原理及应用

MyBaits基本概念和原理