transacao.xml
13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
<?xml version='1.0' encoding="utf-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" []>
<chapter id="transacao">
<title>Transação</title>
<para>
Esta funcionalidade utiliza os recursos do CDI para interceptar e delegar adequadamente o tratamento das transações.
Em outras palavras, não reinventamos a roda. Criamos algumas estratégias de delegação e
controle de transação com base no que está sendo mais utilizado no mercado, algumas mais simples de configurar,
outras mais completas para utilizar.
</para>
<para>
Além de plugar e usar as estratégias prontas que fizemos para você, é possível também criar a sua. Vai que você
precise de algo que não pensamos ainda. O importante é que você tenha opções, e uma das opções também é não
utilizar a nossa solução. Caso você esteja utilizando o <emphasis>Demoiselle Framework</emphasis> em conjunto
com outro framework (tais como o JBoss Seam, Spring ou Google Guice) que ofereça o controle de transação,
você pode usá-lo também. Viva a liberdade de escolha!
</para>
<para>
Neste capítulo apresentaremos para você como usar a nossa solução de controle de transação, as estratégias
prontas que oferecemos e a criação de sua própria estratégia.
</para>
<section>
<title>Configurando</title>
<para>
Para um correto funcionamento do Demoiselle é necessário inserir o interceptador de transação no arquivo <filename>src/main/WEB-INF/beans.xml</filename>.
</para>
<programlisting role="XML"><![CDATA[<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<interceptors>
<class>br.gov.frameworkdemoiselle.transaction.TransactionalInterceptor</class>
</interceptors>
</beans>]]></programlisting>
</section>
<section>
<title>Métodos transacionais</title>
<para>
Vamos começar pelo mais importante: como declarar os métodos como transacionais? Como informar ao
<emphasis>Demoiselle Framework</emphasis> que o método deve participar da sessão transacional?
A resposta é muito simples: anote seu método com <literal>@Transactional</literal>.
</para>
<programlisting role="JAVA"><![CDATA[@Transactional
public void inserir() { }]]></programlisting>
<para>
Se você desejar que todos os métodos de sua classe sejam transacionais, anote diretamente a classe:
</para>
<programlisting role="JAVA"><![CDATA[@Transactional
public class Simples {
public void inserir() { }
public void alterar() { }
public void excluir() { }
}]]></programlisting>
<para>
Neste exemplo, os métodos <function>inserir()</function>, <function>alterar()</function> e
<function>excluir()</function> da classe <literal>Simples</literal> participarão do contexto transacional.
</para>
</section>
<section>
<title>E se acontecer uma Exception?</title>
<para>
Caso ocorra uma exceção na execução de um método transacional, o mecanismo fará rollback na transação
automaticamente. É possível mudar este comportamento utilizando exceções de aplicação (para maiores detalhes ver <link linkend="excecao">Exceção</link>).
</para>
<programlisting role="JAVA"><![CDATA[@ApplicationException(rollback = false)
public class AbacaxiException {
}]]></programlisting>
</section>
<section>
<title>O objeto Transaction</title>
<para>
Para ter acesso à instância da transação corrente, basta injetar <literal>TransactionContext</literal> em sua classe e obter a transação corrente.
</para>
<programlisting role="JAVA"><![CDATA[public class Simples {
@Inject
private TransactionContext transactionContext;
public void experimento() {
Transaction transaction = transactionContext.getCurrentTransaction();
}
}]]></programlisting>
</section>
<section>
<title>A estratégia mais adequada</title>
<para>
Para o controle transacional funcionar corretamente é preciso escolher a estratégia mais adequada para o seu
caso. Não existe a bala de prata, você tem que avaliar a melhor estratégia para o seu projeto.
</para>
<para>
Você também pode optar por não utilizar controle de transação. Neste caso, basta não utilizar a anotação <literal>@Transactional</literal>. Contudo,
caso você a utilize, você poderá escolher entre as estratégias JPA, JDBC, JTA (ambas fornecidas pelo <literal>Framework</literal>) e uma estratégia que você
pode criar ou importar para seu projeto.
</para>
<para>
A forma de selecionar cada uma dessas estratégias é descrita abaixo. Caso tente utilizar o controle de transação e não selecione nenhuma estratégia,
o framework lançará uma exceção lhe avisando sobre isto!
</para>
</section>
<section>
<title>Estratégia JDBC</title>
<para>
Esta estratégia, que está disponível na extensão <literal>demoiselle-jdbc</literal>, delega o
controle das transações para o <literal>java.sql.Connection</literal> da
especificação JDBC. Você deve escolher esta estratégia quando estiver persistindo dados
com JDBC e utilizando apenas uma base de dados em sua aplicação. Como um <literal>Connection</literal>
acessa apenas uma base de dados, não há como fazer o controle transacional de base de dados distintas.
</para>
<para>
A transação JDBC é simples de configurar e não exige nenhum recurso externo à sua aplicação.
Para utilizá-la basta que seu projeto adicione no arquivo pom.xml dependência à extensão <literal>demoiselle-jdbc</literal>, que o
Demoiselle fará a seleção por essa estratégia de forma automática.
</para>
<tip><para>Para utilizar a estratégia de transação JDBC, inclua a dependência para extensão JDBC
no arquivo pom.xml.</para>
<programlisting role="XML"><![CDATA[<dependency>
<groupId>br.gov.frameworkdemoiselle</groupId>
<artifactId>demoiselle-jdbc</artifactId>
<scope>compile</scope>
</dependency>]]></programlisting></tip>
</section>
<section>
<title>Estratégia JPA</title>
<para>
Esta estratégia, que está disponível na extensão <literal>demoiselle-jpa</literal>, delega o
controle das transações para o <literal>javax.persistence.EntityManager</literal> da
especificação JPA. Você deve escolher esta estratégia quando estiver persisteindo dados
com JPA e utilizando apenas uma base de dados em sua aplicação. Como um <literal>EntityManager</literal>
acessa apenas uma unidade de persistência, não há como fazer o controle transacional de unidades distintas.
</para>
<para>
A transação JPA é simples de configurar e não exige nenhum recurso externo à sua aplicação.
Para utilizá-la basta que seu projeto adicione no arquivo pom.xml dependência à extensão <literal>demoiselle-jpa</literal>, que o
Demoiselle fará a seleção por essa estratégia de forma automática.
</para>
<tip><para>Caso não esteja utilizando o arquétipo JSF-JPA fornecidos pelo Demoiselle, confira se a dependência para a
extensão está indicada corretamente no arquivo pom.xml.</para>
<programlisting role="XML"><![CDATA[<dependency>
<groupId>br.gov.frameworkdemoiselle</groupId>
<artifactId>demoiselle-jpa</artifactId>
<scope>compile</scope>
</dependency>]]></programlisting></tip>
</section>
<section>
<title>Estratégia JTA</title>
<para>
Esta estratégia, também disponível através de uma extensão (<literal>demoiselle-jta</literal>), é
responsável por delegar o controle de transação para um container JEE. Com a <literal>JTATransaction</literal>
é possível incluir várias unidades de persistência de uma mesma aplicação no mesmo contexto transacional.
Isso mesmo, o famoso <emphasis>Two-Phase Commit (2PC)</emphasis>.
</para>
<para>
A estratégia JTA não serve apenas para persistência em banco de dados, serve também para integrar com
tecnologias que façam acesso ao contexto JTA, como é o caso do EJB. Para ativar esta estratégia basta
que seu projeto adicione no arquivo pom.xml a dependência à extensão <literal>demoiselle-jta</literal>, que o
Demoiselle fará a seleção por essa estratégia de forma automática, pois essa estratégia tem prioridade em relação
à estratégia JPA e JDBC.
</para>
<!--
defina no
arquivo <filename>demoiselle.properties</filename> a seguinte configuração:
</para>
<programlisting>frameworkdemoiselle.transaction.class=br.gov.frameworkdemoiselle.transaction.JTATransaction</programlisting>
-->
<para>
Feito isto, o controle transacional será delegado para a transação acessível via JNDI com o nome
<literal>UserTransaction</literal>. A estratégia acessa o objeto da seguinte maneira:
<literal>Beans.getReference(UserTransaction.class)</literal>. Portanto, para você utilizar esta estratégia,
você precisa de um container JEE ou de um servidor JTA qualquer.
</para>
<para>
Caso você esteja persistindo os dados com JPA, é preciso também informar no arquivo <filename>persistence.xml</filename>
o endereço da conexão JTA gerenciada. Veja um exemplo utilizando o servidor de aplicações JBoss AS7 e com o
provider Hibernate (embutido no JBoss AS) como implementação JPA:
</para>
<programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="bookmark-ds" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
</properties>
</persistence-unit>
</persistence>]]></programlisting>
<tip><para>Caso não esteja utilizando o arquétipo JSF-JPA fornecidos pelo Demoiselle, confira se a dependência para a
extensão está indicada corretamente, no arquivo pom.xml.</para>
<programlisting role="XML"><![CDATA[<dependency>
<groupId>br.gov.frameworkdemoiselle</groupId>
<artifactId>demoiselle-jta</artifactId>
<scope>compile</scope>
</dependency>]]></programlisting></tip>
<para>
Caso você esteja persistindo os dados com JDBC, é preciso informar no arquivo <filename>demoiselle.properties</filename>
o endereço da conexão JTA gerenciada. Veja um exemplo utilizando o servidor de aplicações JBoss AS7:
</para>
<programlisting role="XML"><![CDATA[frameworkdemoiselle.persistence.jndi.name=java:jboss/datasources/ExampleDS]]></programlisting>
</section>
<section>
<title>Criando sua própria estratégia</title>
<para>
Caso nenhuma das estratégias oferecidas sirva para você, crie a sua. Basta escrever uma
classe não-final que implemente a interface <literal>Transaction</literal> do pacote
<literal>br.gov.frameworkdemoiselle.transaction</literal>. <!--Anote a classe com
<literal>@SessionScoped</literal> e <literal>@Alternative</literal> para que o CDI saiba
que se trata de uma estratégia.-->É preciso que sua classe não possua construtores explícitos ou
que possua um construtor público sem parâmetros. É possível fazer injeções nesta classe.
</para>
<!-- import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Alternative;
@Alternative
@SessionScoped -->
<programlisting role="JAVA"><![CDATA[package projeto;
import br.gov.frameworkdemoiselle.transaction.Transaction;
public class MyTransaction implements Transaction {
public void begin() { }
public void commit() { }
public void rollback() { }
public void setRollbackOnly() { }
public int getStatus() { }
public void setTransactionTimeout(int seconds) { }
public boolean isActive() { }
public boolean isMarkedRollback() { }
}]]></programlisting>
<para>
Pronto, é só isso! Agora, os métodos anotados com <literal>@Transactional</literal> irão utilizar a estratégia criada em seu projeto de forma automática,
mesmo que as extensões <literal>demoiselle-jdbc</literal>, <literal>demoiselle-jpa</literal> e <literal>demoiselle-jta</literal> sejam adicionadas ao
projeto, pois o framework dará prioridade máxima à estratégia criada no projeto.
</para>
</section>
<section>
<title>Escolhendo a estratégia manualmente</title>
<para>
Existem alguns casos nos quais você vai ter que definir a estratégia manualmente. Um exemplo é quando seu projeto implementa mais do que uma estratégia
de transação. Outra situação pode acontecer em casos de teste, nos quais você queira utilizar estratégia diferente. Nesses casos você deve definir no
arquivo <filename>demoiselle.properties</filename> qual estratégia será utilizada. Veja alguns exemplos de definição de estratégias própria,
<literal>JDBCTransaction</literal>, <literal>JPATransaction</literal> e <literal>JTATransaction</literal>. É importante notar que apenas uma estratégia
pode estar ativa por vez:
</para>
<programlisting>frameworkdemoiselle.transaction.class=projeto.MyTransaction
frameworkdemoiselle.transaction.class=br.gov.frameworkdemoiselle.transaction.JDBCTransaction
frameworkdemoiselle.transaction.class=br.gov.frameworkdemoiselle.transaction.JPATransaction
frameworkdemoiselle.transaction.class=br.gov.frameworkdemoiselle.transaction.JTATransaction</programlisting>
</section>
</chapter>