Skip to content

Latest commit

 

History

History
252 lines (183 loc) · 8.53 KB

README-PTBR.md

File metadata and controls

252 lines (183 loc) · 8.53 KB

Activate Persistence Framework

Introdução

O Activate é um framework para persistência de objetos em Scala. Ele é um STM (Software Transacional Memory) durável, com persistência plugável. Seu núcleo é o RadonSTM, que provê um poderoso o mecanismo de controle de transações em memória, análogo às transações dos bancos de dados, para controle de concorrência otimista. A durabilidade das transações (persistência) é plugável, sendo possível utilizar persistência em diferentes paradigmas como relacional (JDBC), prevalência (Prevayler) e não relacional (MongoDB).

Benefícios

Os principais benefícios do framework são:

  • Transações atômicas, consistentes, isoladas e duráveis. É possível utilizar as entidades sem se preocupar com problemas de concorrência.
  • As entidades sempre estão consistentes em memória e na camada de persistência. Por exemplo, ao ocorrer rollback, as entidades em memória não ficam em um estado inconsistente.
  • Controle de propagação das transações, incluindo transações aninhadas.
  • Persistência transparente. Basta usar as entidades dentro de transações e elas são automaticamente persistidas.
  • As entidades são carregadas de forma lazy e inicializadas automaticamente quando necessário.
  • As consultas são type-safe e consistentes, inclusive com os objetos criados na transação corrente. Portanto, uma entidade criada na mesma transação pode ser retornada em uma consulta.

Artefatos

Baixe o xsbt sbt-launch.jar e o activate example project.

Crie um script para o chamar o sbt como esse e coloque no path do sistema:

java -XX:MaxPermSize=512m -Xmx512M -noverify -jar /location/of/sbt-launch.jar "$@"

Lembre-se de substituir "/location/of/sbt-launch.jar" com o caminho do sbt-launch.jar baixado. Você pode também chamar essa linha de comando diretamente. Lembre-se de adicionar a opção "-noverify"

Modifique project/ActivateExampleBuild.scala e com/example/foo/ActivateExampleContext.scala para determinar o storage. Memory storage é o padrão.

Chame o sbt dentro da pasta activate-example e crie o projeto eclipse:

$ sbt
> eclipse

Agora você pode importar o projeto no eclipse. É necessário que o plugin do scala esteja instalado http://scala-ide.org/.

Caso deseje alterar o storage, basta alterar as duas classes citadas acima, abrir o console sbt e recriar o projeto eclipse com o mesmo comando ("eclipse").

Utilização

Inicialmente, deve ser criado o contexto do Activate. O contexto deve ser um singleton, portanto faz sentido declarar como "object":

Prevayler

import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.storage.prevayler.PrevaylerMemoryStorage

object prevaylerContext extends ActivateContext {
	def contextName = "prevaylerContext"
	val storage = new PrevaylerMemoryStorage
}

Memória transiente

import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.storage.memory.MemoryStorage

object memoryContext extends ActivateContext {
	def contextName = "memoryContext"
	val storage = new MemoryStorage
}

Oracle

import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.storage.relational.JdbcRelationalStorage
import net.fwbrasil.activate.storage.relational.oracleDialect

object oracleContext extends ActivateContext {
	def contextName = "oracleContext"
	val storage = new SimpleJdbcRelationalStorage {
		val jdbcDriver = "oracle.jdbc.driver.OracleDriver"
		val user = "USER"
		val password = "PASS"
		val url = "jdbc:oracle:thin:@localhost:1521:oracle"
		val dialect = oracleDialect
	}
}

Mysql

import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.storage.relational.JdbcRelationalStorage
import net.fwbrasil.activate.storage.relational.mySqlDialect

object mysqlContext extends ActivateContext {
	def contextName = "mysqlContext"
	val storage = new SimpleJdbcRelationalStorage {
		val jdbcDriver = "com.mysql.jdbc.Driver"
		val user = "root"
		val password = "root"
		val url = "jdbc:mysql://127.0.0.1/test"
		val dialect = mySqlDialect
	}
}

MongoDB

import net.fwbrasil.activate.ActivateContext
import net.fwbrasil.activate.storage.mongo.MongoStorage

object mongoContext extends ActivateContext {
	def contextName = "mongoContext"
	val storage = new MongoStorage {
		val host = "localhost"
		override val port = 27017
		val db = "dbName"
		override val authentication = Option("user", "pass")
	}
}

É importante que o nome do contexto seja único, porém você pode possuir vários contextos na mesma VM.

Para utilizar o contexto, importe ele:

import prevaylerContext._

Desta forma, as classes necessárias como Entity e Query estarão no escopo. As entidades devem estender do trait "Entity":

abstract class Pessoa(var nome: String) extends Entity
class PessoaFisica(nome: String, var nomeMae: String) extends Pessoa(nome)
class PessoaJuridica(nome: String, var diretor: PessoaFisica) extends Pessoa(nome)

É possível declarar as propriedades como val ou var, caso estas sejam imutáveis ou não.

Utilize as entidades sempre dentro de transações:

transactional {
	val pessoa = new PessoaFisica("Fulano", "Maria")
	pessoa.nome = "Fulano2"
	println(pessoa.nome)
}

Não é necessário chamar um método como "store" ou "save" para adicionar a entidade. Apenas a crie, utilize, e ela será persistida.

Consultas:

Execute as consultas dentro de transações:

transactional {
	val result = 
		query {
			(person: Person) => where(person.name :== "Test") select(person)
		}
	for (person <- result)
		println(person.name)
}

Os operadores de consulta disponíveis são :==, :<, :>, :<=, :>=, isNull, isNotNull, :||, :&&, like and regexp. Observe que as queries podem ser feitas sobre super classes (incluindo trait e abstract class).

Existem formas alternativas de consulta. Com o allWhere possível utilizar uma lista de critérios.

transactional {
	val pessoaList1 = all[Pessoa]
	val pessoaList2 = allWhere[PessoaFisica](_.nome :== "Teste", _.nomeMae :== "Mae")
}

Queries utilizando mais de uma entidade ou com propriedades aninhadas:

val q2 = query {
	(empresa: PessoaJuridica, diretor: PessoaFisica) => where(empresa.diretor :== diretor) select (empresa, diretor)
}
val q3 = query {
	(empresa: PessoaJuridica) => where(empresa.diretor.nome :== "Silva") select(empresa)
}

Obs.: Queries que envolvem mais de uma entidade não são suportadas pelo MongoStorage.

Para apagar uma entidade:

transactional {
	for(pessoa <- all[Pessoa])
		pessoa.delete
}

Tipicamente os blocos transacionais são controlados pelo framework. Porém é possível controlar a transação como segue:

val transaction = new Transaction
transactional(transaction) {
	new PessoaFisica("Teste", "Mae")
}
transaction.commit

Definindo a propagação da transação:

transactional {
	val pessoa = new PessoaFisica("Teste", "Mae")
	transactional(mandatory) {
		pessoa.nome = "Teste2"
	}
	println(pessoa.nome)
}

Transações aninhadas são um tipo de propagação:

transactional {
	val pessoa = new PessoaFisica("Teste", "Mae")
	transactional(nested) {
		pessoa.nome = "Teste2"
	}
	println(pessoa.nome)
}

As propagações disponíveis são baseadas nas do EJB:

  • required
  • requiresNew
  • mandatory
  • notSupported
  • supports
  • never
  • nested

Banco de dados

Este é o mapeamento entre os tipos dos atributos das entidades e os tipos dos bancos de dados:

Tipo Mysql Oracle
ID VARCHAR(50) VARCHAR2(50)
Int INTEGER INTEGER
Boolean BOOLEAN NUMBER(1)
Char CHAR CHAR
String VARCHAR VARCHAR2
Float DOUBLE FLOAT
Double DOUBLE DOUBLE PRECISION
BigDecimal DECIMAL NUMBER
Date LONG TIMESTAMP
Calendar LONG TIMESTAMP
Array[Byte] BLOB BLOB
Entity VARCHAR(50) VARCHAR2(50)
Enumeration VARCHAR(20) VARCHAR2(20)
  • Sempre adicione uma coluna "ID" nas tabelas das entidades.
  • O nome da tabela é o nome da classe da entidade.
  • O tipo AbstractInstant (JodaTime) segue o mesmo mapemanento do tipo Date.

Licença

O código é licenciado como LGPL.