1 前世今生
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)
当前,最新版本是MyBatis 3.5.2 ,其发布时间是2019年7月15日。
2.1 Mybatis的前身是apache开源组织开发的一款叫做ibatis的框架
2.2 在2010年迁移到goole code, 并更名为Mybatis
2.3 在2013年迁移到了github上, 目前也在github托管
MyBatis 是一款优秀的持久层(关于分层看前几篇博客)框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
1.2背景介绍
MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。
用xml文件构建SqlSessionFactory实例是非常简单的事情。推荐在这个配置中使用类路径资源(classpath resource),但你可以使用任何Reader实例,包括用文件路径或file://开头的url创建的实例。MyBatis有一个实用类----Resources,它有很多方法,可以方便地从类路径及其它位置加载资源。
1.3特点
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
提供映射标签,支持对象与数据库的orm字段关系映射
提供对象关系映射标签,支持对象关系组建维护
提供xml标签,支持编写动态sql。
1.4总体流程
(1)加载配置并初始化
触发条件:加载配置文件
处理过程:将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)接收调用请求
触发条件:调用Mybatis提供的API
传入参数:为SQL的ID和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。
(3)处理操作请求
触发条件:API接口层传递请求过来
传入参数:为SQL的ID和传入参数对象
处理过程:
(A)根据SQL的ID查找对应的MappedStatement对象。
(B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
©获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
(D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
(E)释放连接资源。
(4)返回处理结果将最终的处理结果返回。
1.4 功能
我们把Mybatis的功能架构分为三层:
(1)API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
(2)数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
(3)基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
1.5框架架构
框架架构讲解:
(1)加载配置:配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个
mybatis结构
mybatis结构
个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
(2)SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
(3)SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
(4)结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
1.6动态SQL
MyBatis 最强大的特性之一就是它的动态语句功能。如果您以前有使用JDBC或者类似框架的经历,您就会明白把SQL语句条件连接在一起是多么的痛苦,要确保不能忘记空格或者不要在columns列后面省略一个逗号等。动态语句能够完全解决掉这些痛苦。
尽管与动态SQL一起工作不是在开一个party,但是MyBatis确实能通过在任何映射SQL语句中使用强大的动态SQL来改进这些状况。动态SQL元素对于任何使用过JSTL或者类似于XML之类的文本处理器的人来说,都是非常熟悉的。在上一版本中,需要了解和学习非常多的元素,但在MyBatis 3 中有了许多的改进,现在只剩下差不多二分之一的元素。MyBatis使用了基于强大的OGNL表达式来消除了大部分元素。
1.7 集成
单独使用mybatis是有很多限制的(比如无法实现跨越多个session的事务),而且很多业务系统本来就是使用spring来管理的事务,因此mybatis最好与spring集成起来使用。
spring事务配置
copy
<!--自动扫描业务包-->
<context:component-scanbase-package="com.xxx.service"/>
<!--数据源-->
<jee:jndi-lookupid="jndiDataSource"jndi-name="java:comp/env/jdbc/datasource"/>
<!--配置事务-->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="jndiDataSource"/>
</bean>
<!--配置基于注解的事物aop-->
<tx:annotation-driventransaction-manager="txManager"proxy-target-class="true"/>
2开发第一个自己的MyBatis程序
MyBatis工具类
package Util;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* @category Mybatis核心API工具类封装
* @author 许清磊
*
*/
public class MyBatisUtil {
private static SqlSessionFactory factory;//因为下面要用SqlSessionFactory创建SqlSession 然后静态方法只能访问静态所以加static
private static final ThreadLocal<SqlSession> tdl = new ThreadLocal<SqlSession>();//为了线程安全
//静态代码块读取mybatis中核心配置文件
//SqlSessionFactoryBuilder和SqlSessionFactory都是重量级别组件
static{
//Mybatis核心API接口
//创建SqlSessionFactoryBuilder对象 读核心配置文件 获取SqlSessionFactory对象
try {
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
//获取SqlSessionFactory对象用来创建SqlSession对象
factory = builder.build(reader);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* @category 静态方法获取SqlSession一次sql会话
* * SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,
* 没有任何理由对它进行清除或重建。
* 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,
* 多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。
* 因此 SqlSessionFactory 的最佳作用域是应用作用域。
* 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
* @return
*/
public static SqlSession openSession(){
SqlSession session = tdl.get();//先从当前线程副本获取
if(session==null){//为空说明没创建 创建放到当前线程副本上面
session = factory.openSession();//用工厂创建调用openSession方法SqlSession
tdl.set(session);//放到当前局部变量线程池
}
return session;
}
/**
* @category 释放资源
* @param session
*/
public static void close(SqlSession session){
if(session!=null){
session.close();//关闭SqlSession
tdl.remove();//移除当前线程副本内容
}
}
}
Mybatis传递多个参数的4种方式
现在大多项目都是使用Mybatis了,但也有些公司使用Hibernate。使用Mybatis最大的特性就是sql需要自己写,而写sql就需要传递多个参数。面对各种复杂的业务场景,传递参数也是一种学问。
下面给大家总结了以下几种多参数传递的方法。
方法1:顺序传参法也叫下标传参
public User selectUser(String name, int deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user
where user_name = #{0} and dept_id = #{1}
</select>
#{}里面的数字代表你传入参数的顺序。
这种方法不建议使用,sql层表达不直观,且一旦顺序调整容易出错。
方法2:@Param注解传参法
public User selectUser(@Param("userName") String name, int @Param("deptId") deptId);
<select id="selectUser" resultMap="UserResultMap">
select * from user
where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}里面的名称对应的是注解@Param括号里面修饰的名称。
这种方法在参数不多的情况还是比较直观的,推荐使用。
方法3:Map传参法
public User selectUser(Map<String, Object> params);
<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
select * from user
where user_name = #{userName} and dept_id = #{deptId}
</select>
#{}里面的名称对应的是Map里面的key名称。
这种方法适合传递多个参数,且参数易变能灵活传递的情况。
方法4:Java Bean传参法
<insert id="insertCard" parameterType="Card">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select card176_seq.nextval from dual
</selectKey>
insert into card176 values(#{id},#{cardNumber},#{address},#{date})
</insert>
#{}里面的名称对应的是User类里面的成员属性。
这种方法很直观,但需要建一个实体类,扩展不容易,需要加属性,看情况使用。
六、Struts2与mybatis整合