ORM确实事很方便让人不需要大量的写SQL,但是很多人诟病造成SQL性能不好

举个例子,一个功能是修改get用户数据的金币清零然后update

非常简单的一个业务:

User user=dao.getUser(uid);
user.setGold(0);
dao.updateUser(user);

就这样一个简单的功能,实际会向数据库发送一长串的SQL update语句

如:update user set a=?,b=?,c=?............gold=? where uid = ?

看到这里有人会明白问题出在哪里了,想想一下每个表都有一堆字段, 而实际上我们在各个业务里面只会修改一两个字段,导致每次调用业务都会生产这样一长串的SQL,给数据库来带巨大而且没有必要的压力。

有的人会说:我编程习惯很好,平时都会把调用频率高的方法单独写sql。例如上面修改金币会单独写一个updateGold方法。当然,这是一种很好的习惯并且也能解决这个问题。但是 大部分开发者、大部分业务实现并不会这样做。不是吗?

现在可以通过另外一种方法来实现对原有的ORM系统优化兼顾开发效率和系统性能提升:

  /** update之前先比较,只update修改过的列 */public <T> void compareAndUpdate(T oldT, T newT);

简单的介绍一下就是,通过对比新旧实体,根据修改过的列来生成指定的列到达针对性更新的目的。

//以前:
User user=dao.getUser(uid);
user.setGold(0);
dao.updateUser(user);
//产生的sql:
update user set a=?,b=?,c=?............gold=? where uid = ?//新的做法:
User user=dao.getUser(uid);
User oldUser=BeanUtils.cloneBean(user);
user.setGold(0);
dao.compareAndUpdate(oldUser,user);
//产生的sql:
update user set gold = ? where uid = ?sql语句的缩短成倍的降低了与数据库通讯的开销,并且大大的降低了数据库压力。如果上面的写法可能会稍微麻烦点,我们可以再偷点懒:
User user=dao.getUser(uid);
Object oldBean=BeanUtils.copyBean(user);//这样的区别是copy这段代码即可,不需要经常修改oldBean的类型。因为我们不关心oldBean是什么类型。
user.setGold(0);
dao.compareAndUpdate(oldBean,user);

有人会说实体copy和拼接sql也会产生开销,这个是不错。但是这种开销对于数据库的压力来说根本就是九牛一毛不值一提。

compareAndUpdate这个方法是我自己写的ORM框架:freyja-jdbc 里面改写update方法产生的。如果是使用的其他ORM框架 有预留接口的话可以改写下即可。没有接口的话可能需要自己去实现了,方法就是映射实体和字段 生成sql语句

hibernate 好久没碰了,怎么改写hibernate也能达到一样的效果不清楚,有兴趣的可以自己研究下。

最后还是放下相关代码吧

 public static Parameter compareAndUpdate(Object oldEntity, Object newEntity) {FreyjaEntity entity = ShardingUtil.getEntity(newEntity.getClass());List<Object> args = new ArrayList<Object>();Object idValue = null;BeanMap oldBeanMap = BeanMap.create(oldEntity);BeanMap beanMap = BeanMap.create(newEntity);List<String> columnNameList = new ArrayList<String>();for (Property p : entity.getProperties().values()) {ShardingProperty s = (ShardingProperty) p;Object newPropertyValue = beanMap.get(p.getName());if (s.isId()) {idValue = newPropertyValue;continue;} else {Object oldPropertyValue = oldBeanMap.get(p.getName());if ((newPropertyValue == null && oldBeanMap == null)|| newPropertyValue.equals(oldPropertyValue)) {// 值未改变过,不更新continue;}}columnNameList.add(p.getName());args.add(newPropertyValue);}args.add(idValue);Parameter parameter = null;if (entity.isSubTable()) {DbResult result = ShardingUtil.engine.getShardingStrategy().getShardingTableNameById(entity.getTableName(), idValue);parameter = entity.updateByColumn(columnNameList, idValue);parameter.setDbNo(result.getDbNo());} else {parameter = entity.updateByColumn(columnNameList, null);}parameter.setArgs(args.toArray());return parameter;}/** 根据指定列生产相关信息 */public Parameter updateByColumn(List<String> columnNameList, Object idValue) {String set = "";List<Integer> types = new ArrayList<Integer>();for (String cn : columnNameList) {ShardingProperty s = (ShardingProperty) getProperties().get(cn);set += s.getDbColumnName() + " = ? ,";types.add(s.getTypes());}set = set.substring(0, set.length() - 1);String setSql = " set " + set + " where " + getId().getDbColumnName()+ " = ?";types.add(getId().getTypes());String sql = null;if (idValue == null) {sql = "update " + getTableName() + setSql;} else {// 分库DbResult result = ShardingUtil.engine.getShardingStrategy().getShardingTableNameById(getTableName(), idValue);sql = "update " + result.getTableName() + setSql;}Parameter p = new Parameter();p.setSql(sql);p.setSqlTypes(ListUtil.toPrimitive(types));return p;}

----------------------------------------------------------------------------

实际操作了下后发现虽然确实是不错,但是对现有系统和写法有出入。有没有兼容现有系统的写法更智能一些的办法呢。

然后想到了另外一种做法:

public class PersistObj implements Serializable {/** 用于更新compareAndUpdate,并且改属性不会被序列化 */private transient  Object oldBean;
get();set();
}//然后让你的实体继承这个对象,这样默认都会有了一个oldBean属性来存放oldBean
//再写个通用方法@Overridepublic <T> T getAndClone(Class<T> clazz, Object id) {T t = super.get(clazz, id);if (t instanceof PersistObj) {PersistObj obj = (PersistObj) t;Object oldBean = BeanUtils.cloneBean(t);obj.setOldBean(oldBean);}return t;}//这样查询的时候就把oldBean存储了。//之前的update 方法改写下:if (oldT == null) {if (newT instanceof PersistObj) {PersistObj obj = (PersistObj) newT;oldT = (T) obj.getOldBean();}}让oldBean从 oldBean属性里面去取。不需要再传递了

这样做后的效果是:

      User user = userDao.getAndClone(uid);user.setGold(0);userDao.compareAndUpdate(user);//这里这样写是为了让大家明白如何工作的。
//实际上这些方法是可以替换底层封装的,业务代码不需要修改。
//也就是说可以达到这种写法效果:User user = userDao.getUser(uid);
user.setGold(0);
userDao.updateUser(user);//是不是和最初一样了,在不影响现有代码的基础上提升性能

这样做后对原有的业务不需要再修改, 因为这些dao方法都是底层的。替换的就可以了。service业务方法不需要变动。

当然,这样写有2个缺点:

1、无法对缓存有效。

2、每次查询都会克隆一遍。

针对第一个问题:当有用到缓存的地方,只能用之前的方法,手动的cloneBean。

针对第二个问题:首先对于不需要这种功能的实体不用getAndClone方法就没有任何影响

对于其他的一般我们查询肯定是为了修改的。大部分逻辑都是这样。所以默认情况影响不大,如果明确不涉及到修改,不使用getAndClone方法就可以了使用其他默认的get()方法就可以了。也没有太大影响,只是编写的时候多了一种选择

成倍提升ORM系统SQL性能的一个方法相关推荐

  1. (转)用DynamicMethod提升ORM系统转换业务数据的性能

    原文 用DynamicMethod提升ORM系统转换业务数据的性能 在上一篇文章<把Sql数据转换为业务数据的几种方法>中提到了ORM系统把Sql数据转换为业务数据的几种方法,但这些方法都 ...

  2. MySql查询优化性能调优,sql性能自测方法,及Mysql索引介绍

    MySql查询优化性能调优,sql性能自测方法,及Mysql索引介绍 前言 一.普通优化加索引(适用于where条件后一个查询条件) 二.组合查询加索引(适用于where条件后多个查询条件) 三.My ...

  3. 39个必知必会的SQL 性能调优方法

    1.选择最有效率的表名顺序(只在基于规则的优化器中有效) ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理 ...

  4. plm服务器 硬件性能,如何对PLM系统进行性能诊断与调优?

    原标题:如何对PLM系统进行性能诊断与调优? PLM系统是企业最重要的信息系统之一,尤其对于研发人员,PLM系统更是日常工作中非常重要的一环.随着时间的推移,企业对PLM系统的相关应用越来越深入,一方 ...

  5. matlab 动态优化,基于Matlab的测控系统动态性能优化与仿真

    随着测试技术的发展,人们采用传感器测控系统的动态性能指标来表征系统性能.描述传感器的主要动态性能指标是工作频带,系统的动态性能研究的重要一步是在辨识出合适的模型结构和模型参数的基础上,根据现有的工作频 ...

  6. 智能SQL优化工具--SQL Optimizer for SQL Server(帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 )...

    SQL Optimizer for SQL Server 帮助提升数据库应用程序性能,最大程度地自动优化你的SQL语句 SQL Optimizer for SQL Server 让 SQL Serve ...

  7. 性能优化——提升Win10系统反应速度

    性能优化--提升Win10系统反应速度 来源:Win7之家    浏览量: 3969 次      2015-04-16 16:23 性能优化--提升Win10系统反应速度    一个系统使用了一段时 ...

  8. 我用多线程进一步优化了亿级流量电商业务下的海量数据校对系统,性能再次提升了200%!!(全程干货,建议收藏)

    大家好,我是冰河~~ 在[精通高并发系列]的<我用多线程优化了亿级流量电商业务下的海量数据校对系统,性能直接提升了200%!!(全程干货,建议收藏)>一文中,我们主要使用了CountDow ...

  9. flyme android os 耗电,魅族运行安卓5.0 Flyme OS系统实测 性能流畅度提升

    魅族上个月开启了安卓5.0 Flyme OS系统的测试,首先适配的是MX4 Pro,现在我们来看看安卓5.0 Flyme OS系统的实测体验. 首先简单罗列一下已知的部分新特性: - Android ...

  10. 我用多线程优化了亿级流量电商业务下的海量数据校对系统,性能直接提升了200%!!(全程干货,建议收藏)

    大家好,我是冰河~~ 最近不少运营同事找到我说:咱们的数据校对系统越来越慢了,要过很久才会显示出校对结果,你能不能快速优化一下呢?我:好的,我先了解下业务啊. 注:全程干货,文章对你有点帮助的话,小伙 ...

最新文章

  1. ui动效 unity_Unity - UIWidgets 2. 控件组合
  2. Linux/unix 查看端口占用
  3. js string转number_Node.js 和 C++ 之间的类型转换
  4. Servlet多线程机制
  5. java aes加密_springboot.X手册:防抓包?快速实现API接口数据加密
  6. 饥荒联机建立好服务器找不到,饥荒联机版浏览世界找不到已经创建的世界 | 手游网游页游攻略大全...
  7. 浅说物联网之一:物联网圈子的三个玩家
  8. android 友盟统计功能,Android应用中添加友盟统计
  9. 悟已往之不谏,知来者之可追;实迷途其未远,觉今是而昨非
  10. CTF比赛(详细介绍)
  11. macOS安装homebrew与更新gcc
  12. iPhone手机在Apple启动logo处卡住,无法开机该怎么办?
  13. 查看电脑可支持最大内存容量的方法
  14. Flutter开始支持Windows了
  15. 推荐几个帮你避坑和赚钱的公众号
  16. Drools从入门到精通
  17. java类 家族成员 姓氏_java题目 将一些学生分别按姓氏分类,每个姓氏的学生输出到一行上。...
  18. GameFi独角兽区块帝国,今日开启全球IDO
  19. 地理信息辅助空间决策
  20. 老卫带你学---WLD韦伯局部描述符

热门文章

  1. 宝塔脚本下载慢解决办法
  2. CSS 选择所有子元素添加样式
  3. 数学----两个或者多个函数相乘求它们的导数
  4. java 图片 pdf_Java 添加图片到PDF
  5. 浅层介质过滤器工作原理介绍
  6. 最强大脑《智行营救》
  7. 加速度传感器和角度传感器
  8. 计算机中年级排名怎么操作,智学网年级排名查看方法规则介绍
  9. allegro的器件无法移动,而且右键点解锁没有用
  10. IDEA 找不到或无法加载主类