
每个人都说代码是程序员手中的一把雕刻刀,是拆雀此对他们产品轮廓和细节的打磨。每个程序员在代码优化方面需要做的是,即使是每天处理代码的程序员也有很多关于他们编写代码的问题,所以优化很重要。下面霍营霍营IT培训为大家介绍代码优化的方法。
1、尽量重用目标
特别是,使用代表字符串收敛的String目标应该使用StringBuilder/StringBuffer。因为Java虚拟机不仅要花时间生成目标,而且可能还需要花时间检索和删除这些目标,所以霍营计算机学院发现生成太多目标会对程序的功能产生重大旅迅影响。
2、岁罩可以运用局部变量
调用方法时传递的参数和调用中创建的临时变量保存在堆栈中的速度更快。其他变量,如静态变量、实例变量等等,在堆中创建,速度较慢。此外,霍营北大青鸟发现在堆栈中创建的变量,方法的 *** 作结束,当这些内容都消失了,就不需要额定废物回收。
3、及时封闭流
Java的程序编写过程中,数据库连接,I/O流 *** 作必须谨慎,应用结束后,应该及时关闭发布资源。因为霍营java培训发现这些大目标的运行会造成大系统支出,稍有不慎就会导致严重的结果。
降低用户跳出率的方法有很多,对于软件开发程序员来说,代码的优化和网络优化都是很有效的方法。今天,霍营IT培训就从以下几个方面来了解一下,网络优化的具体 *** 作内容。
1Gzip压缩
HTTP协议上的Gzip编码是一种用来改进WEB应用程序性能的技锋轮术,用来减少传输数据量大小,减少传输数据量大小有两个明显的好处:
可以减少流量消耗
可以减少传输的时间。
2IP直连与HttpDns
DNS解析的失败率占联网失败中很大一种,而且次域名解析一般需要几百毫秒。针对此,我们可以不用域名,才用IP直连省去DNS解析过程,节省这部分时间。
另外熟悉阿里云的小伙伴肯定知道HttpDns:HttpDNS基于Http协议的域名解析,替代了基于DNS协议向运营商LocalDNS发起解析请求的传统方式,可以避免LocalDNS造成的域名劫持和跨网访问问题,解决域名解析异常带来的困扰。
3图片处理
3.1图片下载
使用WebP格式同样的照片,采用WebP格式可大幅节省流量,相做基返对于JPG格式的图片,流量能节省将近25%到35%相对于PNG格式的图片,流量可以节省将近80%。重要的是使用WebP之后图片质量也没有改变。
使用缩略图App中需要加载的图片按需加载,列表中的图片根据需要的尺寸加载合适的缩略图即可,只有用户查看大图的时候才去加载原图。不仅节省流量,同时也能节省内存!之前使用某公司的图片存储服务在原图链接之后拼接宽高参数,根据参数的不同返回相应的图片。
3.2图片上传
图片(文件)的上传失败率比较高,不仅仅因为大文件,同时带宽、时延、稳定性等因素在此场景下的影响也更加明显
避免整文件传输,采用分片传输纯饥
根据网络类型以及传输过程中的变化动态的修改分片大小
每个分片失败重传的机会。
备注:图片上传是一项看似简单、共性很多但实际上复杂、需要细分的工作。移动互联网的场景和有线的场景是有很多区别的,例如移动网络的质量/带宽经常会发生“跳变”,但有线网络却是“渐变”。
4协议层的优化
使用新的协议,Http协议有多个版本:0.9、1.0、1.1、2等。新版本的协议经过再次的优化,例如:
Http1.1版本引入了“持久连接”,多个请求被复用,无需重建TCP连接,而TCP连接在移动互联网的场景下成本很高,节省了时间与资源
Http2引入了“多工”、头信息压缩、服务器推送等特性。
新的版本不仅可以节省资源,同样可以减少流量我对Http2并没有实际接入经验,此处仅从原理进行分析。
这周一,公司新来了一个同事,面试的时候表现得非常不错,各种问题对答如流,老板和我都倍感欣慰。
这么优秀的人,绝不能让他浪费一分一秒,于是很快,我就发他了需求文档、源码,让他先在本地熟悉一下业务和开发流程。
结果没想到,周三大家一块 review 代码的时候就发现了问题,新来的同事直接把原来 @Transactional 优化成了这个鬼样子:
就因为这一行代码,老板(当年也是一线互联网大厂的好手)当场就发飙了,马上就要劝退这位新同事,我就赶紧打圆场,毕竟自己面试的人,不看僧面看佛面,是吧?于是老板答应我说再试用一个月看看。
会议结束后,我就赶紧让新同事复习了一遍事务,以下是他自己做的总结,还是非常详细的,分享出来给大家一点点参考和启发。相信大家看完后就明白为什么不能这样优化 @Transactional 注解了,纯属画蛇添足和乱用。
事务在逻辑上是一组 *** 作, 要么执行,要不都不执行 。主要是针对数据库而言的,比如说 MySQL。
只要记住这一点,理解事务就很容易了。在 Java 中,我们通常要在业务里面处理多个事件,比如说编程喵有一个保存文章的方法,它除了要保存文章本身之外,还要保存文章对应的标签,标签和文章不在同一个表里,但会通过在文章表里(posts)保存标签主键(tag_id)来关联标签表(tags):
那么此时就需要开启事务,保证文章表和标签表中的数据保持同步,要么都执行,要么都不执行。
否则就有可能造成,文章保存成功了,但标签保存失败了,或者文章保存失败了,标签保存成功了——这些场景都不符合我们的预期。
为了保证事务是正确可靠的,在数据库进行写入或者更新 *** 作时,就必须得表现出 ACID 的 4 个重要特性:
其中,事务隔离又分为 4 种不同的级别,包括:
需要格外注意的是: 事务能否生效,取决于数据库引擎是否支持事务,MySQL 的 InnoDB 引擎是支持事务的,但 MyISAM 就不支持 。
1)编程式事务
编程式事务是指将事务管理代码嵌入嵌入到业务代码中,来控制事务的提交和回滚。
你比如说,使用 TransactionTemplate 来管理事务:
再比如说,使用 TransactionManager 来管理事务:
就编程式事务管理而言,Spring 更推荐使用 TransactionTemplate。
在编程式事务中,必须在每个业务 *** 作中包含额外的事务管理代码,就导致代码看起来非常的臃肿,但对理解 Spring 的事务管理模型非常有帮助。
当然了,要想实现事务管理和业务代码的抽离,就必须得用到 Spring 当中最关键最核心的技术之一,AOP,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入念前一个事务,执行完目标方法之后根据执行的情况提交或者回滚。
Spring 将事务管理的核心抽象为一个事务管理器(TransactionManager),它的源码只有一个简单的接口定义,属于一个标记接口:
通过 PlatformTransactionManager 这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
参数 TransactionDefinition 和 @Transactional 注解是对应的,比如说 @Transactional 注解中定义的事务传播行为、隔离级别、事务野尺超时时仔脊清间、事务是否只读等属性,在 TransactionDefinition 都可以找得到。
返回类型 TransactionStatus 主要用来存储当前事务的一些状态和数据,比如说事务资源(connection)、回滚状态等。
TransactionDefinition.java:
Transactional.java
说到这,我们来详细地说明一下 Spring 事务的传播行为、事务的隔离级别、事务的超时时间、事务的只读属性,以及事务的回滚规则。
当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播 ,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。
TransactionDefinition 一共定义了 7 种事务传播行为:
01、 PROPAGATION_REQUIRED
这也是 @Transactional 默认的事务传播行为,指的是如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。更确切地意思是:
这个传播行为也最好理解,aMethod 调用了 bMethod,只要其中一个方法回滚,整个事务均回滚。
02、 PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都会开启自己的事务,且开启的事务与外部的事务相互独立,互不干扰。
如果 aMethod()发生异常回滚,bMethod()不会跟着回滚,因为 bMethod()开启了独立的事务。但是,如果 bMethod()抛出了未被捕获的异常并且这个异常满足事务回滚规则的话,aMethod()同样也会回滚。
03、 PROPAGATION_NESTED
如果当前存在事务,就在当前事务内执行;否则,就执行与 PROPAGATION_REQUIRED 类似的 *** 作。
04、 PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
05、 PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
06、 PROPAGATION_NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
07、 PROPAGATION_NEVER
以非事务方式运行,如果当前存在事务,则抛出异常。
3、4、5、6、7 这 5 种事务传播方式不常用,了解即可。
前面我们已经了解了数据库的事务隔离级别,再来理解 Spring 的事务隔离级别就容易多了。
TransactionDefinition 中一共定义了 5 种事务隔离级别:
通常情况下,我们采用默认的隔离级别 ISOLATION_DEFAULT 就可以了,也就是交给数据库来决定,可以通过 SELECT @@transaction_isolation 命令来查看 MySql 的默认隔离级别,结果为 REPEATABLE-READ,也就是可重复读。
事务超时,也就是指一个事务所允许执行的最长时间,如果在超时时间内还没有完成的话,就自动回滚。
假如事务的执行时间格外的长,由于事务涉及到对数据库的锁定,就会导致长时间运行的事务占用数据库资源。
如果一个事务只是对数据库执行读 *** 作,那么该数据库就可以利用事务的只读属性,采取优化措施,适用于多条数据库查询 *** 作中。
这是因为 MySql(innodb)默认对每一个连接都启用了 autocommit 模式,在该模式下,每一个发送到 MySql 服务器的 SQL 语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务。
那如果我们给方法加上了 @Transactional 注解,那这个方法中所有的 SQL 都会放在一个事务里。否则,每条 SQL 都会单独开启一个事务,中间被其他事务修改了数据,都会实时读取到。
有些情况下,当一次执行多条查询语句时,需要保证数据一致性时,就需要启用事务支持。否则上一条 SQL 查询后,被其他用户改变了数据,那么下一个 SQL 查询可能就会出现不一致的状态。
默认情况下,事务只在出现运行时异常(Runtime Exception)时回滚,以及 Error,出现检查异常(checked exception,需要主动捕获处理或者向上抛出)时不回滚。
如果你想要回滚特定的异常类型的话,可以这样设置:
以前,我们需要通过 XML 配置 Spring 来托管事务,有了 Spring Boot 之后,一切就变得更加简单了,只需要在业务层添加事务注解( @Transactional )就可以快速开启事务。
也就是说,我们只需要把焦点放在 @Transactional 注解上就可以了。
虽然 @Transactional 注解源码中定义了很多属性,但大多数时候,我都是采用默认配置,当然了,如果需要自定义的话,前面也都说明过了。
1)要在 public 方法上使用,在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有个判断,如果目标方法不是public,则TransactionAttribute返回null,即不支持事务。
2)避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效。
在测试之前,我们先把 Spring Boot 默认的日志级别 info 调整为 debug,在 application.yml 文件中 修改:
然后,来看修改之前查到的数据:
开搞。在控制器中添加一个 update 接口,准备修改数据,打算把沉默王二的狗腿子修改为沉默王二的狗腿:
在 Service 中为方法加上 @Transactional 注解并抛出运行时异常:
按照我们的预期,当执行 save 保存数据后,因为出现了异常,所以事务要回滚。所以数据不会被修改。
在浏览器中输入 http://localhost:8080/user/update 进行测试,注意查看日志,可以确认事务起效了。
当我们把事务去掉,同样抛出异常:
再次执行,发现虽然程序报错了,但数据却被更新了。
这也间接地证明,我们的 @Transactional 事务起效了。
看到这,是不是就明白为什么新同事的优化纯属画蛇添足/卵用了吧?
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)