myBatis性能优化【转】
官方doc文档 http://www.mybatis.org/mybatis-3/configuration.html#settings
最近测试发现个myBatis 有个比较严重的性能问题, 描述如下:
1. define a bean class
public class Bean {
private int id;
private String desc;
private long price;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public long getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
}
2. 如果在这个Bean定义中,存在一个属性没有 Getter方法 在运行过程中, Mybatis 会表现为把 class Bean 确定成一个ComplexAccessPlan的对象。那么, Mybatis对Bean对象填充SQL执行后的返回结果会造成比较严重的性能问题。 复杂对象填充Bean的结果在性能上表现比较差一点。 这个性能差异随着需要设置属性数量的增加, 性能成正比的下降。 目前我测试的结果是10个属性情况下影响大约 5-6%的执行时间, 如果属性增加到 84个(中文站的offer对象),他的性能会导致超过30%的下降。 具体的原因, 我会如下解释:
com.mybatis.sqlmap.engine.accessplan.AccessPlanFactory Line 60
if (bytecodeEnhancementEnabled) {
try {
plan = new EnhancedPropertyAccessPlan(clazz, propertyNames);
} catch (Throwable t) {
try {
plan = new PropertyAccessPlan(clazz, propertyNames);
} catch (Throwable t2) {
plan = new ComplexAccessPlan(clazz, propertyNames);
}
}
}
com.mybatis.common.beans.ClassInfo Line256
public Method getGetter(String propertyName) {
Method method = (Method) getMethods.get(propertyName);
if (method == null) {
throw new ProbeException("There is no READABLE property named '" + propertyName + "' in class '" + className + "'");
}
return method;
}
class EnhancedPropertyAccessPlan/PropertyAccessPlan call com.mybatis.common.beans.ClassInfo.getGetter(String) that cause an exception when a bean have no Getter method, AccessPlan object choose ComplexAccessPlan.
3. 根据以上的代码, 我们还可以得出如下结论(这是我给MYBATIS开发团队的邮件部分, 不翻译:)):
IBtatis automatic decide a simple bean that property have no Getter method to be Complex type. Mybatis does not prompt any warning enhancementEnable option will be skipped. I think these mybatis exception handling is not smooth. and If user's bean loose some Getter method, a common user does not know why mybatis performance become bad.
就是一个对象由于Getter方法的缺失, Mybatis把这个对象的当做复杂对象, 从而, 导致enhancementEnable=true(bean对象字节增加功能, 有兴趣的同学可以看看CGLIB中BulkBean的使用)的定义失去了任何作用, 进一步导致MYBATIS的性能下降。
针对我们发现的问题, 我们建议如下解决问题:
1. 任何被Mybatis 使用的对象属性必须定义完整的Setter/Getter方法
2. 避免使用自定义类型的对象属性
3. 如果部分属性需要被适当处理后才能使用的, 比如表中有一个字段price, 但是我们需要使用的是Money对象, 请按如下方式使用。primitivePrice作为数据库使用的属性, price作为应用程序使用的属性。
public class Bean {
private Money price = null;
private long primitivePrice;
public Money getPrice() {
if (price == null) {
this.price = new Money(0, 0);
this.price.setCent(primitivePrice);
}
return price;
}
public void setPrice(Money price) {
if (price == null) {
this.price = new Money(0, 0);
} else {
this.price = price;
}
this.primitivePrice = price.getCent();
}
public void setPrimitivePrice(long price) {
this.primitivePrice = price;
}
public long getPrimitivePrice() {
return this.primitivePrice ;
}
}
======================================================================
Mybatis on Oracle的性能优化
我们先主要看2个参数
1.defaultRowPrefetch of oracle
2.enhancementEnabled of Mybatis
环境
1. Java HotSpot(TM) Server VM (build 1.5.0_12-b04, mixed mode)
Java HotSpot(TM) Server VM (build 1.6.0_05-b13, mixed mode)
2. Intel(R) Core(TM)2 CPU T7400 @ 2.16GHz L2 4M
3. JVM OPTION -Xms512m -Xmx1024m -XX:PermSize=96m
从数据库中读取10000行, 5列数据情况, Java Bean对象大约不到100个属性。循环20次, 外加5次的赃数据。
A. defaultRowPrefetch=default enhancementEnabled=false/true 754ms/743ms
B. defaultRowPrefetch=50 enhancementEnabled=false/true 389ms/382ms
C. defaultRowPrefetch=100 enhancementEnabled=false/true 319ms/319ms
D. defaultRowPrefetch=200 enhancementEnabled=false/true 277ms/274ms
E. defaultRowPrefetch=500 enhancementEnabled=false/true 251ms/250ms
F. defaultRowPrefetch=1000 enhancementEnabled=false/true 242ms/238ms
G. defaultRowPrefetch=1000 enhancementEnabled=true 237ms(JAVA6)
H. defaultRowPrefetch=200 enhancementEnabled=true 271MS(JAVA6)
总结以上情况, 在数据行比较多的情况下, defaultRowPrefetch值的提高, 对于性能的影响是显著的, 但是, 这个提升是牺牲很多内存为代价的, 因此, 如果过高的defaultRowPrefetch值会导致内存比较紧张。 另外值得说明的是, 在一样的参数前提下, JAVA6对于性能还是有一定的提升的。对于比较大的查询, defaultRowPrefetch经验值应该是200还是合理的。 另外, 对于enhancementEnabled选项带来的收益, 相对来说比较少。 但是,对于高压力的系统, 这是无IO等待下情况的代码执行提高这些是非常值。
以上的测试数据列数比较少, 因此在JAVA BEAN的建立上是非常的节约时间的, 我们看看在差不多100个属性的填充下的性能表现, 我们已经知道了defaultRowPrefetch带来收益的经验值。 因此, 我们设置defaultRowPrefetch=200.
A. defaultRowPrefetch=200 enhancementEnabled=false 1736ms
B. defaultRowPrefetch=200 enhancementEnabled=true 1721ms
C. defaultRowPrefetch=50 enhancementEnabled=true 1866ms
OK, enhancementEnabled继续表明对性能的提升作用很小, 但是列的数据大小对性能的影响是非常大的。 但是, 我们无法确定这个时间是消耗在Java Bean 填充上 还是列读取上。Mybatis没有具体的办法测试。 不过, 在减少结果参数说明的情况下,性能能得到明显的提升, 我们还是可以断定, JAVA BEAN的被声明成结果映射的时候, 尽量减少结果映射的列,可以获得很高性能的提升。 因此, 使用Mybatis操作大量的数据的表, 建议只映射应该获取到的数据, 而不是全部的列。 select * from db where... 你可以取需要的列到java bean. 总而言之: select * from db where... 这样的形式对性能影响比 把所有的列映射到Java Bean 来的小! set bean property + ResultSet.getXXX(int index)的操作消耗了大部分的性能。
一些代码片段:
数据原的定义
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:oracle:thin:@10.0.0.1:1521:test</value>
</property>
<property name="properties">
<props>
<prop key="user">test</prop>
<prop key="password">test</prop>
<prop key="defaultRowPrefetch">50</prop>
</props>
</property>
</bean>
为单个SQL查询定义defaultRowPrefetch, 在Mybatis的定义中为fetchSize
<select id="MS-FIND-PublishedOffers-By-MemberId-Paged" resultMap="RM-OfferResult" fetchSize="200">
CGLIB增强定义
<settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="false" maxRequests="3000" maxSessions="3000" maxTransactions="3000" useStatementNamespaces="false"/>
转
根据Ibatis手册上配置参数说明:
|
参数名称 |
参数说明 |
|
cacheModelsEnabled |
是否启动ibatis中的缓存功能。 |
|
enhancementEnabled |
是否需要POJO启动Java字节码增强功能,可以提升getter/setter的调用效能避免Java反射所带来的性能开销。 |
|
lazyLoadingEnabled |
是否同时Lazy Loading带来极大的性能提升。 |
|
useStatementNamespaces |
是否使用 domain xml 文件中 namespace 别名配置。 |
|
maxRequests |
最大并发请求数(Statemetn数)。 |
|
maxTransactions |
最大并发事务数 |
|
maxSessions |
最大Session数,当前最大允许的并发 SqlMapCliect数 |
|
maxSessions |
须界于 maxTransactions和maxRequests之间进行配置 |
根据自己的多次实践证明,发现这些配置参数的选择与数值将对系统的影响是很大的。
经过多次摸索,按照以下配置参数进行配置可以将ibatis的性能进行提升。仅供参数,还需要根据您自己的实 际情况来界定。
具体配置参数如下:
<sqlMapConfig>
<settings cacheModelsEnabled="true"
lazyLoadingEnabled="true"
enhancementEnabled="true"
errorTracingEnabled="true"
maxSessions="1024"
maxTransactions="512"
maxRequests="2048"
useStatementNamespaces="true" />
myBatis性能优化【转】的更多相关文章
- mybatis性能优化之降低数据库连接
做性能优化的最重要的功能就是降低数据库的交互.非常多程序猿一般在开发的时候仅仅考虑简单的实现功能,无论业务简单复杂,仅仅要实现即可. mybatis有个重要的功能就是考虑在联合查询时技巧: <? ...
- Mybatis动态sql及性能优化-3
内容简介 1.回顾 2.动态sql 3.性能优化 懒加载机制 一级缓存 二级缓存 一.回顾 1.config文件常用标签 properties标签:引入外部properties文件资源. settin ...
- Spring:利用PerformanceMonitorInterceptor来协助应用性能优化
前段时间对公司产品做性能优化,如果单依赖于测试,进度就会很慢.所以就通过对代码的方式来完成,并以此来加快项目进度.具体的执行方案自然就是要知道各个业务执行时间,针对业务来进行优化. 因为项目中使用了S ...
- 15套java架构师、集群、高可用、高可扩展、高性能、高并发、性能优化、Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程
* { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩展. ...
- 15套java互联网架构师、高并发、集群、负载均衡、高可用、数据库设计、缓存、性能优化、大型分布式 项目实战视频教程
* { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...
- java架构师负载均衡、高并发、nginx优化、tomcat集群、异步性能优化、Dubbo分布式、Redis持久化、ActiveMQ中间件、Netty互联网、spring大型分布式项目实战视频教程百度网盘
15套Java架构师详情 * { font-family: "Microsoft YaHei" !important } h1 { background-color: #006; ...
- 15套java架构师、集群、高可用、高可扩 展、高性能、高并发、性能优化Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm大型分布式项目实战视频教程
* { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...
- 网站性能优化小结和spring整合redis
现在越来越多的地方需要非关系型数据库了,最近网站优化,当然从页面到服务器做了相应的优化后,通过在线网站测试工具与之前没优化对比,发现有显著提升. 服务器优化目前主要优化tomcat,在tomcat目录 ...
- 推荐:Java性能优化系列集锦
Java性能问题一直困扰着广大程序员,由于平台复杂性,要定位问题,找出其根源确实很难.随着10多年Java平台的改进以及新出现的多核多处理器,Java软件的性能和扩展性已经今非昔比了.现代JVM持续演 ...
随机推荐
- bool([x]) 将x转换为Boolean类型
>>> a = 1 >>> b = 0 >>> c = "None" >>> d = bool(a) > ...
- Loadrunner负载机agent
记录下来备用,若要一台服务器充当负载机,windows下必须启动magentproc.exe
- ps 命令使用总结
ps命令用来查看进程信息,它是类似于快照类型的只显示一次,如果想及时刷新请用top命令. 1. 常用参数列表 -a 显示所有终端机下执行的进程,除了阶段作业领导者之外. a 显示现行终端机下的所有进程 ...
- Linux使用wake_up_interruptible()唤醒注册到等待队列上的进程
http://blog.sina.com.cn/s/blog_4770ef020101h48l.html 功能:唤醒注册到等待队列上的进程 原型: #include void ...
- 公司的SVN服务器改变了IP地址,请问以前下载的代码如何同步,
工作根目录上 右键->TortoiseSVN->Relocate,修改URL 更新前先备份!
- BNU29368:Check the Identity(栈)
Just determine whether an algebraic expression can always simplify to zero. Input The first line con ...
- Spring AOP实现方式二【附源码】
自动代理模式[和我们说的方式一 配置 和 测试调用不一样哦~~~] 纯POJO切面 源码结构: 1.首先我们新建一个接口,love 谈恋爱接口. package com.spring.aop; /* ...
- 令人头疼的clientTop、scrollTop、offsetTop
1.网络上流传的图片 2.稍微容易理解点的示意图 参考链接:http://blog.csdn.net/lidiansheng/article/details/7950751 3.言简意赅的示意图 4. ...
- rc522 ,pn544区别
请问 我们之前用的刷卡的 是用 rc522 ,,pn544和这个有什么区别? xqhrs232 (10:14:27): 支持的协议更多点吧! 春tian在哪里 (10:14:38): 比如? xq ...
- Android开发之bindService()侦听service内部状态
在Android开发之bindService()通信的基础上,实现bindService()方法侦听service内部状态. 实现侦听service内部状态,使用的是回调机制 1.首先实现一个接口 p ...