Mybatis学习总结——全局配置文件SQL映射文件动态SQL缓存机制

Posted AC_Jobim

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习总结——全局配置文件SQL映射文件动态SQL缓存机制相关的知识,希望对你有一定的参考价值。

一、MyBatis简介

MyBatis简介

  • MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录.

MyBatis的历史

  • 原是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation 迁移到了Google Code,随着开发团队转投Google Code旗下, iBatis3.x正式更名为MyBatis ,代码于2013年11月迁移到Github(下载地址见后)。
  • iBatis一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。 iBatis提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

为什么要使用MyBatis?

  • MyBatis是一个半自动化的持久化层框架。
  • JDBC
    • SQL夹在Java代码块里,耦合度高导致硬编码内伤
    • 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
  • Hibernate和JPA
    • 长难复杂SQL,对于Hibernate而言处理也不容易
    • 内部自动生产的SQL,不容易做特殊优化。
    • 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。导致数据库性能下降。
  • 对开发人员而言,核心sql还是需要自己优化
  • sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。

MyBatis官网:https://github.com/mybatis/mybatis-3/

二、MyBatis——HelloWorld

  1. 创建javaBean:Employee(封装表的数据)

    public class Employee {
    	private Integer id;
    	private String empName;
    	private Integer gender;
    	private String email;
    	//set,get方法
    }
    
  2. 创建一个Dao接口,用来操作数据库;

    public interface EmployeeDao {
    	//按照员工id查询员工
    	public Employee getEmpById(Integer id);
    }
    
  3. 导包

     mysql-connector-java-5.1.37-bin.jar
     mybatis-3.4.1.jar
     log4j-1.2.17.jar
     //建议导入日志包;这样的话在mybatis关键的环节就会有日志打印;
     //log4j(日志框架);依赖类路径下一个log4j.xml配置文件;
    

    log4j.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
     
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
     
     <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
       <param name="Encoding" value="UTF-8" />
       <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \\n" />
       </layout>
     </appender>
     <logger name="java.sql">
       <level value="debug" />
     </logger>
     <logger name="org.apache.ibatis">
       <level value="info" />
     </logger>
     <root>
       <level value="debug" />
       <appender-ref ref="STDOUT" />
     </root>
    </log4j:configuration>
    
  4. 写配置(两个,全局配置文件(指导mybatis运行的),SQL映射文件(dao接口的实现文件,描述dao中每个方法怎么工作))

    1. 第一个配置文件;mybatis的全局配置文件(指导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/mybatis_01"/>
              <property name="username" value="root"/>
              <property name="password" value="root"/>
            </dataSource>
          </environment>
        </environments>
        
        <!-- 引入我们自己编写的每一个接口的实现文件 -->
        <mappers>
        	<!--resource:表示从类路径下找资源  -->
          <mapper resource="mybatis/EmployeeDao.xml"/>
        </mappers>
      </configuration>
      
    2. 第二个配置文件:SQL映射文件(编写每一个方法都如何向数据库发送sql语句,如何执行。。。。相当于接口的实现类)
      <?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:名称空间;写接口的全类名,相当于告诉MyBatis这个配置文件是实现哪个接口的;  -->
      <mapper namespace="com.zb.dao.EmployeeDao">
      <!-- public Employee getEmpById(Integer id); -->
      <!-- 
       select:用来定义一个查询操作   
       id:方法名,相当于这个配置是对于某个方法的实现 
       resultType:指定方法运行后的返回值类型;(查询操作必须指定的)
       #{属性名}:代表取出传递过来的某个参数的值
       -->
        <select id="getEmpById" resultType="com.zb.bean.Employee">
          select * from t_employee where id = #{id}
        </select>
      </mapper>
      
    3. 我们写的dao接口的实现文件,mybatis默认是不知道的,需要在全局配置文件中注册
      <!-- 引入我们自己编写的每一个接口的实现文件 -->
      <mappers>
      	<!--resource:表示从类路径下找资源  -->
      	<mapper resource="mybatis/EmployeeDao.xml"/>
      </mappers>
      
  5. 测试

    1. 根据全局配置文件先创建一个SqlSessionFactory

      //1、根据全局配置文件创建一个SqlSessionFactory
      //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象
      //SqlSession:sql会话(代表和数据库的一次会话)
      String resource = "mybatis-config.xml";
      InputStream inputStream = Resources.getResourceAsStream(resource);//org.apache.ibatis.io.Resources;
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      
    2. 使用SqlSessionFactory获取sqlSession对象。一个SqlSession对象代表和数据库的一次会话。

      //2、获取和数据库的一次会话:等同于getConnection();
      SqlSession openSession = sqlSessionFactory.openSession();
      try {
      	//3、使用SqlSession操作数据库,获取dao接口的实现
      	EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
      	//4、调用查询方法
      	Employee employee = employeeDao.getEmpById(1);
      	System.out.println(employee);
      } finally{
      	openSession.close();
      }
      

两个文件:

  • 全局配置文件:mybatis-config.xml;指导mybatis正确运行的一些全局设置;
  • 映射文件:EmployeeDao.xml;相当于是对Dao接口的一个实现描述

细节:

  1. 获取到的是接口的代理对象;mybatis自动创建的;
    EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);中employeeDao为借口的代理对象
    System.out.println(employeeDao.getClass());//class com.sun.proxy.$Proxy5,employeeDao
  2. SqlSessionFactory和SqlSession;
    • SqlSessionFactory创建SqlSession对象,Factory只new一次就行
    • SqlSession:相当于connection和数据库进行交互的,和数据库的一次会话,就应该创建一个新的sqlSession;

三、全局配置文件

官方文档:https://mybatis.org/mybatis-3/zh/configuration.html

MyBatis 的配置文件包含了影响 MyBatis 行为甚深的 设置(settings)和属性(properties)信息。文档的 顶层结构如下:
在这里插入图片描述

该顺序也为标签书写的前后顺序,可以没有某个标签,但顺序不能乱(乱了会报错)。

2.1 properties属性

mybatis可以使用properties来引入外部properties配置文件的内容;

  • resource:引入类路径下的资源
  • url:引入网络路径或者磁盘路径下的资源
<!-- 
	resource:从类路径下开始引用
	url:引用磁盘路径或者网络路径的资源
 -->
<properties resource="dbconfig.properties">

注: dbconfig.properties 在项目的根目录下,如果是 maven 项目 dbconfig.properties 在resources 目录下。

如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

  1. 在 properties 元素体内指定的属性首先被读取。
  2. 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
  3. 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。

dbconfig.properties

username=root
password=root
jdbcurl=jdbc:mysql://localhost:3306/mybatis_01
driverclass=com.mysql.jdbc.Driver

读取:

<configuration>
	<!-- properties和Spring的context:property-placeholder类似 ,都是引用外部配置文件 -->
	<!-- 
		resource:从类路径下开始引用 
		url:引用磁盘路径或者网络路径的资源 
	-->
	<properties resource="dbconfig.properties">

	</properties>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<!-- ${}取出配置文件中的值 -->
				<property name="driver" value="${driverclass}" />
				<property name="url" value="${jdbcurl}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="mybatis/EmployeeDao.xml" />
	</mappers>
</configuration>

2.2 settings设置

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为在这里插入图片描述

settings包含很多重要的设置项

  • setting:用来设置每一个设置项
  • name:设置项名
  • value:设置项取值

开启驼峰命令规则映射为例:
在这里插入图片描述
如果不开启驼峰命令这个设置,select * from t_employee where id = #{id} 是无法映射 loginAccount的,需要给查询出来的 login_account取别名为loginAccount,select id,empName,email,gender,login_account loginAccount from t_employee where id = #{id} 。

mybatis-config.xml中开启驼峰命名规则映射

<settings>
	<!-- name:配置项的key,value:配置项的值 -->
	<!-- 此时会自动将数据库中login_account字段,自动封装到bean的loginAccount变量中 -->
	<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

此时就可以通过select * from t_employee where id = #{id} 是映射 loginAccount了。

注意:mybatis在封装javabean是不区分bean属性的大小写

2.3 typeAliases别名处理器

类型别名是为 Java 类型设置一个短的名字,可以方便我们 引用某个类。

typeAliases别名处理器:可以为我们的java类型起别名,别名不区分大小写。

  1. typeAlias:为某个java类型起别名

     type:指定要起别名的类型全类名;默认别名就是类名(不区分大小写);employee
     alias:指定新的别名
    
    <!-- 类型别名:为常用的类型(javaBean)起别名; -->
    <typeAliases>
    	<!-- typeAlias:就是为一个javaBean起别名;别名默认就是类名(不区分大小写),配置文件中就可以用别名了 -->
    	<!-- alias="",指定一个别名 -->
    	<typeAlias type="com.zb.bean.Employee" alias="Employee"/>
    </typeAliases>
    
  2. package:为某个包下的所有类批量起别名

    类很多的情况下,可以批量设置别名这个包下的每一个类 创建一个默认的别名,就是简单类名小写。

    name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(默认类名就是别名))

    <!-- 类型别名:为常用的类型(javaBean)起别名; -->
    <typeAliases>
    	<!-- 批量起别名;name=""指定包名,默认别名就是类名 -->
    	<package name="com.zb.bean"/>
    </typeAliases>
    
  3. 批量起别名的情况下,使用@Alias注解为某个类型指定新的别名
    benn对象

    @Alias("emp")
    public class Employee {}
    

注意:MyBatis已经为许多常见的 Java 类型内建 了相应的类型别名。它们都是大小写不敏感的,我们在起 别名的时候千万不要占用已有的别名。
在这里插入图片描述

2.4 plugins插件

插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。(后面介绍)

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

2.5 environments环境

MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置,每种环境使用一个environment标签进行配置并指定唯一标识符,可以通过environments标签中的default属性指定 一个环境的标识符来快速的切换环境

<!-- environments配置环境们
	environment:配置一个具体的环境。每个环境都需要一个事务管理器和一个数据源
	transactionManager:事务管理器
	dataSource:数据源
	以后数据源和事务管理器都使用Spring配置
 -->
<!-- default="development":默认使用哪个环境 -->
<environments default="development">
	<!-- id="testEnv"是当前环境的唯一标识 -->
	<environment id="testEnv"><!-- 用户测试的环境 -->
		<transactionManager type="JDBC" />
		<dataSource type="POOLED">
			<!-- ${}取出配置文件中的值 -->
			<property name="driver" value="${driverclass}" />
			<property name="url" value="jdbc:mysql://localhost:3306/mybatis_teset" />
			<property name="username" value="${username}" />
			<property name="password" value="${password}" />
		</dataSource>
	</environment>
	
	<environment id="development"><!-- 用于开发的环境 -->
		<transactionManager type="JDBC" />
		<dataSource type="POOLED">
			<!-- ${}取出配置文件中的值 -->
			<property name="driver" value="${driverclass}" />
			<property name="url" value="${jdbcurl}" />
			<property name="username" value="${username}" />
			<property name="password" value="${password}" />
		</dataSource>
	</environment>
</environments>

2.6 databaseIdProvider

MyBatis 可以根据不同的数据库厂商执行不同的语句

  • Type:DB_VENDOR 使用MyBatis提供的VendorDatabaseIdProvider解析数据库 厂商标识。也可以实现DatabaseIdProvider接口来自定义。
  • Property-name:数据库厂商标识
  • Property-value:为标识起一个别名,方便SQL语句使用 databaseId属性引用

mybatis_config.xml

<!-- mybatis用来考虑数据库移植性的 -->
<databaseIdProvider type="DB_VENDOR">
	<!-- 
		name属性:数据库厂商标识  
		value属性:给数据库厂商标识起别名
		MYSQL、Oracle、SQL Server;
	 -->
	<property name="MySQL" value="mysql"/>
	<property name="SQL Server" value="sqlserver"/>
	<property name="Oracle" value="oracle"/>
</databaseIdProvider>

EmployeeDao.xml,根据不同环境执行不同的 sql 语句:

<!-- 默认查询不区分环境,如果能精确匹配就精确,不能就用模糊的 -->
<select id="getEmpById" resultType="com.zb.bean.Employee">
	select * from t_employee where id = #{id}
</select>

<!-- 表示该查询在MySQL环境下执行 -->
<select id="getEmpById" resultType="com.zb.bean.Employee" databaseId="mysql">
	select * from t_employee where id = #{id}
</select>
<!-- 表示该查询在Oracle环境下执行 -->
<select id="getEmpById" resultType="com.zb.bean.Employee" databaseId="oracle">
	select * from t_employee where id = #{id}
</select>

MyBatis匹配规则如下:

  1. 如果没有配置databaseIdProvider标签,那么databaseId=null
  2. 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为 null
  3. 如果databaseId不为null,他只会找到配置databaseId的sql语句
  4. MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。

2.7 mapper映射

mapper中属性介绍:

class属性:引用接口全类名,直接使用不知道绑定哪个配置文件(报错),解决办法
	1、可以将xml和dao接口放在同一个文件目录下,并且xml文件名和接口名相同
	2、dao接口头注解上写对应的sql语句
resource属性:在类路径下找sql映射文件
url属性:从磁盘和网络路径引用sql映射文件

  1. mapper中使用class绑定配置文件(dao接口头注解上写对应的sql语句)

    PersonDaoAnnotation:在dao接口头注解上写对应的sql语句

    public interface PersonDaoAnnotation{
    
        @Select("select * from t_employee where id = #{id}")
        public Employee getEmpById(Integer id);
    
        @Update("update t_employee set empname = #{empName},gender = #{gender},email = #{email} where id = #{id}\\n")
        public int updateEmp(Employee employee);
    
        @Delete("delete from t_employee where id = #{id}")
        public boolean deleteEmpById(Integer id);
    
        @Insert("insert into t_employee(empname,gender,email)" +
                "values(#{empName},#{gender},#{email}))")
        public int insertEmp(Employee employee);
    
    }
    
  2. 使用批量注册

    这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下,第一种方式中通过class来配置的也是一样。
    mybatis全局配置文件的总结

    Mybatis 不同使用方式

    mybatis总结回顾

    学习MyBatis必知必会~注解开发动态SQL

    02-Mybatis工作原理

    mybatis编写流程