2016-11-02 1 views
1

私はトランザクションのコードブロックを囲むことができるようにしたい。どのように暗黙のパラメータのコールコードに不可知論をフードの下で渡すようにするか?

def transactional(block: => Unit): Unit = { 
    implicit val conn: Connection = ??? 

    conn.begin() 
    try { 
    block 
    conn.commit() 
    } catch { 
    case ex: Exception => 
     conn.rollback() 
     throw ex 
    } finally { 
    conn.close() 
    } 
} 

save方法は、接続して何かをする必要がありますが、私がしたい:私はこのようなtransactional機能を作るために考え

transactional { 
    save("something") 
} 

:呼び出し元のコードは、このような単純なする必要があります呼び出しコードをそれに不可知論にする(上記参照)。私はこのように素朴に実装しました。

def save(operation: String)(implicit conn: Connection): Unit = { 
    println(s"saving $operation using $conn") 
} 

もちろん、接続が見つからないというコンパイルエラーが発生します。接続をtransactionalファンクションからsaveファンクションに接続するには、どの部分が欠けていますか?

答えて

2

transactional関数を次のように変更します(トランザクションのコードスニペットを参照してください)。ここでの問題は、トランザクションでは接続が利用可能ですが、暗黙的に関数を保存する必要があります。したがって、接続オブジェクトを取得すると、トランザクション内で実行される関数に渡します。次に、このコード(f)は接続にアクセスできます。 fが接続にアクセスすると暗黙のキーワードを使用してimplicitにすることができます。暗黙のうちに接続を取るsaveのような関数は、トランザクション内でシームレスに呼び出すことができます。 =>ユニット)パスF(F:代わりのコードブロック(ブロック通過

1をトランザクションする

重要な変更)トランザクションの内部接続=>ユニット)

2)は、接続オブジェクトにfを適用します接続オブジェクトへのfアクセスを与える。あなたは機能を保存した場合

def transactional(f: Connection => Unit): Unit = { 
    val conn = getConnectionFromDatabase() 
    conn.begin() 
    try { 
    f(conn) 
    conn.commit() 
    } catch { 
    case ex: Exception => 
     conn.rollback() 
     throw ex 
    } finally { 
    conn.close() 
    } 
} 

今、あなたはこの

transactional { implicit conn => 
    save("something") 
} 

のようにそれを使用することができますそして、あなたはあなたができる接続

transactional(save("foo")) 
+0

は修正されたバージョンは私が呼び出し元のコードのうち、接続を残すことができます、ありがとうございます。また、Tzach Zoharの答えでは、save関数のまわりでコードをラップすることができますが、それでも機能します。私はその理由でこの答えを受け入れます。ラッピングが必要ない場合、彼の答えはややシンプルです。 –

1

なしで行くことができます。この

def save(str: String): Connection => Unit = ??? 

のようなものですを使わずに、および呼び出し側のコードを変更せずに、接続を期待する機能save戻り場合:

def transactional(block: Connection => Unit): Unit = { 
    val conn: Connection = ??? 

    // stuff.. 
    block(conn) 
    // stuff.. 
} 

def save(operation: String): Connection => Unit = { conn => 
    println(s"saving $operation using $conn") 
} 

transactional { 
    save("something") 
} 
+0

ありがとう、これは動作します。今私はもう一つ質問があります。 save( "something") 'を' for(i < - 1〜3){save( "something")} 'に置き換えると、動作しません。その上の任意のアイデア? –

+0

Jeroenは、 'transactional'より上のコードで、' Connection => Unit'型の引数を期待しています。 save()はそれを正確に返します。 'for'ループはそうではありません。 –

関連する問題