中国领先的IT技术网站
|
|

Scala的启发:代码本质与过度包装的平衡

基于Java、Hibernate的商业应用开发确实陷入到了一个很痛苦的境界,而大家却都觉得这就是正常的程序员生活。不过,一段Scala直译JDBC的代码,却引发了另一番思考。

作者:王在祥来源:Wang Zai Xiang|2009-11-10 17:23

Tech Neo技术沙龙 | 11月25号,九州云/ZStack与您一起探讨云时代网络边界管理实践


本文来自王在祥先生的博客(blogspot),原标题为《重温 scala》。对于代码简洁化与可读性矛盾的解决,Scala语言无疑是一种启发。以下为原文:

51CTO编辑推荐:Scala编程语言专题

最近,在阅读项目组的代码时,再次陷入了苦思:基于Java、Hibernate的商业应用开发确实陷入到了一个很痛苦的境界,这个问题实际上正在进行开发的大部分开发人员都不会感觉到,因为大家都觉得这就是正常的程序员生活。再说,几乎所有的框架都在力捧Hibernate这样的ORM工具能够极大的简化程序的开发,要不,你去使用使用 JDBC试试。

在Java中基于JDBC编程,确实有些汇编语言的感觉,摘抄一份实际项目的代码:

  1. public void updateTerminalStatus(String timeout, String transtime) throws Exception {  
  2.         //更新超时终端的状态值(9为超时)   
  3.         String updateTerminal = "update T_Terminal set Status=9 "   
  4.             + " where TerminalID in (select TerminalID from T_Terminal where TO_CHAR(latestDate, 'yyyymmddHH24miss')<=? and (status=0 or status=2) ) ";  
  5.           
  6.         //查询超时的终端信息,且该终端号在故障表中没有未处理的超时记录,(包含该终端号在故障表中没有超时记录的情况)。  
  7.         String queryTimeOutTerm = "SELECT te.TerminalID FROM T_TERMINAL te WHERE te.status=9 ";  
  8.         String queryTerm = "SELECT terminalid FROM T_TROUBLELOG tr " +  
  9.                 " WHERE tr.DeviceID='COMMMODULE' AND tr.TroubleID='CommTimeOut' " +  
  10.                 " AND tr.SolveDate IS NULL GROUP BY  terminalid ";  
  11.           
  12.         //向故障表中添加一条新的故障记录。  
  13.         String insertTrouble = "insert into T_TroubleLog (LogID, TerminalID, DeviceID, TroubleID, HappenDate) " 
  14.             + " values (?, ?, 'COMMMODULE', 'CommTimeOut', TO_DATE(?,'yyyymmddHH24miss')) ";  
  15.           
  16.         //更新故障表中的终端超时记录,该终端号的状态已经不超时,则超时故障处理完毕。  
  17.         String updateTrouble = "UPDATE T_TROUBLELOG tl SET tl.SolveDate=TO_DATE(?,'yyyymmddHH24miss') " +  
  18.                 " WHERE terminalid IN" +  
  19.                 " (SELECT tm.terminalid FROM T_TERMINAL tm,T_TROUBLELOG tl " +  
  20.                 " WHERE tm.Status != 9 AND tm.TerminalID=tl.TerminalID )" +  
  21.                 " AND tl.DeviceID='COMMMODULE' AND tl.TroubleID='CommTimeOut' AND tl.SolveDate IS NULL ";  
  22.           
  23.         Connection conn = null;  
  24.         PreparedStatement pstmt = null;  
  25.         PreparedStatement pstmtInsert = null;  
  26.         ResultSet rs = null;  
  27.         List terlist = new ArrayList();  
  28.         List noterlist = new ArrayList();  
  29.         try {  
  30.               
  31.             conn = transDataSource.getConnection();  
  32.             conn.setAutoCommit(false);  
  33.  
  34.             pstmt = conn.prepareStatement(updateTerminal);  
  35.             pstmt.setString(1, timeout);  
  36.             pstmt.executeUpdate();  
  37.             pstmt.close();  
  38.               
  39.             pstmt = conn.prepareStatement(updateTrouble);  
  40.             pstmt.setString(1, transtime);  
  41.             pstmt.executeUpdate();  
  42.             pstmt.close();  
  43.             log.debug("更新完成");  
  44.  
  45.             //生成32位的随机ID,使用Hibernate中的UUID算法。  
  46.             Properties props = new Properties();  
  47.             props.setProperty("separator""");  
  48.             IdentifierGenerator gen = new UUIDHexGenerator();  
  49.             ( (Configurable) gen ).configure(Hibernate.STRING, props, null);  
  50.               
  51.             pstmtInsert = conn.prepareStatement(insertTrouble);  
  52.  
  53.             pstmt = conn.prepareStatement(queryTerm);  
  54.             rs = pstmt.executeQuery();  
  55.             while(rs.next()){  
  56.                 String termid = rs.getString(1);  
  57.                 terlist.add(termid);  
  58.             }  
  59.             log.debug("查询终端号在故障表中没有未处理的超时记录完成");  
  60.             rs.close();  
  61.             rs = null;  
  62.             pstmt.close();  
  63.             pstmt = null;  
  64.               
  65.               
  66.             pstmt = conn.prepareStatement(queryTimeOutTerm);  
  67.             rs = pstmt.executeQuery();  
  68.             while (rs.next()) {  
  69.                 String term = rs.getString(1);  
  70.                 noterlist.add(term);  
  71.             }  
  72.             log.debug("查询超时的终端信息完成" + noterlist.size());  
  73.               
  74.             for(int j = 0; j < noterlist.size(); j++){  
  75.                 String terminalid = noterlist.get(j).toString();  
  76.                 if(terlist.contains(terminalid)){  
  77.                     continue;  
  78.                 }  
  79.                 pstmtInsert.setString(1, (String) gen.generate(nullnull));  
  80.                 pstmtInsert.setString(2, terminalid);  
  81.                 pstmtInsert.setString(3, transtime);  
  82.                 pstmtInsert.addBatch();  
  83.             }  
  84.             pstmtInsert.executeBatch();  
  85.  
  86.             conn.commit();  
  87.             log.debug("向故障表中添加新的故障记录完成");  
  88.               
  89.         } catch (Exception ex) {  
  90.             try{  
  91.                 conn.rollback();  
  92.             }catch (Exception e) {  
  93.             }  
  94.             throw ex;  
  95.         } finally {  
  96.             if (rs != null) {  
  97.                 try {  
  98.                     rs.close();  
  99.                 } catch (Exception ex) {  
  100.                 }  
  101.             }  
  102.             if (pstmt != null) {  
  103.                 try {  
  104.                     pstmt.close();  
  105.                 } catch (Exception ex) {  
  106.                 }  
  107.             }  
  108.             if (pstmtInsert != null) {  
  109.                 try {  
  110.                     pstmtInsert.close();  
  111.                 } catch (Exception ex) {  
  112.                 }  
  113.             }  
  114.             if (conn != null) {  
  115.                 try {  
  116.                     conn.close();  
  117.                 } catch (Exception ex) {  
  118.                 }  
  119.             }  
  120.         }  
  121.     }  
  122.  

这份代码长达120行,要去理解它还是得花一些时间的,如果使用 scala来写的话,可以怎么写呢?

  1. implicit val conn: Connection  = transDataSource.getConnection()  
  2. transaction {  
  3.  
  4.     update("""update T_Terminal set Status=9 where TerminalID in   
  5.         (select TerminalID from T_Terminal where TO_CHAR(latestDate, 'yyyymmddHH24miss')<= ? and (status=0 or status=2))  
  6.         """, timeout);  
  7.       
  8.     update("""UPDATE T_TROUBLELOG tl SET tl.SolveDate=TO_DATE(?,'yyyymmddHH24miss') WHERE terminalid IN   
  9.         (SELECT tm.terminalid FROM T_TERMINAL tm,T_TROUBLELOG tl  WHERE tm.Status != 9 AND tm.TerminalID=tl.TerminalID )   
  10.         AND tl.DeviceID='COMMMODULE' AND tl.TroubleID='CommTimeOut' AND tl.SolveDate IS NULL  
  11.         """, transtime);  
  12.  
  13.     val terlist: List[String] = List()  
  14.     query("""SELECT terminalid FROM T_TROUBLELOG tr   
  15.             WHERE tr.DeviceID='COMMMODULE' AND tr.TroubleID='CommTimeOut' AND tr.SolveDate IS NULL   
  16.             GROUP BY  terminalid  
  17.         """).foreach { (row) =>  
  18.         terlist += row("terminalid")  
  19.     }  
  20.     log.debug("查询终端号在故障表中没有未处理的超时记录完成");  
  21.  
  22.     val noterlist: List[String] = List()  
  23.     query("SELECT te.TerminalID FROM T_TERMINAL te WHERE te.status=9").foreach { (row)=>  
  24.         noterlist += row("terminalid")  
  25.     }  
  26.     log.debug("查询超时的终端信息完成" + noterlist.size());  
  27.  
  28.     val psInsert = conn prepareStatement """insert into T_TroubleLog (LogID, TerminalID, DeviceID, TroubleID, HappenDate)   
  29.         values (?, ?, 'COMMMODULE''CommTimeOut', TO_DATE(?,'yyyymmddHH24miss'))"""  
  30.  
  31.     for(val terminalId <- noterlist){  
  32.         psInsert << uuid() << terminalid << transtime <<!  
  33.     }  
  34.  
  35. }  
  36.  

这是一个直译的版本,代码函数为34行,瘦身到25%左右。不仅代码行数更短,而且新的代码的可读性也更高得多。

最近一直在思考,我们对JDBC是否做了过度的包装?包括事务处理,DAO等从EJB1.0时代产生的设计模式,到后续的O-R-M框架,看上去代码是越发简洁,实际上已经远远的远离代码的本质。这种基于Scala的JDBC简单封装,即便于我,也还远不如原始的4GL的简洁,但相比传统的jdbc或者后续的orm、spring+dao等等,则要简化得多。

scala到底能不能投入实际项目应用?开发人员的学习成本有多高?这个问题一直让我痛苦,最近,看到 dcaoyuan 先生的netbeans scala ide,让我重新点燃对scala的欲望,或许,在我们的平台中,接下来就可以尝试 scala了:至少在我看来,scala可以有效的消除我们目前代码中不必要的 DAO 模式以及复杂的事务处理模型等。如果能够在有限的范围内进行尝试,进而进行推广。或许能够在接下来能进一步的提高工作效率。

【责任编辑:杨赛 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

标准C++开发入门与编程实践

本书着重介绍标准C++语言,即1998年由ISO正式推出的关于C++的国际性标准版本。 本书从最基础的编程语言概念讲起,共分6篇24章。前4篇完整...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× Phthon,最神奇好玩的编程语言