【MyBatis系列1】MyBatis快速入门demo(基于传统JDBC,DBUtils,Hibernate的对比分析)

1,121 阅读4分钟

前言

作为一名Java后台开发,与数据库打交道是必不可少的一部分,那么与数据库打交道就涉及到了如何建立连接,如何将数据库的表转换为Java对象等等,这些都是需要考虑的问题,所以Java中提供了JDBC来供我们操作数据库

JDBC编程

JDBC(Java Data Base Connectivity),早先的Java开发程序员都是通过JDBC来操作数据库的,通过JDBC来操作数据库有一个很大的弊端就是操作过于繁琐,会有大量的和业务无关的一些操作。通过JDBC来操作数据库主要经过如下步骤:

  • 1、注册驱动,并通过指定的数据库url,账号密码等信息来建立连接
  • 2、打开连接,获取Connection对象
  • 3、通过Connection获取Statement对象
  • 4、通过Statement对象操作SQL语句,获得结果集ResultSet对象
  • 5、通过ResultSet对象获取结果集,并将结果集转换为Java对象
  • 6、关闭数据库连接相关资源

如下就是一个典型的JDBC操作数据库过程:
引入maven相关依赖:

 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

写一个简单的实体类来接收数据库查询结果:

package com.lonelyWolf.mybatis.model;

public class LwUser {
    private String userId; //用户id
    private String userName; //用户名称

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}

然后写一个测试类:

package com.lonelyWolf.mybatis;

import com.lonelyWolf.mybatis.model.LwUser;

import java.sql.*;

public class TestJDBC {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try {
            //1、注册JDBC驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、打开连接,获得Connection对象
            conn = DriverManager.getConnection("jdbc:mysql://10.xxx.xxx.xxx:3306/lonely_wolf", "root", "123456");
            //3、获得Statement对象
            stmt = conn.createStatement();
            //4、执行sql语句获取结果集ResultSet
            String sql = "select user_id,user_name from lw_user";
            ResultSet rs = stmt.executeQuery(sql);
            //5、将结果集转换为Java对象
            while (rs.next()) {
                LwUser lwUser = new LwUser();
                String userId = rs.getString("user_id");
                String userName = rs.getString("user_name");
                lwUser.setUserId(userId);
                lwUser.setUserName(userName);
                System.out.println(JSONObject.toJSONString(lwUser));
            }
            //6、关闭资源
            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException se) {
            se.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (stmt != null) stmt.close();
            } catch (SQLException se2) {
            }
            try {
                if (conn != null) conn.close();
            } catch (SQLException se) {
                se.printStackTrace();
            }
        }
    }
}

这就是一个简单的原生JDBC编程的代码,而且是不带参数的查询,如果待参数的话需要进行如下改写:

 String sql = "select user_id,user_name from lw_user where user_id=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1,"1");//第1个1表示参数位置,第二个是参数的值
            ResultSet rs = ps.executeQuery();

也就是说我们需要知道参数具体位置,具体类型然后按顺序设置参数。
可以很明显看到,我们只是想执行一个简单的查询,却需要写很多底层操作的和业务无关的逻辑。
具有以下明显的缺陷:

  • 1、需要手动管理资源
  • 2、代码重复
  • 3、业务逻辑与数据操作的代码耦合
  • 4、SQL语句需要硬编码写在业务代码内
  • 5、设置参数时必须要知道参数具体位置
  • 6、结果集需要手动处理

既然这么多和业务无关的代码,那么封装起来就好了,是的,这是一个办法,所以这就有了一些工具类,如DbUtils等来将我们数据操作相关的代码进行了封装

Apache DbUtils

DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,其目的是能够简化JDBC应用程序的开发过程中大量繁琐的数据操作(类似的还有Spring JDBC工具)。
我们先来看一个简单的例子:
首先引入依赖:

<dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>

然后通过DbUtils将上面的JDBC操作进行改写:

package com.lonelyWolf.mybatis;

import com.alibaba.fastjson.JSONObject;
import com.lonelyWolf.mybatis.model.LwUser;
import org.apache.commons.dbutils.*;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;

public class TestDbUtil {
    public static void main(String[] args) throws SQLException {
        Connection connection = null;
        try {
            //1、注册JDBC驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、打开连接,获得Connection对象
            connection = DriverManager.getConnection("jdbc:mysql://10.xxx.xxx.xxx.xxx:3306/lonely_wolf", "root", "123456");
        }catch (Exception e){
            e.printStackTrace();
        }
        QueryRunner queryRunner = new QueryRunner();
        String sql = "select user_id,user_name from lw_user";
        //开启驼峰
        BeanProcessor bean = new GenerousBeanProcessor();
        RowProcessor processor = new BasicRowProcessor(bean);
        //执行查询
        List<LwUser> lwUsers = queryRunner.query(connection,sql,new BeanListHandler<>(LwUser.class,processor));
        System.out.println(null == lwUsers ? "":JSONObject.toJSONString(lwUsers));
        DbUtils.closeQuietly(connection);
    }
}

可以看到,获取连接之后我们不需要再去获取Statement和ResultSet等对象了,直接调用API就可以拿到转换成Java对象之后的数据。
使用DbUtils如果执行带参数的查询呢,也是需要进行如下改写:

 Object[] params = new Object[1];
        params[0] = "1";
        List<LwUser> lwUsers = queryRunner.query(connection,sql,params,new BeanListHandler<>(LwUser.class,processor));

相比较于原生的JDBC操作,使用DbUtils已经简单了很多,DbUtils解决了一些问题,但是也有一些问题没有解决。
DbUtils解决了:

  • 1、方法封装
  • 2、支持数据源
  • 3、映射结果集
    但是DbUtils仍然有如下2个主要问题没有解决:
  • 1、SQL语句硬编码
  • 2、参数只能按顺序传入(占位符)
  • 3、没有提供缓存等功能(每次操作都需要操作数据库连接,非常消耗性能)

所以为了改进工具类的不足,基于ORM模型的框架就应运而生了。

ORM模型

ORM,Object Relational Mapping:对象关系映射。
ORM模型简单来说就是数据库表和Java对象(Plain Ordinary Java Object,简称POJO)的映射关系模型,如下图所示:
在这里插入图片描述
有了ORM框架,开发的时候再也不用去关心底层的数据库操作,只需要专心的写业务代码就行了,大大提升了开发效率。

常见的ORM框架

有了ORM模型,那么就会有人将其落地实现,所以也就有了各种类型的框架。

Hibernate

Hibernate在Java开发中应该可以称之为著名的ORM框架之一了,很多人都用过SSH(Struts2+Hibernate+Spring)框架组合开发,现在用的人可能比较少了,但是在以前Hibernate是开发首选的ORM框架。

Hibernate之所以能流行是因为在Hibernate之前Sun公司曾经推出过一个Java服务端组件模型EJB(Enterprise Java Beans),但是EJB配置比较复杂,而且适用范围小。所以Hibernate诞生后就替代了EJB模型。

Hibernate是通过一个hbm.xml配置文件来实现了数据库和POJO映射,不论是一对一,一对多还是都对多,都可以通过配置文件实现。
在这里插入图片描述
Hibernate虽然解决了传统JDBC编程锁存在的一些问题,但是同时也存在以下两个较严重的问题:

  • 1、对多表关联和比较复杂的数据表结构查询支持相对较差。
  • 2、SQL语句是自动生成的,我们很难修改其生成的SQL语句,也就是无法对SQL进行很好地优化,这对当今互联网公司的数据量级别是无法接受的。
  • 3、Hibernate是全表映射,在某些场景中,操作大表会浪费带宽

MyBatis

为了解决Hibernate框架所存在的问题,MyBatis出现了。

MyBatis的前身是Apache的一个开源项目iBatis,并且在2010年正式脱离了Apache,并命名为Mybatis。

Mybatis是一款半自动化的ORM框架,因为要实现数据库和和Java对象的映射需要我们自己去手动实现(Hibernate中并不需要),使用MyBatis,我们需要提供以下三类文件:

  • SQL语句
  • 映射规则
  • POJO

SQL语句需要手动编写,这就给了我们优化的机会,而在Mybatis中,编写SQL语句和传统JDBC不一样的是传统JDBC是直接写在业务代码里,而MyBatis是相对独立的。
MyBatis的映射模型如下图所示:
在这里插入图片描述

MyBatis简单示例

接下来我们来看一个MyBatis的简单例子:

1、引入MyBatis依赖:

<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
<!-- maven编译xml文件需要手动添加配置,否则会找不到mapper.xml文件-->
<build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**\\/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

配置mybatis-config.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>
    <properties resource="db.properties"></properties>
    <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
        <!-- 开启驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!-- 别名 -->
    <typeAliases>
        <typeAlias alias="lwUser" type="com.lonelyWolf.mybatis.model.LwUser" />
    </typeAliases>

    <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://10.xxx.xxx.xxx:3306/lonely_wolf"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/lonelyWolf/mybatis/mapping/UserMapper.xml"/>
    </mappers>

</configuration>

对应的mapper接口文件:

package com.lonelyWolf.mybatis.mapper;

import com.lonelyWolf.mybatis.model.LwUser;
import java.util.List;

public interface UserMapper {
    List<LwUser> listAllUser();
}

对应的UserMapper.xml文件,注意,这两个文件要保持同名(UserMapper.java和UserMapper.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接口 -->
<mapper namespace="com.lonelyWolf.mybatis.mapper.UserMapper">

	<!-- 因为定义了别名,所以这里可以直接使用lwUser-->
    <select id="listAllUser" resultType="lwUser">
        select user_id,user_name from lw_user
    </select>

</mapper>

最后新建一个测试类来试试:

package com.lonelyWolf.mybatis;

import com.alibaba.fastjson.JSONObject;
import com.lonelyWolf.mybatis.model.LwUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMyBatis {

    public static void main(String[] args) throws IOException {
        String resource = "mybatis-config.xml";
        //读取mybatis-config配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //创建SqlSession对象
        SqlSession session = sqlSessionFactory.openSession();
        try {
            List<LwUser> userList = session.selectList("com.lonelyWolf.mybatis.mapper.UserMapper.listAllUser");
            System.out.println(null == userList ? "":JSONObject.toJSONString(userList));
        } finally {
            session.close();
        }
    }
}

如此一个简单的demo就完成了。

总结

本文通过将传统JDBC,DBUtils,Hibernate,Mybatis等进行了对比,分析了为什么最后MyBatis会成为当前最流行的ORM框架,并利用了一个简单的demo来完成了一个简单的查询语句。
下一篇会详细介绍MyBatis的全局配置文件都可以配置哪些功能。