Использование Squeryl с актерами Akka

Поэтому я пытаюсь работать как с Squeryl, так и с Akka Actors. Я много занимался поиском, и все, что мне удалось найти, - это следующее сообщение группы Google:

https://groups.google.com/forum/

Я думаю, что мог выстрелить себе в ногу, когда я изначально создал этот фабричный шаблон, чтобы я мог разбрасывать объекты базы данных.

object DatabaseType extends Enumeration {
  type DatabaseType = Value
  val Postgres = Value(1,"Postgres")
  val H2 = Value(2,"H2")
}

object Database {

  def getInstance(dbType : DatabaseType, jdbcUrl : String, username : String, password : String) : Database = {

    Class.forName(jdbcDriver(dbType))
    new Database(Session.create(
      _root_.java.sql.DriverManager.getConnection(jdbcUrl,username,password),
      squerylAdapter(dbType)))

  }

  private def jdbcDriver(db : DatabaseType) = {
    db match {
      case DatabaseType.Postgres => "org.postgresql.Driver"
      case DatabaseType.H2 => "org.h2.Driver"
    }
  }

  private def squerylAdapter(db : DatabaseType) = {
    db match {
      case DatabaseType.Postgres => new PostgreSqlAdapter
      case DatabaseType.H2 => new H2Adapter
    }
  }      
}

Первоначально в своей реализации я пытался окружить все свои операторы с помощью (session), но я продолжал получать страшную ошибку "Нет сессии, связанной с текущим потоком", поэтому я добавил session.bindToCuirrentThread в конструктор.

class Database(session: Session) {

  session.bindToCurrent

  def failedBatch(filename : String, message : String, start : Timestamp = now, end : Timestamp = now) =
batch.insert(new Batch(0,filename,Some(start),Some(end),ProvisioningStatus.Fail,Some(message)))

  def startBatch(batch_id : Long, start : Timestamp = now) =
batch update (b => where (b.id === batch_id) set (b.start := Some(start)))

...more functions

Это работало достаточно хорошо, пока я не попал в Scala Actors.

class TransferActor() extends Actor {

  def databaseInstance() = {
    val dbConfig = config.getConfig("provisioning.database")
    Database.getInstance(DatabaseType.Postgres,
      dbConfig.getString("jdbcUrl"),
      dbConfig.getString("username"),
      dbConfig.getString("password"))
  }

  lazy val config = ConfigManager.current

  override def receive: Actor.Receive = { /* .. do some work */

Я постоянно получаю следующее:

[ERROR] [03/11/2014 17:02:57.720] [provisioning-system-akka.actor.default-dispatcher-4] [akka://provisioning-system/user/$c] No session is bound to current thread, a session must be created via Session.create 
and bound to the thread via 'work' or 'bindToCurrentThread'
Usually this error occurs when a statement is executed outside of a transaction/inTrasaction block
java.lang.RuntimeException: No session is bound to current thread, a session must be created via Session.create 
and bound to the thread via 'work' or 'bindToCurrentThread'

Я получаю новый объект базы данных каждый раз, не кешируя его с ленивым значением val, поэтому разве этот конструктор не должен всегда вызываться и присоединяться к моему текущему потоку? Акка присоединяет разные темы к разным актерам и обменивает их? Должен ли я просто добавить функцию для вызова session.bindToCurrentThread каждый раз, когда я в актере? Похоже, хак.

1 ответ

Акка присоединяет разные темы к разным актерам и обменивает их?

Именно так работает модель актера. Идея состоит в том, что у вас может быть небольшой пул потоков, обслуживающий очень большое количество потоков, потому что актеры должны использовать поток только тогда, когда у них есть сообщение, ожидающее обработки.

Некоторые общие советы для Squeryl.... Сеанс - это связь один-к-одному с соединением JDBC. Основным преимуществом сохранения открытых сессий является то, что вы можете иметь открытую транзакцию, которая дает вам единообразное представление базы данных при выполнении нескольких операций. Если вам это не нужно, сделайте свой код сеанса / транзакции детализированным, чтобы избежать подобных проблем. Если вам это нужно, не полагайтесь на то, что сеансы доступны в локальном контексте потока. Использовать transaction(session){} или же transaction(sessionFactory){} методы явного указания Squeryl, откуда вы хотите, чтобы ваш сеанс пришел.

Другие вопросы по тегам