Caros, apesar dos quase 10 anos de estrada em Java, só agora me aventurei no Spring Framework. Antes tarde do que nunca.
Estou fazendo uma aplicação simples (prova de conceito) para um cliente, usando Java 5, Tomcat, Struts 1.x, Spring e MySQL.
Fiz uma busca simples e funcionou, a inserção de dados (no caminho feliz) funcionou, mas quando lanço uma "RuntimeException", ele faz o commit até o ponto atual e descarta o resto. Eu preciso que ele faça, neste último caso, o rollback de toda a transação.
Estou achando que as configurações utilizadas não atribuem o status de auto commit = false para a conexão com o MySQL. Alguém pode ajudar?
poc.xml[code]<?xml version="1.0" encoding="UTF-8"?>
<Context path="/poc" reloadable="false">
<Resource name="jdbc/mysqlLocal"
auth="Container"
driverClassName="com.mysql.jdbc.Driver"
maxActive="20"
maxIdle="10"
type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/distesdp?autoCommit=false"
username="root"
password=""/>
<ResourceLink global="jdbc/mysqlLocal"
name="jdbc/mysqlLocal"
type="javax.sql.DataSource"/>
</Context>[/code]
struts-config.xml[code]<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<!-- outras configs aqui -->
<action-mappings>
<action path="/insercaoTestes"
type="org.springframework.web.struts.DelegatingActionProxy"
input="/insercaoTestes.jsp" validate="false" name="searchForm" />
</action-mappings>
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/spring-config.xml" />
</plug-in>
</struts-config>[/code]
spring-config.xml[code]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<context:component-scan base-package="poc" />
<context:annotation-config />
<tx:annotation-driven transaction-manager="txManager"/>
<jee:jndi-lookup id="dataSourceMySQLLocal" jndi-name="jdbc/mysqlLocal" />
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceMySQLLocal" />
</bean>
<bean name="/insercaoTestes" class="poc.web.action.InsercaoTestesAction" />
</beans>[/code]
ProdutoDAOJdbc.java[code]package poc.dao;
import java.sql.;
import java.util.;
import javax.annotation.Resource;
import org.springframework.jdbc.core.;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.;
import poc.modelo.Produto;
@Repository
@Transactional(readOnly=true)
public class ProdutoDAOJdbc implements ProdutoDAO {
@Resource(name="dataSourceMySQLLocal")
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public List<Produto> buscarProdutos( String desc ) throws SQLException {
final String sql = "SELECT ...";
desc = "%"+desc.trim().toUpperCase()+"%";
// exemplo usando JDBC Template do Spring
return getJdbcTemplate().query( sql, new Object[]{desc}, new ProdutoMapper() );
}
@Transactional(readOnly=false, propagation = Propagation.REQUIRED)
public void salvarTeste( String nome, String valor ) throws SQLException {
final String sql = "INSERT INTO TESTE (NOME,VALOR) VALUES (?,?)";
// exemplo usando JDBC Template do Spring
getJdbcTemplate().update(sql, new Object[] {nome, valor});
}
private JdbcTemplate getJdbcTemplate() {
if( jdbcTemplate == null ) {
setJdbcTemplate(new JdbcTemplate(dataSource));
}
return jdbcTemplate;
}
private void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
[/code]
CatalogoProdutos.java[code]package poc.business;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import poc.dao.ProdutoDAO;
import poc.modelo.Produto;
@Service
public class CatalogoProdutos {
private static int idx = 0;
@Autowired
private ProdutoDAO dao;
public List<Produto> buscarProdutos( String descricao ) {
try {
return dao.buscarProdutos(descricao);
} catch( Exception e ) {
throw new RuntimeException(e);
}
}
public void salvarDadosTesteTransacao() {
try {
for( int i=0; i< 10; i++ ) {
dao.salvarTeste("Nome "+(++idx),"Valor "+(idx));
if( i==6 ) {
throw new RuntimeException("Erro gerado propositalmente na criação dos dados de teste");
}
}
} catch( Exception e ) {
throw new RuntimeException(e);
}
}
public ProdutoDAO getDao() {
return dao;
}
public void setDao(ProdutoDAO dao) {
this.dao = dao;
}
}[/code]
InsercaoTestesAction.java[code]package poc.web.action;
import javax.servlet.http.;
import org.apache.struts.action.;
import org.springframework.beans.factory.annotation.Autowired;
import poc.dao.*;
public class InsercaoTestesAction extends Action {
@Autowired
private CatalogoProdutos catalogo;
public CatalogoProdutos getCatalogo() {
return catalogo;
}
public void setCatalogo(CatalogoProdutos catalogo) {
this.catalogo = catalogo;
}
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
getCatalogo().salvarDadosTesteTransacao();
} catch (Exception e) {
ActionErrors errors = new ActionErrors();
errors.add("errors", new ActionMessage("msg.error", e.getMessage()));
saveErrors(request, errors);
}
return mapping.getInputForward();
}
}[/code]