了解MyBatis——让开发更简捷与规范

Jessica瑾妞

2018-03-14

开发Web应用,数据的存储和处理往往离不开数据库和SQL语句。在使用Java开发的Web应用中,自然也少不了连接数据库的步骤。在底层连接数据库的时候,一般使用JDBC技术,也就是Java的一种提供数据库连接和操作SQL的底层API。但是互联网技术正在飞速发展,使用原始JDBC已经满足不了项目的开发需求了,这就使得Hibernate、MyBatis(iBatis)、JPA、JDO等一些优秀的ORM(Object Relational Mapping,对象关系映射)框架诞生,它们不仅结合了原生JDBC的功能,还使开发简捷化、规范化。

1 传统JDBC开发模式的缺陷

JDBC技术作为Java Web的数据库连接核心API,已经成为Java Web开发中不可或缺的工具。但是传统的数据库连接的开发模式是有局限性的,了解其需要优化的地方,有助于理解MyBatis框架的优势所在。

1.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);
    }
}

可以看到,在代码中,数据库驱动程序名称、数据库连接地址、数据库账号及密码全部是“硬编码”到程序中的。所谓的“硬编码”,就是将程序中的外部变量值,使用赋值语句写死在程序中,当需要修改时,要修改源码并重新编译。一般来说,采用“硬编码”的软件项目,其扩展性都非常差。

对于日常开发的项目,在不可控的外部因素下,例如更换数据库所在的服务器导致数据库连接地址发生变化、数据库管理员修改了数据库密码、更换了数据库软件类型(如MySQL更改为Oracle)等情况,都需要对数据库连接类的源代码进行修改、重新编译、打包和上线,这样会浪费很多人力和时间,而且经常变动会导致项目数据不稳定,极易引起软件安全隐患。

最重要的一点是,在每一个操作数据库的类中,都需要引入类似上面的DBConnection数据库连接类,然后获取数据库连接,等到操作数据完毕之后,关闭数据库连接。这样对数据库进行频繁连接、开启和关闭操作,会造成数据库资源的浪费,十分影响数据库的性能。

小贴士:仔细思考一下自己平时开发时的数据库连接方式,有什么优点和缺陷?

1.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),仍需要对源代码进行修改,然后重新编译、打包和上线,这同样不利于软件系统的维护与扩展。

小贴士:思考一下你自己在平时的开发中,有没有出现“硬编码”的情况?

1.3 待优化的问题

经过上述探讨,可以总结出传统JDBC开发模式中存在的需要优化的缺陷。

    1. 连接参数、SQL语句的硬编码:将SQL语句配置在XML或其他非Java的配置文件中,这样即使SQL发生变化,也不需要重新编译Java文件。
    1. 数据库的频繁连接与断开:使用数据库连接池来管理数据的连接。
    1. 查询结果集取数据的硬编码:使用一种机制,将查询出的结果集自动映射为Java对象,无须手动设置。

以上优化问题的解决方案,我们将在下面的MyBatis框架的学习过程中逐步了解。

2 初识MyBatis

伟大的物理学家牛顿曾说过:“如果说我所看得比笛卡儿更远一点,那是因为站在巨人肩上”,而MyBatis就是这一宽厚的肩膀,帮助程序员提高开发效率,更容易开发出高性能的程序。MyBatis框架弥补了传统JDBC开发模式的不足,同时其强大的加载配置、SQL解析与执行、结果映射等机制,使得项目的开发效率和程序的数据处理性能得到大大的提升,是目前比较成熟、使用率比较高的持久层框架。

2.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.2 MyBatis整体架构

MyBatis整体的构造由数据源配置文件、SQL映射配置文件、会话工厂、会话、执行器以及底层封装对象组成。接下来对这些核心对象进行逐一讲解。

1. 数据源配置文件

对于一个持久层框架,也就是负责连接数据库,并对数据进行操作的一套框架,连接数据库是最重要的一步。MyBatis框架对于数据库连接的配置信息,采用了配置“数据库连接池”的形式。所谓的“数据库连接池”(又可称作“数据源”),就是让数据库的配置信息从外部的某种配置文件中读取,然后由一个独立处理数据库连接的程序来和数据库进行交互。这样一来,应用程序本身不必关心数据库的配置信息,数据库的配置交由独立的模块管理和配置。

在MyBatis中,数据库的数据源是配置在SqlMapConfig.xml(文件名可更改)配置文件中的,其中配置了数据库驱动、数据库连接地址、数据库用户名和密码、事务管理等参数,如果对数据库连接池有性能的要求,还可以配置连接池的连接数和空闲时间等详细参数。

在项目中,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单独配置数据库连接池了。

小贴士:不同的数据库,拥有不同的数据库连接驱动,这里需要开发者根据需要配置连接参数。

2. 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语句。

3. 会话工厂与会话

准备好了数据库连接池配置文件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。

2.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运行流程结构如图2-1所示。

理解MyBatis的运行流程结构,对接下来的学习很有帮助。

小贴士:在之后的学习过程中,可以反复观察MyBatis的运行流程结构图,了解每一个组件在整个架构中扮演的角色。

本文选自《Spring MVC+MyBatis开发从入门到项目实战》

读者评论

相关专题

相关博文

  • Spark四大特征分析介绍

    Spark四大特征分析介绍

    Jessica瑾妞 2018-03-21

    Spark是一种基于内存的、分布式的、大数据处理框架,在 Hadoop 的强势之下,Spark凭借着快速、简洁易用、通用性以及支持多种运行模式四大特征,冲破固有思路成为很多企业标准的大数据分析框架。 1 快速 面向磁盘的MapRed...

    Jessica瑾妞 2018-03-21
    10588 0 1 1
  • 数据治理“知易行难”?来看看《数据治理实践者手记》

    博文小编 2024-04-22

    当前,在全球信息化快速发展的背景下,我国对数据治理的重视程度显著提升,各地纷纷成立大数据局、数据交易所,同时数据资产入表的工作也在尝试和快速推进中。 这些动作不仅标志着数据治理在政策和战略层面得到重视,也反映了数据作为一种新的生产要...

    博文小编 2024-04-22
    17 0 0 0
  • 用Python构建大数据推荐系统:一个世界500强企业的成功案例

    用Python构建大数据推荐系统:一个世界500强企业的成功案例

    博文小编 2023-06-02

    推荐系统是大数据时代的利器,它能够为企业提升用户体验、增加用户粘性、促进销售转化、提高营销效率等。但是,搭建一个成功的推荐系统并不容易,它需要综合考虑多方面的因素,并根据业务场景、用户需求、数据变化等不断地进行迭代和优化。 本文将以...

    博文小编 2023-06-02
    205 0 0 0