持久层框架MyBatis及Hibernate -- softwbc 发布于:2017年12月27日 浏览量:1129  |

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录

原理详解:

        MyBatis应用程序根据XML配置文件创建SqlSessionFactorySqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSessionSqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession

优点:

1、简单易学

       mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用

2、灵活

       mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。

3、解除sql与程序代码的耦合

       通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

4、提供映射标签,支持对象与数据库的orm字段关系映射

5、提供对象关系映射标签,支持对象关系组建维护

6、提供xml标签,支持编写动态sql

缺点:

1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。

2SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。

3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

4、二级缓存机制不佳


1.1      Hibernate

一、Hibernate是对JDBC进一步封装

       原来没有使用Hiberante做持久层开发时,存在很多冗余,如:各种JDBC语句,connection的管理,所以出现了HibernateJDBC封装了一下,我们不用操作数据,直接操作它就行了。

二、我们再从分层的角度来看

       我们知道非常典型的三层架构:表示层,业务层,还有持久层。Hiberante也是持久层的框架,而且持久层的框架还有很多,比如:IBatisNhibernateJDOOJBEJB等等。

三、Hibernate是开源的一个ORM(对象关系映射)框架。

      ORM,即Object-Relational Mapping,它的作用就是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了(把关系数据库的字段在内存中映射成对象的属性)。


 

从上图中,我们可以看出Hibernate六大核心接口,两个主要配置文件,以及他们直接的关系。Hibernate的所有内容都在这了。那我们从上到下简单的认识一下,每个接口进行一句话总结。

1Configuration接口:负责配置并启动Hibernate

2SessionFactory接口:负责初始化Hibernate

3Session接口:负责持久化对象的CRUD操作

4Transaction接口:负责事务

5Query接口和Criteria接口:负责执行各种数据库查询

注意:Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。

Hibernate的优/缺点:

优点:

1、更加对象化

  以对象化的思维操作数据库,我们只需要操作对象就可以了,开发更加对象化。

2、移植性

      因为Hibernate做了持久层的封装,你就不知道数据库,你写的所有的代码都具有可复用性。

3Hibernate是一个没有侵入性的框架,没有侵入性的框架我们称为轻量级框架。

      对比StrutsActionActionForm,都需要继承,离不开StrutsHibernate不需要继承任何类,不需要实现任何接口。这样的对象叫POJO对象。

4Hibernate代码测试方便。

5、提高效率,提高生产力。

缺点:

1、使用数据库特性的语句,将很难调优

2、对大批量数据更新存在问题

3、系统中存在大量的攻击查询功能


1.1  与Hibernate对比

1.1.1       简介

Hibernate:Hibernate是当前最流行的ORM框架之一,对JDBC提供了较为完整的封装。Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL的自动生成和执行。

Mybatis:Mybatis同样也是非常流行的ORM框架,主要着力点在于 POJO 与 SQL 之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定 POJO 。相对Hibernate“O/R”而言,Mybatis 是一种“Sql Mapping”的ORM实现。

1.1.1       开发速度

1.  难易度

Hibernate的真正掌握要比Mybatis困难,Hibernate比mybatis更加重量级一些。

Mybatis框架相对简单很容易上手,但也相对简陋些。

2.  开发工作量

Mybatis需要我们手动编写SQL语句,回归最原始的方式,所以可以按需求指定查询的字段,提高程序的查询效率。

Hibernate也可以自己写SQL语句来指定需要查询的字段,但这样破坏了Hibernate封装以及简洁性。

1.1.2       数据库移植性

Mybatis由于所有SQL都是依赖数据库书写的,所以扩展性,迁移性比较差。

Hibernate与数据库具体的关联都在XML中,所以HQL对具体是用什么数据库并不是很关心。

1.1.3       缓存机制对比

1.  相同点

Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。

2.  不同点

Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。

MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。

3.  两者比较

因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。

1.1.4       总结

相同点

·        Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。


 

  • Hibernate和MyBatis都支持JDBC和JTA事务处理。

 

Hibernate优势

·        Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。

·        Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。

·        Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。

·        Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

Mybatis优势

·        MyBatis可以进行更为细致的SQL优化,可以减少查询字段。

·        MyBatis容易掌握,而Hibernate门槛较高。

1.1  Mapper命名空间

Mapper中的namespace用于绑定dao接口的,即面向接口编程。

当namespace绑定接口后,可以不用写接口实现类,mybatis会通过该绑定自动找到对应要执行的SQL语句(接口中的方法与映射文件中的SQL语句的ID一一对应 )

命名解析:

为了减少输入量,MyBatis 对所有的命名配置元素(包括语句,结果映射,缓存等)使用了如下的命名解析规则:

    1.完全限定名(比如“com.mypackage.MyMapper.selectAllThings”)将被直接查找并且找到即用。

    2.短名称(比如“selectAllThings”)如果全局唯一也可以作为一个单独的引用。如果不唯一,有两个或两个以上的相同名称(比如“com.foo.selectAllThings ”和“com.bar.selectAllThings”),那么使用时就会收到错误报告说短名称是不唯一的,这种情况下就必须使用完全限定名。

1.2      动态SQL# $

MyBatis采用功能强大的基于OGNLObject-Graph Navigation Language,对象图导航语言)的表达式来完成动态SQL

动态SQLmybatis的强大特性之一,mybatis在对sql语句进行预编译之前,会对sql进行动态解析,解析为一个BoundSql对象,也是在此处对动态sql进行处理。下面让我们先来熟悉下mybatis#{}${}的用法:

  在动态sql解析过程,#{}${}的效果是不一样的:

#{ }解析为一个JDBC预编译语句(prepared statement)的参数标记符。

如以下sql语句

select*fromuserwhere name = #{name};

会被解析为:

select*fromuserwhere name = ?;

可以看到#{}被解析为一个参数占位符?。

${ }仅仅为一个纯碎的string替换,在动态SQL解析阶段将会进行变量替换

如以下sql语句:

select*fromuserwhere name = ${name};

当我们传递参数“sprite”时,sql会解析为:

select*fromuserwhere name = "sprite";

可以看到预编译之前的sql语句已经不包含变量name了。

综上所得, ${ } 的变量的替换阶段是在动态 SQL 解析阶段,而 #{ }的变量的替换是在 DBMS 中。

#{}${}的区别可以简单总结如下:

·        #{}将传入的参数当成一个字符串,会给传入的参数加一个双引号

·        ${}将传入的参数直接显示生成在sql中,不会添加引号

·        #{}能够很大程度上防止sql注入,${}无法防止sql注入

  ${}在预编译之前已经被变量替换了,这会存在sql注入的风险。如下sql

select*from ${tableName} where name = ${name}

  如果传入的参数tableNameuser; delete user; --,那么sql动态解析之后,预编译之前的sql将变为:

select*fromuserdeleteuser-- where name = ?;

  --之后的语句将作为注释不起作用,顿时我和我的小伙伴惊呆了!!!看到没,本来的查询语句,竟然偷偷的包含了一个删除表数据的sql,是删除,删除,删除!!!重要的事情说三遍,可想而知,这个风险是有多大。

·        ${}一般用于传输数据库的表名、字段名等

·        能用#{}的地方尽量别用${}

  进入正题,通过上面的分析,相信大家可能已经对如何动态调用表名和字段名有些思路了。示例如下:

<select id="getUser" resultType="java.util.Map" parameterType="java.lang.String" statementType="STATEMENT">

select ${columns} from ${tableName}where COMPANY_REMARK = ${company}

</select>

要实现动态调用表名和字段名,就不能使用预编译了,需添加statementType="STATEMENT" 

statementType:STATEMENT(非预编译),PREPARED(预编译)或CALLABLE中的任意一个,这就告诉MyBatis分别使用Statement,PreparedStatement或者CallableStatement。默认:PREPARED。这里显然不能使用预编译,要改成非预编译。

其次,sql里的变量取值是${xxx},不是#{xxx}

  因为${}是将传入的参数直接显示生成sql,如${xxx}传入的参数为字符串数据,需在参数传入前加上引号,如:

        String name = "sprite";

        name = "'" + name + "'";

  mybatis动态调用表名和字段名,还可以应用于日志的收集上,如数据库的日志表,每隔一个月动态建一个日志表,表名前缀相同(如log_201610,log_201611等),这样实现日志的分月分表存储,方便日志的分析。

1.3      JDBCType

1.   JDBC Type           Java Type  

2.   CHAR                String  

3.   VARCHAR             String  

4.   LONGVARCHAR         String  

5.   NUMERIC             java.math.BigDecimal  

6.   DECIMAL             java.math.BigDecimal  

7.   BIT             boolean  

8.   BOOLEAN             boolean  

9.   TINYINT             byte  

10.  SMALLINT            short  

11.  INTEGER             int  

12.  BIGINT              long  

13.  REAL                float  

14.  FLOAT               double  

15.  DOUBLE              double  

16.  BINARY              byte[]  

17.  VARBINARY           byte[]  

18.  LONGVARBINARY               byte[]  

19.  DATE                java.sql.Date  

20.  TIME                java.sql.Time  

21.  TIMESTAMP           java.sql.Timestamp  

22.  CLOB                Clob  

23.  BLOB                Blob  

24.  ARRAY               Array  

25.  DISTINCT            mapping of underlying type  

26.  STRUCT              Struct  

27.  REF                         Ref  

28.  DATALINK            java.net.URL[color=red][/color]  



关于我们 |  广告服务 |  联系我们 |  网站声明

Copyright © 2015 - 2016 DISPACE.NET |  使用帮助 |  关于我们 |  投诉建议

京ICP备13033209号-2