myibats原理深入理解总结

来源:互联网 发布:软件开发教材 编辑:程序博客网 时间:2024/06/08 07:59
1.MyBatis初始化的过程,就是创建 Configuration对象的过程

MyBatis的初始化可以有两种方式:

  • 基于XML配置文件:基于XML配置文件的方式是将MyBatis的所有配置信息放在XML文件中,MyBatis通过加载并XML配置文件,将配置文信息组装成内部的Configuration对象
  • 基于Java API:这种方式不使用XML配置文件,需要MyBatis使用者在Java代码中,手动创建Configuration对象,然后将配置参数set 进入Configuration对象中 
 mybatis使用过程:mybatis初始化 -->创建SqlSession -->执行SQL语句 返回结果三个过程
2.解析配置文件过程
处理properties节点->处理typealiases节点->处理插件->处理objectfactory->处理
objectWrapperFactory->处理settings->处理environment->处理database->处理typehandler->处理mapper(核心内容,加载相应的配置文件,分析sql语句)。

3.mybatis一级缓存
SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否在缓存中,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果; statementId  + rowBounds  + 传递给JDBC的SQL  + 传递给JDBC的参数值
当创建了一个SqlSession对象时,MyBatis会为这个SqlSession对象创建一个新的Executor执行器,而缓存信息就被维护在这个Executor执行器中,MyBatis将缓存和对缓存相关的操作封装成了Cache接口中。

a. MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

b. 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;

c. 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;

d.SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

cache配置:

  1. <cache eviction="FIFO" flushInterval="60000" size="512"   
  2. readOnly="true"/>  

4.MyBatis支持配置多个dataSource 环境,可以将应用部署到不同的环境上,如DEV(开发环境),TEST(测试换将),QA(质量评估环境),UAT(用户验收环境),PRODUCTION(生产环境),可以通过将默认environment值设置成想要的 environment id 值。

  1. <environments default="development">  
  2.     <environment id="development">  
  3.       <transactionManager type="JDBC" />  
  4.       <dataSource type="POOLED">  
  5.         <property name="driver" value="${jdbc.driverClassName}" />  
  6.         <property name="url" value="${jdbc.url}" />  
  7.         <property name="username" value="${jdbc.username}" />  
  8.         <property name="password" value="${jdbc.password}" />  
  9.       </dataSource>  
  10.     </environment>  
  11.     <environment id="production">  
  12.       <transactionManager type="MANAGED" />  
  13.       <dataSource type="JNDI">  
  14.         <property name="data_source" value="java:comp/jdbc/MyBatisDemoDS" />  
  15.       </dataSource>  
  16.     </environment>  
  17.   </environments>  

5.dataSource的类型可以配置成其内置类型之一,如 UNPOOLED,POOLED,JNDI。
    - l  如果将类型设置成UNPOOLED,MyBatis会为每一个数据库操作创建一个新的连接,并关闭它。该方式适用于只有小规模数量并发用户的简单应用程序上。
    - l   如果将属性设置成POOLED,MyBatis会创建一个数据库连接池,连接池中的一个连接将会被用作数据库操作。一旦数据库操作完成,MyBatis会将此连接返回给连接池。在开发或测试环境中,经常使用此种方式。
    - 如果将类型设置成JNDI,MyBatis从在应用服务器向配置好的JNDI数据源dataSource获取数据库连接。在生产环境中,优先考虑这种方式。

6.ResultMaps被用来 将SQL SELECT语句的结果集映射到 JavaBeans的属性中。我们可以定义结果集映射ResultMaps并且在一些SELECT语句上引用resultMap。 <association property="address" resultMap="AddressResult" />  用来作为嵌套的resultmap。MyBatis可以使用RowBounds逐页加载表数据。RowBounds对象可以使用offset和limit参数来构建。参数o
ffset表示开始位置,而limit表示要取的记录的数目。MyBatis提供了ResultHandler插件形式允许我们以任何自己喜欢的方式处理结果集ResultSet。
<mybatis:scan>元素将在特定的以逗号分隔的包名列表中搜索映射器Mapper接口。

7.N+1问题:嵌套查询就一个(即resultMap 内部就一个association标签),现查询的结果集返回条数为N,那么关联查询语句将会被执行N次,加上自身返回结果集查询1次,共需要访问数据库N+1次。如果N比较大的话,这样的数据库访问消耗是非常大的!所以使用这种嵌套语句查询的使用者一定要考虑慎重考虑,确保N值不会很大。Mybatis还支持一种嵌套结果的查询:即对于一对多,多对多,多对一的情况的查询,Mybatis通过联合查询,将结果从数据库内一次性查出来,然后根据其一对多,多对一,多对多的关系和ResultMap中的配置,进行结果的转换,构建需要的对象。
  1. resultMap type="com.foo.bean.BlogInfo" id="BlogInfo">  
  2.     <id column="blog_id" property="blogId"/>  
  3.     <result column="title" property="title"/>  
  4.     <association property="author" column="blog_author_id" javaType="com.foo.bean.Author">  
  5.         <id column="author_id" property="authorId"/>  
  6.         <result column="user_name" property="userName"/>  
  7.         <result column="password" property="password"/>  
  8.         <result column="email" property="email"/>  
  9.         <result column="biography" property="biography"/>  
  10.     </association>  
  11.     <collection property="posts" column="blog_post_id" ofType="com.foo.bean.Post">  
  12.         <id column="post_id" property="postId"/>  
  13.         <result column="blog_id" property="blogId"/>  
  14.         <result column="create_time" property="createTime"/>  
  15.         <result column="subject" property="subject"/>  
  16.         <result column="body" property="body"/>  
  17.         <result column="draft" property="draft"/>  
  18.     </collection>  
  19.       
  20. </resultMap>  
  21. <select id="queryAllBlogInfo" resultMap="BlogInfo">  
  22.     SELECT   
  23.      B.BLOG_ID,  
  24.      B.TITLE,  
  25.      B.AUTHOR_ID AS BLOG_AUTHOR_ID,  
  26.      A.AUTHOR_ID,  
  27.      A.USER_NAME,  
  28.      A.PASSWORD,  
  29.      A.EMAIL,  
  30.      A.BIOGRAPHY,  
  31.      P.POST_ID,  
  32.      P.BLOG_ID   AS BLOG_POST_ID ,  
  33.   P.CREATE_TIME,  
  34.      P.SUBJECT,  
  35.      P.BODY,  
  36.      P.DRAFT  
  37. FROM BLOG B  
  38. LEFT OUTER JOIN AUTHOR A  
  39.   ON B.AUTHOR_ID = A.AUTHOR_ID  
  40. LEFT OUTER JOIN POST P  
  41.   ON P.BLOG_ID = B.BLOG_ID  
  42. </select>  
执行过程:根据表的对应关系,进行join操作,获取到结果集;据结果集的信息和BlogInfo 的resultMap定义信息,对返回的结果集在内存中进行组装、赋值,构造BlogInfo;返回构造出来的结果List<BlogInfo> 结果。

8.当我们需要创建SqlSession对象并需要执行SQL语句时,这时候MyBatis才会去调用dataSource对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。当 <dataSource>的type属性被配置成了”UNPOOLED”,MyBatis首先会实例化一个UnpooledDataSourceFactory工厂实例,然后通过.getDataSource()方法返回一个UnpooledDataSource实例对象引用,我们假定为dataSource。使用UnpooledDataSource的getConnection(),每调用一次就会产生一个新的Connection实例对象。获得connection是通过DriverManager.getConnection()返回新的java.sql.Connection实例。MyBatis将连接池中的PooledConnection分为两种状态: 空闲状态(idle)和活动状态(active),这两种状态的PooledConnection对象分别被存储到PoolState容器内的idleConnectionsactiveConnections两个List集合中
先看是否有空闲(idle)状态下的PooledConnection对象,如果有,就直接返回一个可用的PooledConnection对象;查看活动状态的PooledConnection池activeConnections是否已满;如果没有满,则创建一个新的PooledConnection对象,然后放到activeConnections池中,然后返回此PooledConnection对象;最先进入activeConnections池中的PooledConnection对象是否已经过期:如果已经过期,从activeConnections池中移除此对象,然后创建一个新的PooledConnection对象,添加到activeConnections中,然后将此对象返回;否则线程等待。

怎样实现Connection对象调用了close()方法,而实际是将其添加到连接池中:这是要使用代理模式,为真正的Connection对象创建一个代理对象,代理对象所有的方法都是调用相应的真正Connection对象的方法实现。当代理对象执行close()方法时,要特殊处理,不调用真正Connection对象的close()方法,而是将Connection对象添加到连接池中。


9.mybats加载流程

1. 调用SqlSessionFactoryBuilder对象的build(inputStream)方法;

2. SqlSessionFactoryBuilder会根据输入流inputStream等信息创建XMLConfigBuilder对象;

3. SqlSessionFactoryBuilder调用XMLConfigBuilder对象的parse()方法;

4. XMLConfigBuilder对象返回Configuration对象;

5. SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;

6. SqlSessionFactoryBuilder返回 DefaultSessionFactory对象给Client,供Client使用。


10.MyBatis的事务Transaction的接口设计以及其不同实现JdbcTransaction  ManagedTransaction
使用JDBC的事务管理机制:即利用java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等
使用MANAGED的事务管理机制:这种机制MyBatis自身不会去实现事务管理,而是让程序的容器如(JBOSS,Weblogic)来实现对事务的管理,相应的commit,rollback代码中没有具体的实现,而是交由容器去执行。
MyBatis初始化解析<environment>节点时,会根据type来创建相应的事物机制。
如果我们使用MyBatis构建本地程序,即不是WEB程序,若将type设置成"MANAGED",那么,我们执行的任何update操作,即使我们最后执行了commit操作,数据也不会保留,不会对数据库造成任何影响。因为我们将MyBatis配置成了“MANAGED”,即MyBatis自己不管理事务,而我们又是运行的本地程序,没有事务管理功能,所以对数据库的update操作都是无效的。

11.mybatis的核心部件
SqlSession            作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
Executor              MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
StatementHandler   封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
ParameterHandler   负责对用户传递的参数转换成JDBC Statement 所需要的参数,
ResultSetHandler    负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
TypeHandler          负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatement   MappedStatement维护了一条<select|update|delete|insert>节点的封装, 
SqlSource            负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
BoundSql             表示动态生成的SQL语句以及相应的参数信息
Configuration        MyBatis所有的配置信息都维持在Configuration对象之中。
Executor主要功能:

(1、根据传递的参数,完成SQL语句的动态解析,生成BoundSql对象,供StatementHandler使用;

(2、为查询创建缓存,以提高性能(具体它的缓存机制不是本文的重点,我会单独拿出来跟大家探讨,感兴趣的读者可以关注我的其他博文);

(3、创建JDBCStatement连接对象,传递给StatementHandler对象,返回List查询结果。


12.myibats缓存

一级缓存是Session会话级别的缓存,位于表示一次数据库会话的SqlSession对象之中,又被称之为本地缓存。一级缓存是MyBatis内部实现的一个特性,用户不能配置,默认情况下自动支持的缓存,用户没有定制它的权利(不过这也不是绝对的,可以通过开发插件对它进行修改);二级缓存是Application应用级别的缓存,它的是生命周期很长,跟Application的声明周期一样,也就是说它的作用范围是整个Application应用。

一个SqlSession对象会使用一个Executor对象来完成会话操作,MyBatis的二级缓存机制的关键就是对这个Executor对象做文章。如果用户配置了"cacheEnabled=true",那么MyBatis在为SqlSession对象创建Executor对象时,会对Executor对象加上一个装饰者:CachingExecutor,这时SqlSession使用CachingExecutor对象来完成操作请求。CachingExecutor对于查询请求,会先判断该查询请求在Application级别的二级缓存中是否有缓存结果,如果有查询结果,则直接返回缓存结果;如果缓存中没有,再交给真正的Executor对象来完成查询操作,之后CachingExecutor会将真正Executor返回的查询结果放置到缓存中,然后在返回给用户。MyBatis自己定义的二级缓存实现;你也可以通过实现org.apache.ibatis.cache.Cache接口自定义缓存;也可以使用第三方内存缓存库,如Memcached
MyBatis并不是简单地对整个Application就只有一个Cache缓存对象,它将缓存划分的更细,即是Mapper级别的,为每一个Mapper分配一个Cache缓存对象(使用<cache>节点配置);多个Mapper共用一个Cache缓存对象(使用<cache-ref>节点配置);Mapper中配置了<cache>,并且为此Mapper分配了Cache对象,这并不表示我们使用Mapper中定义的查询语句查到的结果都会放置到Cache对象之中,我们必须指定Mapper中的某条选择语句是否支持缓存,即如下所示,在<select> 节点中配置useCache="true"Mapper才会对此Select的查询支持缓存特性
使用二级缓存条件:

   1.  MyBatis支持二级缓存的总开关:全局配置变量参数   cacheEnabled=true

   2. 该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效

   3. 该select语句的参数 useCache=true

MyBatis使用了二级缓存,并且你的Mapperselect语句也配置使用了二级缓存,那么在执行select查询的时候,MyBatis会先从二级缓存中取输入,其次才是一级缓存,最后才是数据库;对于某些使用了 join连接的查询,如果其关联的表数据发生了更新,join连接的查询由于先前缓存的原因,导致查询结果和真实数据不同步;一个Mapper中定义的增删改查操作只能影响到自己关联的Cache对象,Mapper之间的缓存关系比较松散,相互关联的程度比较弱。

13.DefaultSqlSession实现了SqlSession接口,里面有各种各样的SQL执行方法,主要用于SQL操作的对外接口,它会的调用执行器来执行实际的SQL语句。对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
mybatis的拦截器只能代理指定的四个类:ParameterHandler、ResultSetHandler、StatementHandler以及Executor。 
通过拦截ResultSetHandler修改接口返回类型; 
通过拦截StatementHandler修改mybatis框架的分页机制; 
通过拦截Executor查看mybatis的sql执行过程等等。

这些方法在MyBatis的一个操作(新增,删除,修改,查询)中都会被执行到,执行的先 后顺序是Executor,ParameterHandler,ResultSetHandler,StatementHandler(其中 ParameterHandler和ResultSetHandler的创建是在创建StatementHandler[3个可用的实现类 CallableStatementHandler,PreparedStatementHandler,SimpleStatementHandler] 的时候,其构造函数调用的[这3个实现类的构造函数其实都调用了父类BaseStatementHandler的构造函数])。

这4个方法实例化了对应的对象之后,都会调用interceptorChain的pluginAll方法,InterceptorChain的pluginAll刚才已经介绍过了,就是遍历所有的拦截器,然后调用各个拦截器的plugin方法。 注意:拦截器的plugin方法的返回值会直接被赋值给原先的对象


14.拦截器的基本使用
这个拦截器拦截Executor接口的update方法(其实也就是SqlSession的新增,删除,修改操作),所有执行executor的update方法都会被该拦截器拦截到。
@Intercepts({@Signature(  type= Executor.class,  method = "update",  args = {MappedStatement.class,Object.class})})public class ExamplePlugin implements Interceptor {  public Object intercept(Invocation invocation) throws Throwable {    return invocation.proceed();  }  public Object plugin(Object target) {    return Plugin.wrap(target, this);  }  public void setProperties(Properties properties) {  }}
配置拦截器:
<plugins>    <plugin interceptor="org.format.mybatis.cache.interceptor.ExamplePlugin"></plugin></plugins>

15.mybatis启用了预编译功能,在sql执行前,会先将上面的sql发送给数据库进行编译,执行时,直接使用编译好的sql,替换占位符“?”就可以了。因为sql注入只能对编译过程起作用,所以这样的方式就很好地避免了sql注入的问题。在框架底层,是jdbc中的PreparedStatement类在起作用.。在mybatis中,”${xxx}”这样格式的参数会直接参与sql编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式,所以,这样的参数需要我们在代码中手工进行处理来防止注入。 在编写mybatis的映射语句时,尽量采用“#{xxx}”这样的格式。

16.myibats一次数据操作过程
1、初始化SqlSessionFactory,默认实现是DefultSqlSessionFactory,这个一般是一个应用一个实例就够了,例如单例模式;
2、通过SqlSessionFactory获得SqlSession,默认实现是DefaultSqlSession,这个应用范围是一次数据库操作,可以简单理解为JDBC操作的Connection,数据库操作执行完,需要调用close方法手动关闭连接;
3、通过SqlSession可以直接执行数据库操作,这个接口已经定义了许多的常用的操作,例如查询一个对象,查询列表数据,更新操作等等,这里先不做详细介绍。现在MyBatis经常就是跟Spring进行结合使用,MyBatis比ibatis最显著的一个升级,应该就是MyBatis可以不用写Dao接口的实现类,直接通过SqlSession.getMapper(Class clz)方法获得Dao接口的代理类(通过Spring的IOC框架管理Dao接口,实际上依赖注入的时候也是通过MyBatis内部的该方法获得实际的Dao代理对象);
4、生成的Dao接口的代理类是通过MapperProxy.newMapperProxy(Class daoInterface,SqlSession sqlSession)生成的,这个是个静态方法,实现原理是使用了JDK的动态代理机制。SO,MapperProxy是实现了InvocationHandler的类,执行数据库操作的入口就是MapperProxy的invoke方法触发的,再看下该方法,可以知道最终是通过MapperMethod.execute(Object[] params)执行数据库操作;
5、在MapperMethod的构造方法里面,会进行被代理接口的执行的那个方法的信息的读取,比如方法名称(以便后来对应到具体的配置文件的具体语句sqlId)、方法参数(以便对具体的sql语句进行参数替换)等等。然后看下execute方法,根据刚刚初始化的配置信息,判断该次执行是select还是update或者delete操作,转了半天发现,最终还是调用了SqlSession的select、update等方法;
6、好吧,现在回到DefaultSqlSession,以一次查询为例子,最终执行的方法是selectList(String statement, Object parameter, RowBounds rowBounds),参数分别是接口对应的方法名称(会对应到具体的sql上),接口方法参数,返回记录范围(一般没啥用了,分页啥的都是分页语句实现了,不会把所有数据都查出来然后再进行数据范围的筛选)。然后发现最终执行查询的是Executor的query方法,这个执行器是DefaultSqlSession的一个成员变量,默认实现是SimpleExecutor,继承了BaseExecutor,query方法就是在该基类中的。
7、现在到BaseExecutor的query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)方法里面来,这个是执行查询的入口,这里的第一个参数要说明下,MapperStatement,直接翻译就是映射声明,是对映射信息的封装对象,用来存储记录要映射的sql语句的id、sql语句、传参等等,这个类有个比较重要的方法就是getBoundSql(Object parameterObject),也就是获取绑定的sql,如果要开发一个分页的插件,要利用反射机制,对这个BoundSql进行修改。
8、再回到BaseExecutor的query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)方法里面来,可以看到最终是调用了内部的query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)方法,在该方法里面发现,如果这次查询是有缓存,则只需从缓存里面取出结果集返回,那这次的查询就结束了。如果没有缓存,那就从数据库里面查询,层层跟踪下去,发现执行的是一个抽象方法doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql),这个方法是由子类实现的,也就是说,我们终于可以回到SimpleExecutor了;
9、回到SimpleExecutor的doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql),在这个方法里面,会选择具体的执行StatementHandler,这是个接口,是通过Configuration的newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)方法获取具体的处理器,并且根据配置文件中的插件,加工StatementHandler,实际上使用的也是JDK的代理机制,如果有添加插件的话,这个StatementHandler也是个代理对象(最常见的分页插件);
10、介绍下StatementHandler,看见Statement,想必有用过java的JDBC操作的都很熟悉这个名字,那实际上Statementhandler就是MyBatis的自己的Statement,用来对数据库进行操作用的。这个接口的是实现类有5个:RoutingStatementHandler,SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler,BaseStatementHandler。
    - RoutingStatementHandler:StatementHandler的路由选择,根据配置文件里面的信息,判断具体选择SimpleStatementHandler,PreparedStatementHandler,CallableStatementHandler三个里面的哪个StatementHandler,它有个成员变量StatemenHandler delegate,这个delegate就是选择的具体的StatementHandler;
    - SimpleStatementHandler:即使用JDBC的Statement进行数据库操作;
    - PreparedStatementHandler:即使用JDBC的PreparedStatement进行数据库操作,一般的配置都是使用这个,预处理语句进行数据库操作;
    - CallableStatementHandler:即使用JDBC的CallableStatement进行数据库操作;
    - BaseStatementHandler:SimpleStatementHandler、PreparedStatementHandler、CallableStatementHandler的父类。
11、现在获取了的具体的StatementHandler后,我们以常用的PreparedStatementHandler为例,然后就是根据配置的信息,参数等对这个handler内部的PreparedStatement进行操作了,也就是JDBC中我们经常做的参数set啥的了,这里就不做介绍了,可以认为StatementHandler就是对JDBC的Statement以符合MyBatis配置的要求进行一次包装,最终对数据库进行操作的,还是JDBC中的Statement(PreparedStatement继承自Statement)。
12、数据库操作就执行结束了,然后就是关闭连接了

17.jdbc,ibats和hiberate效率比较

从映射角度来看

映射sql语句的输入输出参数(ibats)

对数据库表结构来进行映射(hiberate)

    第一,  在进行查询、插入、删除的操作,JDBC>ibatis>hibernate【>代表效率好,下同】。原因:首先ibatis和hibernate框架要进行对应处理【bean对象与数据库的字段的对应处理】,所以ibatis和hibernate框架效率比jdbc慢;而hibernate比ibatis慢的原因是hibernate要处理持久化的操作而ibatis框架没有处理这方面的操作。

       第二,  在进行更新的操作,JDBC>ibatis>hibernate虽然说顺序没有发生变化,但是我们在处理更新的时候,要知道这三者效率的也是上面情况的影响所以效率不同,但是对于hibernate进行更新的时候要注意的时候,用它在更新的时候它要首先把数据查询出来,之后在更新。这点是我们主要的,而且这样所以更加的影响了它的执行效率。所以我们通常说hibernate框架对大数据量更新操作是很影响效率的,就是因为它要先查询在更新,等于做了两步操作。所以我们在选择做设计的时候,这点一定要考虑清楚,如果业务需求中有大量的更新操作,那么我们选择hibernate框架的时候就要好好考虑了。

0 0
原创粉丝点击