MyBatis系列一 MyBatis 简介

一、传统的JDBC编程

  Java程序都是通过JDBC (Java Data Base Connectivity)连接数据库的,这样我们就可 以通过SQL对数据库编程。JDBC是由SUN公司(SUN公司后被Oracle公司收购)提出的一系列规范,但是它只定义了接口规范,而具体的实现是交由各个数据库厂商去实现的,因为每个数据库都有其特殊性,这些是Java规范没有办法确定的,所以JDBC就是一种典型的桥接模式。

 

 

  传统的JDBC编程的使用给我们带来了连接数据库的功能,但是也引发了巨大的问题。

public class JdbcExample (
  private Connection getConnection() (
    Connection connection = null;
    try (
      Class.forName ("com.mysql.jdbc.Driver");
      String url = "jdbc:mysql://localhost:3306/mybatis?zeroDateTimeBehavior=convertToNull";
      String user = “root”;
      String password = "learn";
      connection = DriverManager.getConnection(url,user,password);
    } catch (ClassNotFoundException | SQLException ex) (
      Logger.getLogger(JdbcExample.class.getName()).log(Level•SEVERE, null, ex);
      return null;
    }
    return connection;
  )
  public Role getRole(Long id) (
    Connection connection = getConnection ();
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
      ps = connection.prepareStatement ("select id, role_name, note from t_role where id = ?");
      ps.setLong(1, id);
      rs = ps.executeQuery();
      while(rs.next()) (
      Long roleld = rs.getLong("id");
      String userName = rs.getString ("role_name");
      String note = rs.getString ("note");
      Role role = new Role();
      role.setld(id);
      role.setRoleName(userName);
      role.setNote(note);
      return role;
    )
  } catch (SQLException ex) (
    Logger.getLogger(JdbcExample.class.getName()).log(Level.SEVERE, null, ex);
  } finally (
    this.close(rs, ps, connection);
  }
    return null;
}
  private void close(ResultSet rs, Statement stmt, Connection connection)
(
    try (
      if (rs != null && !rs.isClosed()) (
        rs.close ();
    } 
    catch (SQLException ex) (       Logger.getLogger(JdbcExample.class.getName()).log(Level.SEVERE, null, ex);     }     try (       if (stmt != null && !stmt.isClosed()) {
        stmt.close();       }     }
catch (SQLException ex) (       Logger.getLogger(JdbcExample.class.getName()).log(Level.SEVERE, null, ex);     }     try (       if (connection != null && !connection.isClosed()) (
          connection.close ();         }     }
catch (SQLException ex) (       Logger.getLogger(JdbcExample.class.getName()).log(Level.SEVERE, null, ex);     }   }   public static void main(String[] args) (     JdbcExample example = new JdbcExample();     Role role = example.getRole(IL);     System.err.printIn(nrole_name => n + role.getRoleName());     }   }

从代码中我们可以看出整个过程大致分为以下几步:

•使用JDBC编程需要连接数据库,注册驱动和数据库信息。

操作 Connection,打开 Statement 对象。

•通过Statement执行SQL,返回结果到ResultSet对象。

•使用ResultSet读取数据,然后通过代码转化为具体的POJO对象。

•关闭数据库相关资源。

  使用传统的JDBC方式存在一些弊端。

  其一,工作量相对较大。我们需要先连接,然 后处理JDBC底层事务,处理数据类型。我们还需要操作Connection对象、Statement对象 ResultSet对象去拿到数据,并准确关闭它们。

  其二,我们要对JDBC编程可能产生的异 常进行捕捉处理并正确关闭资源。对于一个简单的SQLJDBC中尚且如此复杂,何况是 更为复杂的应用呢?很快这种模式就被一些新的方法取代,于是ORM模型就出现了。不 过所有的ORM模型都是基于JDBC进行封装的,不同的ORM模型对JDBC封装的强度是 不一样的。

 

二、ORM模型

  由于JDBC存在的缺陷,在实际工作中我们很少使用JDBC进行编程,于是提出了对 象关系映射Object Relational Mapping,简称 ORM,或者 O/RM,或者 O/R mapping)。  什么是ORM模型呢?

  简单地说,ORM模型就是数据库的表和简单Java对象Plain Ordinary Java Object, 简称POJO)的映射关系模型,它主要解决数据库数据和POJO对象的相互映射。我们通过这层映射关系就可以简单迅速地把数据库表的数据转化为POJO,以便程序员更加容易理解 和应用Java程序,如图1.1所示。

 

 

 

  有了 ORM模型,在大部分情况下,程序员只需要了解Java应用而无需对数据库相关 知识深入了解,便可以写出通俗易懂的程序。此外,ORM模型提供了统一的规则使得数据库的数据通过配置便可轻易映射到POJO上。

三、Hibernate

 

 

  最初SUN公司推出了 Java EE服务器端组件模型(EJB),但是由于EJB配置复杂,且 适用范围较小,于是很快就被淘汰了。与EJB的失败伴随而来的是另外一个框架的应运而生。它就是从诞生至今都十分流行的Hibernate

  Hibernate 一问世就成了 Java世界首选的ORM模型,它是建立在POJO和数据库表模 型的直接映射关系上的。

  Hibernate是建立在若干POJO通过XML映射文件(或注解)提供的规则映射到数据 库表上的。换句话说,我们可以通过POJO直接操作数据库的数据。它提供的是一种全表 映射的模型。如图1・2所示是Hibernate模型的开发过程。相对而言,Hibernate对JDBC的 封装程度还是比较高的,我们己经不需要编写SQL语言(Structured Query Language),只 要使用 HQL 语言(Hibernate Query Langurage)就可以了。

 

 

 

  首先我们需要提供hbm.xml文件,制定映射规则。

 

<?xml version="l.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN”
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 2015-12-12 22:50:58 by Hibernate Tools 4.3.1 --> 
<hibernate-mapping>   <class name="com.learn.mybatis.chapterl.po.TRole" table="t_role" catalog="mybatis" optimistic-lock="version">     <id name="id” type="long">       <column name="id" />       <generator class="assigned" />     </id>     <property name="roleName" type="string">       <column name="role_name" length="60" />     </property>     <property name="note" type="string">       <column name="note" length="512" />     </property>    </class> </hibernate-mapping>

 

  这是一个简单的XML文件,它描述的是POJO和数据库表的映射关系。Hibernate 过配置文件(或注解)就可以把数据库的数据直接映射到POJO,我们可以通过操作POJO 去操作数据库记录。对于不擅长SQL的程序员来说,这是莫大的惊喜,因为通过Hibernate 你几乎不需要编写SQL就能操作数据库的记录。代码清单1-3是Hibernate的配置信息。

<?xml version="l.0” encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN” "http://hibernate.sourceforge.net/hibernate- configuration-3.0.dtd”>
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 
   <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>     <property name=nhibernate•connection•urln>jdbc:mysql://localhost:3306/mybatis?zero DateTimeBehavior=convertToNull</property>     <property name=nhibernate.connection•usernamen>root</property> <property name=Hhibernate.connection.passwordff>learn</property> <mapping resource=,fcom/learn/mybatis/chapter1/po/TUser.hbm.xmlH/> <mapping resource=ncom/learn/mybatis/chapterl/po/TRole.hbm.xmln/>   </session-factory〉 </hibernate-configuration〉

  别看代码很多,但是全局就是这样的一个XML文件,作为数据库连接信息,配置信 息也相对简易。然后建立Hibernate的工厂对象(SessionFactory),用它来做全局对象,产 Session接口,就可以操作数据库了。

 

public class HibernateUtil (
  private static final SessionFactory sessionFactory;
    static (
      try (
        Configuration cfg = new Configuration().configure ("hibernate.cfg.xml");
        sessionFactory = cfg.buildSessionFactory();
      } catch (Throwable ex) {
        System.err.printIn("Initial SessionFactory creation failed." +ex);
        throw new ExceptionlnlnitializerError(ex);
        }
      }
  public static SessionFactory getSessionFactory() (
    return sessionFactory;
    }
  } 

 

  上面的操作为的是产生HibernateSessionFactroy它作为全局,可以到处引用,那 么剩下来的使用就非常简单了。

 

public class HibernateExample (
  public static void main(String[] args) (
    Session session = null;
    try {
      session = HibernateUtil.getSessionFactory().openSession();
      TRole role = (TRole)session.get(TRole.class, 1L);       System.err.printin(nrole_name = >” + role.getRoleName());     ) finally (       if (session != null) ( session.close();     }   }   ) }

 

 

  按照代码的方法来实现代码清单1-1的功能有以下好处:

消除了代码的映射规则,它全部被分离到了 XML或者注解里面去配置。

•无需再管理数据库连接,它也配置在XML里面。

• 一个会话中,不要操作多个对象,只要操作Session对象即可。

•关闭资源只需要关闭一个Session便可。

 

  这就是Hibernate的优势,在配置了映射文件和数据库连接文件后,Hibernate就可以通 Session操作,非常容易,消除了 JDBC带来的大量代码,大大提高了编程的简易性和可 读性。此外,它还提供级联、缓存、映射、一对多等功能,以便我们使用。正因为具有这 些优势,Hibernate成为了时代的主流框架,被大量应用在各种Java数据库的访问中。Hibernate是全表映射,你可以通过HQL去操作POJO进而操作数据库的数据。

  但是Hibernate有缺陷吗?当然有,世界上没有完美无缺的方案。作为全表映射框架, 举个例子来说,如果我们有张账务表(按年分表),比如2015年表命名为bill2015,至IJ 2016年表命名为bill2016,要动态加映射关系,Hibernate需要破坏底层封装才能做到。又 比如说,一些账务信息往往需要和某些对象关联起来,不同的对象有不同的列,因此列名 也是无法确定的,显然我们没有办法配置XML去完成映射规则。再者如果使用存储过程, Hibernate也是无法适应的。这些都不是致命的,最为致命的问题是性能。Hibernate屏蔽了 SQL,那就意味着只能全表映射,但是一张表可能有几十到上百个字段,而你感兴趣的只 2个,这是Hibernate无法适应的。尤其是在大型网站系统,对传输数据有严格规定,不 能浪费带宽的场景下就更为明显了。有很复杂的场景需要关联多张表,Hibernate全表逐级 取对象的方法也只能作罢,写SQL还需要手工的映射取数据,这带来了很大的麻烦。此外, 如果我们需要优化SQL, Hibernate也是无法做到的。

我们稍微总结一下Hibernate的缺点: 

•全表映射带来的不便,比如更新时需要发送所有的字段。

•无法根据不同的条件组装不同的SQL。

•对多表关联和复杂SQL查询支持较差,需要自己写SQL,返回后,需要自己将数据组装为POJOo

•不能有效支持存储过程。

•虽然有HQL,但是性能较差。大型互联网系统往往需要优化SQL,而Hibernate不到。

  在当今大型互联网中,灵活、SQL优化,减少数据的传递是最基本的优化方法,显然 Hibernate无法满足我们的要求。这时MyBatis框架诞生了,它提供了更灵活、更方便的方 法,弥补了 Hibernate的这些缺陷。

四、MyBatis

  为了解决Hibernate的不足,一个半自动映射的框架MyBatis应运而生。之所以称它为 半自动,是因为它需要手工匹配提供POJO、SQL和映射关系,而全表映射的Hibernate 只 需要提供POJO和映射关系便可。

  历史上,MyBatis的前身是Apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了 google code,并且改名为 MyBatis02013 11 月迁移到 Github, 所以目前MyBatis是由Github维护的。

  iBatis 一词来源于“internet”和“abatis”的组合,是个基于Java的持久层框架。iBatis 提供的持久层框架包括SQL Maps和DAOCData Access Objects)o它能很好地解决Hibernate 遇到的问题。与Hibernate不同的是,它不单单要我们提供映射文件,还需要我们提供SQL 语句。MyBatis所需要提供的映射文件包含以下三个部分。

  • SQL。
  • 映射规则。
  • POJO。

  在MyBatis里面,你需要自己编写SQL,虽然比Hibernate配置得多,但是MyBatis 以配置动态SQL,这就解决了 Hibernate的表名根据时间变化,不同的条件下列名不一样的 问题。同时你也可以优化SQL,通过配置决定你的SQL映射规则,也能支持存储过程,所 以对于一些复杂的和需要优化性能SQL的查询它更加方便,MyBatis几乎能做到JDBC所能 做到的所有事情。MyBatis具有自动映射功能。换句话说,在注意一些规则的基础上,MyBatis 可以给我们完成自动映射,而无需再写任何的映射规则,这大大提高了开发效率和灵活性。如图1.3所示为MyBatis的0RM映射模型。

 

 

 

  让我们看看如何实现JdbcExample的功能。首先是数据库及其他的基础配置

<?xml version=nl. 0n encoding=nUTF-8,1 ?>
<!DOCTYPE configuration PUBLIC n-//mybatis.org//DTD Config 3.0//EN”
"http://mybatis•org/dtd/mybatis-3-config•dtdn>
<configuration>
  <environments defau11=H deve1opmentn >
    <environment id=ndevelopmentH>
      <transactionManager type=nJDBCf,/>
      <dataSource type=,fPOOLEDn> name=Hdrivern value=f,com.mysql . jdbc . DriverH/> name=nurln value=Hjdbc:mysql://localhost:3306/mybatisM/>
        <property name="username" value="root"/> 
        <property name="password" value="learn"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
  <mapper resource=ncom\learn\mybatis\chapterl\pojo\role.xmln /> </mappers>
</configuration>

  这就是MyBatis的基础配置文件。其次是一个映射文件,也十分简单

 

 

 

  这里我们给出了 SQL,但是并没有给出映射规则,因为这里我们使用的SQL列名和POJO的属性名保持一致,这个时候MyBatis会自动提供映射规则,所以省去了这部分的配置工作。再者,我们还需要一个接口,注意仅仅是接口,而无需实现类.

 

public interface RoleMapper (
  public Role getRole(Long id);
}

 

  为了使用MyBatis,我们还需要建立SqlSessionFactory。

public class MyBatisUtil (
  private static SqlSessionFactory sqlSessionFactory = null;
  public static SqlSessionFactory getSqlSessionFactroy() (
    Inputstream inputstream = null;
    if (sqlSessionFactory == null) (
    try (
      String resource = f,mybatis_config • xmln;
      sqlSessionFactory = new SqlSessionFactoryBuilder().build
      (Resources.getResourceAsStream(resource));
      return sqlSessionFactory;
    ) catch (Exception ex) (
      System.err.printIn(ex.getMessage());
      ex.printStackTrace();
    }
  )
  return sqlSessionFactory;
  }
}

  现在我们可以用MyBatis来实现代码清单1-1的功能了

public class MyBatisExample {
    public static void main(String[] args) (
        SqlSession sqlSession = null;
        try (
             sqlSession =MyBatisUtil.getSqlSessionFactroy().openSession (); 
        RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);         Role role = roleMapper.getRole(1L);         System.err.printIn(nrole_name = >” + role•getRoleName()};
     finally (
        sqlSession.close (); 
      }
    }
  }

 

  这样便完成了 MyBatis的代码编写工作,SQL和映射规则都在XML里面进行了分离,而MyBatis更为灵活。你可以自由书写SQL,定义映射规则。此外,MyBatis提供接口编 程的映射器只需要一个接口和映射文件便可以运行,消除了在iBatis时代需要SqlSession 调度的情况。

五、什么时候用MyBatis

  通过对JDBC、Hibernate和MyBatis的介绍,我们有了一些认识。JDBC的方式在目前 而言极少用到,因为你需要提供太多的代码,操作太多的对象,麻烦不说,还极其容易出 错,所以这不是一种推荐的方式,在实际开发中直接用JDBC的场景也是很少的。

  Hibernate作为较为流行的Java ORM框架,它确实编程简易,需要我们提供映射的规 则,完全可以通过IDE生成,同时无需编写SQL确实开发效率优于MyBatiso此外,它也 提供了缓存、日志、级联等强大的功能,但是Hibernate的缺陷也是十分明显的,多表关联 复杂SQL,数据系统权限限制,根据条件变化的SQLo存储过程等场景使用Hibernate 分不便,而性能又难以通过SQL优化。所以注定了 Hibenate只适用于在场景不太复杂,要 求性能不太苛刻的时候使用。

  如果你需要一个灵活的、可以动态生成映射关系的框架,那么MyBatis确实是一个最 好的选择。它几乎可以代替JDBC,拥有动态列、动态表名,存储过程都支持,同时提供 了简易的缓存、日志、级联。但是它的缺陷是需要你提供映射规则和SQL,所以它的开发 工作量比Hibernate略大一些。

  你需要根据项目的实际情况去选择框架。因为MyBatis具有高度灵活、可优化、易维 护等特点,所以它目前是大型移动互联网项目的首选框架。

  下面各章,我们将分别讨论MyBatis的应用、原理和实践。

 

posted @ 2020-09-02 12:48  跃小云  阅读(188)  评论(0编辑  收藏  举报