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
-
创建javaBean:Employee(封装表的数据)
public class Employee { private Integer id; private String empName; private Integer gender; private String email; //set,get方法 }
-
创建一个Dao接口,用来操作数据库;
public interface EmployeeDao { //按照员工id查询员工 public Employee getEmpById(Integer id); }
-
导包
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>
-
写配置(两个,全局配置文件(指导mybatis运行的),SQL映射文件(dao接口的实现文件,描述dao中每个方法怎么工作))
- 第一个配置文件;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>
- 第二个配置文件: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>
- 我们写的dao接口的实现文件,mybatis默认是不知道的,需要在全局配置文件中注册
<!-- 引入我们自己编写的每一个接口的实现文件 --> <mappers> <!--resource:表示从类路径下找资源 --> <mapper resource="mybatis/EmployeeDao.xml"/> </mappers>
- 第一个配置文件;mybatis的全局配置文件(指导mybatis如何正确运行,比如连接向哪个数据库)
-
测试
-
根据全局配置文件先创建一个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);
-
使用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接口的一个实现描述
细节:
- 获取到的是接口的代理对象;mybatis自动创建的;
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);中employeeDao为借口的代理对象
System.out.println(employeeDao.getClass());//class com.sun.proxy.$Proxy5,employeeDao- 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 将按照下面的顺序来加载:
- 在 properties 元素体内指定的属性首先被读取。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
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类型起别名,别名不区分大小写。
-
typeAlias:为某个java类型起别名
type:指定要起别名的类型全类名;默认别名就是类名(不区分大小写);employee alias:指定新的别名
<!-- 类型别名:为常用的类型(javaBean)起别名; --> <typeAliases> <!-- typeAlias:就是为一个javaBean起别名;别名默认就是类名(不区分大小写),配置文件中就可以用别名了 --> <!-- alias="",指定一个别名 --> <typeAlias type="com.zb.bean.Employee" alias="Employee"/> </typeAliases>
-
package:为某个包下的所有类批量起别名
类很多的情况下,可以批量设置别名这个包下的每一个类 创建一个默认的别名,就是简单类名小写。
name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(默认类名就是别名))
<!-- 类型别名:为常用的类型(javaBean)起别名; --> <typeAliases> <!-- 批量起别名;name=""指定包名,默认别名就是类名 --> <package name="com.zb.bean"/> </typeAliases>
-
批量起别名的情况下,使用@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匹配规则如下:
- 如果没有配置databaseIdProvider标签,那么databaseId=null
- 如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为 null
- 如果databaseId不为null,他只会找到配置databaseId的sql语句
- MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。
2.7 mapper映射
mapper中属性介绍:
class属性:引用接口全类名,直接使用不知道绑定哪个配置文件(报错),解决办法
1、可以将xml和dao接口放在同一个文件目录下,并且xml文件名和接口名相同
2、dao接口头注解上写对应的sql语句
resource属性:在类路径下找sql映射文件
url属性:从磁盘和网络路径引用sql映射文件
-
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); }
-
使用批量注册
这种方式要求SQL映射文件名必须和接口名相同并且在同一目录下,第一种方式中通过class来配置的也是一样。
mybatis全局配置文件的总结