都这样了,还能怎么改进?上学时基础编程练习题和生产业务,其实是一样的…

4 篇文章 0 订阅

翻译翻译,
什么是tom的精益求精
这还用翻译?当然是经常问 “还能怎么改进” 的人 (例如项目经理) 所散发出的 “杠精” 气质。

"还能怎么改进"的“杠精”气质

​ 朋友在学SSM,mybatis插入多条数据,竟然是在service层循环调用dao层函数

​ 我说程序总能改进的,试着传list然后按批处理后提交。

@Transactional
public void add(List<Book> bookList) {
    SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
    BookMapper mapper = session.getMapper(BookMapper.class);
    for (int i = 0; i<bookList.size(); i++) {
        mapper.insertSelective(bookList.get(i));
        if(i%1000==999){
            session.commit();
            session.clearCache();
        }
    }
    session.commit();
    session.clearCache();
}

​ 今天给我看他写的这个,说效率提高了。但抓着我说的“总能改进的“不放,问我还能怎么改进

​ 好家伙,为了效率,我总不能让用JDBC。

于是最终翻译为

@Transactional
public void add(List<Book> bookList) {
    SqlSession session = sqlSessionFactory.openSession( ExecutorType.BATCH, false );
    BookMapper  mapper = session.getMapper( BookMapper.class );
    
    int loopInner = Integer.min( 1000, bookList.size() );
    int loopOuter = bookList.size()/loopInner+1;
    
    for( int j = 0; j < loopOuter; j++ ){
    
        int innerBounds = Integer.min( loopInner*(j+1), bookList.size() );
        for( int i = j*loopInner; i < innerBounds; i++ )
            mapper.insertSelective( bookList.get(i) ); 
            
        session.commit();	
        session.clearCache();
        
    }
}

改进之处,也就减少了 bookList.size() 次取模和比较


如果对时间要求特别高,那先举几个简单例子

核心

  • 已知总循环次数,类似于CLOCK式的迭代需求,能不用if就不用。控制边界和下标减少迭代次数。

副作用

  • 代码或略显冗余,观感下降⬇

5个基础编程练习的例子

【例1】解决难见不良代码

​ 大一新生常见不良习惯,很危险,如果 func(i)中再有循环的话…

for( i ){
    for( j = 0; j < func(i); j++) 	
        //无论是否有i,此处函数每次内层循环都会执行,也就是说没有外循环也不能这么搞
}

​ 替代为:

for( i ){
    int bounds = func(i);
    while(j<bounds){
        //...
       	j++;
    }
}
【例2】解决常见不良代码

​ 第二个就比较有意思了,当年一个的学弟写的,这要是写在循环里,或者func()有循环💀…

j = (func(index)%100==0) ? (func(index)/100) : (func(index)/100+1);

​ 一改,其实还行,大多数人这么写

int jA = func(index);
//数值运算+比较运算+数值运算
j = (jA%100==0) ? (jA/100) : (jA/100+1); 

​ 二改, 简直 💀 …

int jA = func(index);
int remainder = jA%100int quotient = jA/100;
j = (remainder==0) ? quotient : (quotient+1);

​ 数学得过0分的我改:

int jA = func(index);
j = (jA + 100 ) % 100;	//数值运算

或者

j = ( func(index) + 100 ) % 100;
【例3】解决常见不良代码
for( int i = 0; i < loopTimes; i++ ){
    if( i != 100 ) funcA();
    //常见的还有形如if( i <= 100 ) funcA();
    else funcB();
}

​ 控制一下,将 if 部分提出:

int loopPart = Integer.min(100,loopTimes);
int i = 0;
while(i<loopPart) {
	funcA();
	i++;
}
if( i++ == 100 ) funcB();
while(i<loopTimes) {
	funcA();
	i++;
}

如果喜欢空荡荡的"for();",也可以这么写

int loopPart = Integer.min(100,loopTimes);
int i = 0;
for( ; i<loopPart;  i++ ) funcA();
if( i++ == 100 ) funcB();
for( ; i<loopTimes; i++ ) funcA();

【例4】这么恶魔的数字,当然指的是把包括但不限于例1~5所有的都写在一块

​ ……

【例5】解决很常见不良代码
for( int i = 0; i < loopTimes; i++ ){
    funcA();
    if( i%100 == 0 ) funcB();
}

像不像基础编程:

 循环输出1~300的整数,每十个数字换行?

像不像小学数学:

 化简 1(a+b)+2(a+b)+3(a+b)+... 

于是,就这么写

	int loopInner =  Integer.min(100, listA.size());	
	int loopOutter = listA.size()/loopInner+1;
	for( int j = 0; j < loopOutter; j++  ){
	    int innerBounds = Integer.min( loopInner*(j+1), listA.size() );
	    for(int i = j*loopInner; i<innerBounds; i++ ) funcA();
	    funB();
	}

"还能怎么改进"的翻译结果

若没有例5的基础,直接进行修改,产生没有任何的呼吸感与节奏感的初改代码👿

@Transactional
public void add(List<Book> bookList) {
    SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
    BookMapper mapper = session.getMapper(BookMapper.class);
    
    int loopInner = 1000;   // [noteA]此处取1000,对应于本次的需求:每千次提交并清缓存。
    
    //数据条目数不足1000,直接循环list退出
    if( bookList.size()<loopInner ){	
        for (int i = 0; i < bookList.size(); i++)
            mapper.insertSelective(bookList.get(i));
    } //end if
    
    else{	//数据条目数大于1000时	
        //分为loopOuter轮(组),每轮执行loopInner次迭代:插入数据。每轮结束后提交事务
        int loopOuter = bookList.size()/loopInner;	//可能有余数
        int i = 0;
        for( int j = 0; j < loopOuter; j++  ){
            i = j*loopInner;
            int innerBounds = (j+1)*loopInner;
            while( i<innerBounds ){
                mapper.mapper.insertSelective(bookList.get(i++));
            }
            session.commit();
            session.clearCache();
        }
        //有余数,经过loopInner*loopOuter次迭代后剩余部分直接循环处理
        for( i = loopInner*loopOuter; i<bookList.size();i++ )
            mapper.insertSelective(bookList.get(i++));
        

    } //end if-else
    
    session.commit();
    session.clearCache();
}

在例五的基础上改出

final版本

去掉注释,充满了 节奏感与呼吸感

@Transactional
public void add(List<Book> bookList) {

    SqlSession session = sqlSessionFactory.openSession( ExecutorType.BATCH, false );
    BookMapper  mapper = session.getMapper( BookMapper.class );

    int loopInner = Integer.min( 1000, bookList.size() );	//[noteA]后期根据需求修改1000
    int loopOuter = bookList.size()/loopInner+1;			//外层次数:除法直接加一
    
    //int i = 0;	//是否提升内层循环index变量,取决于循环之后是否需要index;
    for( int j = 0; j < loopOuter; j++ ){
    
        int innerBounds = Integer.min( loopInner*(j+1), bookList.size() );//最后一轮取表长
        
        for( int i = j*loopInner; i < innerBounds; i++ )
            mapper.insertSelective( bookList.get(i) ); 
        
        session.commit();	//如果可以被整除就会多执行一次提交与清除缓存,mybatis允许该操作
        session.clearCache();
        
    } //end for
}

​ noteA:

  1. 此处取1000,对应于本次的需求:每千次提交并清缓存
  2. 外层每循环一次,内层的循环次数,理论取值范围[0,bookList.size()]
  3. 在取值合理的范围内:
    a)向数据库插入数据的效率与loopInner值成正比
    b)缓存压力与loopInner值成正比

显然
“杠精”气质看final版,性能比初改版是要差一丢丢的

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值