[Scala] for 處理exception的問題

承襲[Scala] 客製化Interpolation這邊

今天用for去接Presto source的時候出了點問題

這邊做個記錄記錄一下解決方法

在使用下面這段code去操作presto的時候出現一個狀況

MyQuery.scala
  implicit val conn= getConnection()
  import org.mygod.SQLFactory._
  val tables = for (c <- SQL"Show catalogs";
                    s <- SQL"Show schemas from $c";
                    t <- SQL"Show tables from $s"
  ) yield t

presto接了jmx, hive, mysql三個source

但好死不死MySQL沒開機.因此跑出了下面的exception

[info]   java.sql.SQLException: Query failed (#20150709_022734_00013_gbfsf): com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
[info]   at com.facebook.presto.jdbc.PrestoResultSet.resultsException(PrestoResultSet.java:1799)
[info]   at com.facebook.presto.jdbc.PrestoResultSet.access$100(PrestoResultSet.java:74)
[info]   at com.facebook.presto.jdbc.PrestoResultSet$ResultsPageIterator.computeNext(PrestoResultSet.java:1787)
[info]   at com.facebook.presto.jdbc.PrestoResultSet$ResultsPageIterator.computeNext(PrestoResultSet.java:1760)
[info]   at com.facebook.presto.jdbc.internal.guava.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
[info]   at com.facebook.presto.jdbc.internal.guava.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
[info]   at com.facebook.presto.jdbc.internal.guava.collect.TransformedIterator.hasNext(TransformedIterator.java:43)
[info]   at com.facebook.presto.jdbc.internal.guava.collect.Iterators$5.hasNext(Iterators.java:547)
[info]   at com.facebook.presto.jdbc.PrestoResultSet.next(PrestoResultSet.java:158)
[info]   at com.linecorp.etlv.connector.SQLFactory$SQLHelper$.SQL$extension(PrestoConnector.scala:100)
[info]   ...

如果今天只是用單純的try-catch去解決這問題的話

MyQuery.scala
  implicit val conn= getConnection()
  import org.mygod.SQLFactory._
  try{
    val tables = for (c <- SQL"Show catalogs";
                      s <- SQL"Show schemas from $c";
                      t <- SQL"Show tables from $s"
    ) yield t
  }catch{
    case e:Exception => e.printStackTrace()
  }

就會變成要嘛結果全出來,要嘛全都不出來的情形

但這不是我想要,今天MySQL出問題,那就MySQL的source不要出來就好

但我又不想讓SQL函式呼叫丟回一個空結果,想要直接從現有的for下手

幸好Scala有直接支援try-catch賦值

val result = try{...} catch{...}

可以很簡單的用try-catch去包圍for裡面的條件產生就好

下面一個小範例

//模擬datasource 1
def data1 = {1 to 10}

//模擬datasource 2 在i==5的時候丟出exception
def data2(i:Int) = {
   if(i == 5){
       throw new Exception("QQ")
   }
   1 to j
}

//直接執行
val v= for(i <- data1;
    j <- data2(i)
) yield i + ":" + j

//跑出exception
java.lang.Exception: QQ
  at .data2(<console>:9)
  at $anonfun$1.apply(<console>:10)
  at $anonfun$1.apply(<console>:9)
  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:252)
  at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:252)
  at scala.collection.immutable.Range.foreach(Range.scala:166)
  at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:252)
  at scala.collection.AbstractTraversable.flatMap(Traversable.scala:104)

而接下來使用try-catch賦值的方式改造

val v= for(i <- data1;
    j <- try{data2(i)}catch{case e:Exception => List()}  //這裡改成try-catch賦值
) yield i + ":" + j

//結果:除了i==5的配對其他結果正常顯示
v: scala.collection.immutable.IndexedSeq[String] = Vector(1:1, 2:1, 2:2, 3:1, 3:2, 3:3, 4:1, 4:2, 4:3, 4:4, 6:1, 6:2, 6:3, 6:4, 6:5, 6:6, 7:1, 7:2, 7:3, 7:4, 7:5, 7:6, 7:7, 8:1, 8:2, 8:3, 8:4, 8:5, 8:6, 8:7, 8:8, 9:1, 9:2, 9:3, 9:4, 9:5, 9:6, 9:7, 9:8, 9:9, 10:1, 10:2, 10:3, 10:4, 10:5, 10:6, 10:7, 10:8, 10:9, 10:10)
comments powered by Disqus