了解MyBatis——让开发更简捷与规范
Posted 博文视点Broadview
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解MyBatis——让开发更简捷与规范相关的知识,希望对你有一定的参考价值。
小编说:本文带我们了解了原始JDBC开发的缺点,以及MyBatis框架的优势和适用场合。
本文选自《Spring MVC+MyBatis开发从入门到项目实战》,了解本书详情请点击阅读原文。
开发Web应用,数据的存储和处理往往离不开数据库和SQL语句。在使用Java开发的Web应用中,自然也少不了连接数据库的步骤。在底层连接数据库的时候,一般使用JDBC技术,也就是Java的一种提供数据库连接和操作SQL的底层API。但是互联网技术正在飞速发展,使用原始JDBC已经满足不了项目的开发需求了,这就使得Hibernate、MyBatis(iBatis)、JPA、JDO等一些优秀的ORM(Object Relational Mapping,对象关系映射)框架诞生,它们不仅结合了原生JDBC的功能,还使开发简捷化、规范化。
传统JDBC开发模式的缺陷
JDBC技术作为Java Web的数据库连接核心API,已经成为Java Web开发中不可或缺的工具。但是传统的数据库连接的开发模式是有局限性的,了解其需要优化的地方,有助于理解MyBatis框架的优势所在。
1 . JDBC连接数据库模式分析
JDBC(Java DataBase Connectivity)即“Java数据库连接”,是一种提供连接数据库、使用SQL语句操作数据库数据的技术的标准Java API。在传统的JSP/Servlet开发模式下,一般直接使用JDBC进行数据库的连接和操作。
传统开发模式中,在使用JDBC进行数据库连接时,一般都在引入相关的数据库驱动jar包后,创建一个数据库连接类,该类提供数据库驱动的加载、数据库连接参数配置、连接对象的获取以及连接对象的关闭操作,代码示例如下:
package cn.com.test.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBConnection {
//定义mysql的数据库驱动程序
public static final String DBDRIVER = "org.gjt.mm.mysql.Driver" ;
//定义MySQL的数据库连接地址
public static final String DBDURL = "jdbc:mysql://localhost:3306/mydata" ;
//MySQL数据库的连接用户名
public static final String DBUSER = "root" ;
//MySQL数据库的连接密码
public static final String DBPASS = "1234" ;
static{
try {
Class.forName(DBDRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn=null;
try {
conn=DriverManager.getConnection(DBDURL,DBUSER,DBPASS);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(ResultSet rs,Statement st,Connection conn){
try {
if(rs!=null){rs.close();}
if(st!=null){st.close();}
f(conn!=null){conn.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(Statement st,Connection conn){
close(null,st,conn);
}
}
最重要的一点是,在每一个操作数据库的类中,都需要引入类似上面的DBConnection数据库连接类,然后获取数据库连接,等到操作数据完毕之后,关闭数据库连接。这样对数据库进行频繁连接、开启和关闭操作,会造成数据库资源的浪费,十分影响数据库的性能。
小贴士:仔细思考一下自己平时开发时的数据库连接方式,有什么优点和缺陷?
2 . JDBC操作SQL语句模式分析
在使用传统JDBC连接数据库的开发模式下,当需要操作数据库的时候,首先需要创建数据库连接类DBConnection,并通过getConnection方法获取数据库连接对象。在获取数据库连接对象的同时,还要创建一个预编译对象,去加载并预编译SQL语句。然后使用数据库连接对象的prepareStatement方法将编写好的SQL语句预编译。得到预编译对象之后,传入需要操作的参数,并执行SQL语句,就可以得到数据库的操作结果。代码示例如下(以添加一条Teacher类数据的add方法为例):
public boolean add(Teacher teacher) {
boolean flag=false;
Connection conn=null;
PreparedStatement pst=null;
try {
conn=DB.getConnection();
String sql="insert into teacher (number,name,sex,classname,address) values(?,?,?,?,?)";
pst=conn.prepareStatement(sql);
pst.setInt(1, teacher.getNumber());
pst.setString(2, teacher.getName());
pst.setString(3, teacher.getSex());
pst.setString(4, teacher.getClassname());
pst.setString(5, teacher.getAddress());
int rows=pst.executeUpdate();
if(rows>0){flag=true;}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DB.close(pst,conn);
}
return flag;
}
可以看到,在这段代码中,SQL语句和preparedStatement设置的占位符语句,以及各种占位符对应的参数设置,全部是“硬编码”到代码中的。如果修改SQL语句和插入的参数,就要对源代码进行修改,然后重新编译、打包和上线,这样十分不利于软件系统的维护与扩展。
下面这段代码为获取Teacher类全部对象的select方法:
public List<Teacher> getTeachers() {
List<Teacher> list = new ArrayList<Teacher>();
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = DB.getConnection();
String sql = "select * from teacher";
st = conn.createStatement();
rs = st.executeQuery(sql);
while (rs.next()) {
Teacher teacher = new Teacher();
teacher.setNumber(rs.getInt("number"));
teacher.setName(rs.getString("name"));
teacher.setSex(rs.getString("sex"));
teacher.setClassname(rs.getString("classname"));
teacher.setAddress(rs.getString("address"));
list.add(teacher);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
DB.close(rs, st, conn);
}
return list;
}
观察上述代码可以看到,从ResultSet中遍历结果集数据时,使用“getString”、“getInt”等获取数据的方法,其中的参数即是表字段的名称,这也是一种“硬编码”,当数据库相应的表字段出现变动时(如sex列更名为gender),仍需要对源代码进行修改,然后重新编译、打包和上线,这同样不利于软件系统的维护与扩展。
小贴士:思考一下你自己在平时的开发中,有没有出现“硬编码”的情况?
3 . 待优化的问题
经过上述探讨,可以总结出传统JDBC开发模式中存在的需要优化的缺陷。
连接参数、SQL语句的硬编码:将SQL语句配置在XML或其他非Java的配置文件中,这样即使SQL发生变化,也不需要重新编译Java文件。
数据库的频繁连接与断开:使用数据库连接池来管理数据的连接。
查询结果集取数据的硬编码:使用一种机制,将查询出的结果集自动映射为Java对象,无须手动设置。
以上优化问题的解决方案,我们将在下面的MyBatis框架的学习过程中逐步了解。
2 初识MyBatis
伟大的物理学家牛顿曾说过:“如果说我所看得比笛卡儿更远一点,那是因为站在巨人肩上”,而MyBatis就是这一宽厚的肩膀,帮助程序员提高开发效率,更容易开发出高性能的程序。MyBatis框架弥补了传统JDBC开发模式的不足,同时其强大的加载配置、SQL解析与执行、结果映射等机制,使得项目的开发效率和程序的数据处理性能得到大大的提升,是目前比较成熟、使用率比较高的持久层框架。
1 . MyBatis介绍
MyBatis是Apache的一个Java开源项目,原名为iBatis(即Internet与abatis的结合),后因项目托管平台的迁移(由Goolge Code转移至GitHub)更名为MyBatis。MyBatis是一款支持动态SQL语句的持久层框架,支持目的是让开发人员将精力集中在SQL语句上。
MyBatis可以将SQL语句配置在XML文件中,这避免了JDBC在Java类中添加SQL语句的硬编码问题;通过MyBatis提供的输入参数映射方式,将参数自由灵活地配置在SQL语句配置文件中,解决了JDBC中参数在Java类中手工配置的问题;通过MyBatis的输出映射机制,将结果集的检索自动映射成相应的Java对象,避免了JDBC中对结果集的手工检索;同时MyBatis还可以创建自己的数据库连接池,使用XML配置文件的形式,对数据库连接数据进行管理,避免了JDBC的数据库连接参数的硬编码问题。
综上所述,MyBatis的特点是,采用配置文件动态管理SQL语句,并含有输入映射、输出映射机制以及数据库连接池配置的持久层框架。
小贴士:MyBatis是一款优秀的ORM框架,与Hibernate框架的目的相同,都是为了简化数据库开发,但两者的特点又有明显不同。
2 . MyBatis整体架构
MyBatis整体的构造由数据源配置文件、SQL映射配置文件、会话工厂、会话、执行器以及底层封装对象组成。接下来对这些核心对象进行逐一讲解。
① 数据源配置文件
对于一个持久层框架,也就是负责连接数据库,并对数据进行操作的一套框架,连接数据库是最重要的一步。MyBatis框架对于数据库连接的配置信息,采用了配置“数据库连接池”的形式。所谓的“数据库连接池”(又可称作“数据源”),就是让数据库的配置信息从外部的某种配置文件中读取,然后由一个独立处理数据库连接的程序来和数据库进行交互。这样一来,应用程序本身不必关心数据库的配置信息,数据库的配置交由独立的模块管理和配置。
在项目中,SqlMapConfig.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>
<environments default="development">
<environment id="development">
<!-- 使用JDBC事务管理-->
<transactionManager type="JDBC" />
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="org.gjt.mm.mysql.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ mydata?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
</configuration>
值得一提的是,在后期与 Spring MVC框架的整合中,将会使用 Spring MVC建立数据库连接池,此时就不用为MyBatis单独配置数据库连接池了。
小贴士:不同的数据库,拥有不同的数据库连接驱动,这里需要开发者根据需要配置连接参数。
② SQL映射配置文件
在传统的JDBC开发模式中,SQL语句是硬编码在Java代码中的。而MyBatis框架,将SQL配置在独立的配置文件Mapper.xml(文件名可更改)中,简称“Mapper配置文件”。在这个配置文件中可以配置任何类型的SQL语句,包括select、update、delete和insert语句。
对于SQL语句执行所需要的参数,以及查询语句返回的结果集对象,都可以在Mapper.xml配置文件中配置。在输入参数方面,MyBatis框架会根据配置文件中的参数配置,将组装参数的Java对象或Map对象中的相关字段与Mapper.xml中的参数配置做匹配,将相关数据绑定在需要执行的SQL语句上;在查询语句输出结果时,会根据Mapper.xml中配置的结果集信息,将从数据库取出的数据字段,一一映射到相应的Java对象或Map对象中。也就是说,Mapper.xml配置文件,完成了对SQL语句以及输入输出参数的映射配置。
在项目中,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">
<mapper namespace="test">
<select id="findUserById" parameterType="int" resultType="cn.com.mybatis. model.User">
SELECT * FROM USER WHERE id=#{id}
</select>
</mapper>
在上述配置信息中,可以在mapper标签对中配置很多SQL语句。其中的select标签对中包含了一段SQL查询语句,其中的parameterType指定了输入参数的类型,而resultType指定了输出结果映射的Java对象类型。可以看到其中的resultType的参数信息是一个JavaBean(Java基本信息封装类),也就是说,这段select的结果参数配置表示将单条记录映射成一个Java对象。
Mapper.xml的文件路径,一般会配置在数据源配置文件SqlMapConfig.xml中,其会随着数据库配置参数一起被加载。配置方式如下:
<mappers>
<mapper resource="sqlmap/UserMapper.xml"/>
<mapper resource="sqlmap/GoodsMapper.xml"/>
</mappers>
SQL映射配置文件在MyBatis框架中是十分重要的,使用MyBatis框架的开发人员,每天面对最多的就是各种Mapper.xml配置文件。所以,后期将会紧紧围绕着SQL映射配置文件来学习。
小贴士:MyBatis的核心就是基于SQL配置的Mapper映射文件,所有数据库的操作都会基于该映射文件和配置的SQL语句。
③ 会话工厂与会话
准备好了数据库连接池配置文件SqlMapConfig.xml,以及SQL映射配置文件Mapper.xml之后,需要相关的程序来读取并加载这些配置文件的信息。而MyBatis中处理这些配置信息的核心对象就是“会话工厂”与“会话”。
在MyBatis中,“会话工厂”即是SqlSessionFactory类。学过设计模式的读者应该对“工厂”这个抽象词汇不陌生,它是一种会产生某种规范的对象的类。SqlSessionFactory类会根据Resources资源信息加载对象,获取开发人员在项目中配置的数据库连接池配置文件SqlMapConfig.xml的信息,从而产生一种可以与数据库交互的会话实例类——SqlSession。就好像一个卫星工厂一样,给厂商一个卫星的详细发射波长规格配置说明书,他们就能生产出能发射该种类型波长的卫星产品。SqlSessionFactory可以根据数据库配置信息产生出可以连接数据库并与其交互的SqlSession会话实例类。
前面提到过,SQL映射配置文件Mapper.xml的路径是配置在SqlMapConfig.xml配置文件中的,所以SqlSessionFactory类同时也加载了SQL语句的配置信息。通过其产生的SqlSession会话实例类,可以依照Mapper配置文件中的SQL配置,对数据库执行增删改查的操作。
小贴士:会话工厂SqlSessionFactory会根据配置文件生成相应的可以操作数据库的会话实例类SqlSession。
3 . MyBatis运行流程
MyBatis的整个运行流程,也是紧紧围绕着数据库连接池配置文件SqlMapConfig.xml,以及SQL映射配置文件Mapper.xml而开展的。
首先SqlSessionFactory会话工厂会通过Resources资源信息加载对象获取SqlMapConfig.xml配置文件信息,然后产生可以与数据库进行交互的会话实例类SqlSession。会话实例类SqlSession可以根据Mapper配置文件中的SQL配置,去执行相应的增删改查操作。而在SqlSession类内部,是通过执行器Executor(分为基本执行器和缓存执行器)对数据库进行操作的。执行器Executor与数据库交互,依靠的是底层封装对象Mappered Statement,它封装了从Mapper文件中读取的信息(包括SQL语句、输入参数、输出结果类型)。通过执行器Executor与底层封装对象Mappered Statement的结合,MyBatis就实现了与数据库进行交互的功能。
MyBatis运行流程结构如图所示。
MyBatis运行流程结构图
理解MyBatis的运行流程结构,对接下来的学习很有帮助。
小贴士:在之后的学习过程中,可以反复观察MyBatis的运行流程结构图,了解每一个组件在整个架构中扮演的角色。
相关图书《Spring MVC+MyBatis开发从入门到项目实战》,详情点击阅读原文
博文视点
您阅读的专业智库
了解更多本书详情请点击阅读原文
长按二维码轻松关注
点击阅读原文,即可快速抵达本书详情页!
以上是关于了解MyBatis——让开发更简捷与规范的主要内容,如果未能解决你的问题,请参考以下文章