Usar a mesma conexão

19 respostas Resolvido
javamysql
P

Tenho a seguinte estrutura:

  • Uma única servlet
<a class="mention" href="/u/override">@Override</a>

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

process(req, resp);

}
<a class="mention" href="/u/override">@Override</a>

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

process(req, resp);

}

private void process(HttpServletRequest req, HttpServletResponse res) throws ServletException{

String path = req.getServletPath();
  path = path.substring(1, path.indexOf("."));
  
  String actionClass = actions.getProperty(path);
  
  if(actionClass == null){
  	throw new ServletException("Url não encontrada. Verifique o endereço digitado");
  }			
  
  try{			
  	Action action = (Action) Class.forName(actionClass).newInstance();
  	action.setRequest(req);
  	action.setResponse(res);
  	action.runAction();
  } catch (Exception e) {
  	throw new ServletException(e);
  }

}

  • Uma Action Abstrata

public abstract class Action {

private HttpServletRequest request;
private HttpServletResponse response;

public abstract void process() throws Exception;

public void runAction() throws Exception{		

Connection connection = DbConnectionFactory.getInstance();

try{

process();

connection.commit();

}catch (Exception e) {

connection.rollback();

throw new ActionException(e);

}finally {

connection.close();

}

}
  • Actions que extendem a Action abstrata e implementam o método process();
public class TripSaveAction extends Action {

<a class="mention" href="/u/override">@Override</a>

public void process() throws Exception {

Trip trip = new Trip();
TripService tripService = new TripService();
  tripService.save(trip);

  redirect("index.html");

}
}

  • Service pode chamar um DAO

public class TripService extends Service {

<a class="mention" href="/u/override">@Override</a>

public Trip save(Trip trip) throws Exception{

try{

TripDao tripDao = new TripDao();

return tripDao.save(trip);

}catch (Exception e) {

throw new ServiceException(e.getMessage());

}

}
  • Por fim, DAOs

public class TripDao extends Dao {

<a class="mention" href="/u/override">@Override</a>

public Trip save(Trip trip) throws Exception{

try{

PreparedStatement stmt = DbConnectionFactory.getInstance().prepareStatement("INSERT INTO

Estou com dúvida em como usar a conexão/transação que é aberta na Action Abstrata no meu DAO… para que ao final seja feito o commit() ou rollback() em caso de erro…do jeito que esta agora… o DAO pega outra conexão no pool…

19 Respostas

D

Primeiro, mude a estrutura e coloque todas as conexões passando pelo DAO.
Depois, crie os métodos que precisa para cada ação com o banco de dados, no DAO.
Isso resolve os problemas que você tem.

P

Vc diz criar um atributo Connection no DAO?

D

Sim.
Até onde entendo, DAO é a camada que irá conversar com a base de dados. As demais acessam o DAO e todo o processo que dependa da persistência é abstraído a partir daí.

P

Fiquei com uma dúvida…se eu abrir a Conexão no DAO… fazer o INSERT…commit se der certo e rollback se der erro… caso esse insert dependa de outro insert… pode ser q parte das informações sejam salvas e outras não ne… pq cada DAO terá sua transação… ou não?

D

Se você fizer do DAO um singleton, não.

P

Ai eu não acabaria voltando para esse problema: Ajuda com Singleton ??

D

Sim, pode incorrer neste erro novamente.
A questão é que você precisa analisar a tua necessidade e fazer opções pelo que melhor te atende.
Uma opção seria abrir a conexão como auto commit false e, então, tentar controlar as ações na camada de negócios, se todas as alterações na base (insert, update ou delete) ocorrerem sem erros, basta invocar o commit. Caso contrário, invocar o rollback.

P

Penso nisso…
Já abro a conexão com autocommit false… no caso eu tiraria a abertura da conexão da Action abstrata e abriria e fechava em cada Service… por que ai o service poderia chamar “N” DAOs…

Mas como eu passaria a conexão do Service pro DAO? No construtor do DAO? ou em cada Método do DAO?

D

Particularmente eu não gosto dessa abordagem, penso que as conexões se abrem no DAO, você controla a sequência de alterações no service, dentro de um bloco try/catch e garante que chamará o commit ou rollback quando necessário.

P

Você poderia me mostrar como fazer dessa forma?

P

Eu estou em dúvida…onde abrir a conexão e controlar a transação… No Service ou no DAO…

Se for no DAO… como fazer quando um service precisar chamar DAOs diferentes que precisam executar todos com sucesso ou nenhum… pq se a conexão estiver no DAO…cada um dará o seu commit né? E pode funcionar um e outro não…

L

Ao invés de fazer a Action, não seria menos trabalhoso usar um filtro http?

https://www.caelum.com.br/apostila-java-web/recursos-importantes-filtros/

Você pode criar um filtro que abra uma conexão a cada requsição e garante seu fechamento assim que foi processado… na apostila há exemplos…

D

Para isso, normalmente, se utiliza uma classe separada. Eu denomino a mesma como ConnectionUtil, que terá métodos para criar a conexão, fechar a conexão, executar rollback e executar o commit (estáticos ou não).
O método que abre a conexão verifica se a conexão é nula, se for, cria uma nova, senão, devolve a corrente.
Eu ainda não entendi qual a tua necessidade, talvez explicar qual o contexto do problema facilite o entendimento e o apontamento de uma solução. Seguir o que o @LostSoldier sugeriu é uma boa também.

P

@drsmachado eu estava fazendo isso… uma conexão unica para a aplicação através de um Singleton…e encontrei problemas (Leia aqui >> Ajuda com Singleton )… Então…estou partindo para a opção de abrir uma conexão (Na verdade pega uma do pool) sempre que necessário… Porém estou com muita dúvida em abrir a conexão no DAO…pq estou usando setAutoCommit(false) logo eu preciso controlar o commit() e rollback().

Tenho a necessidade de fazer:

Dao1.save();

Dao2.save();

Dao3,save();

e garantir q os 3 sejam feitos com sucesso ou rollback caso algum de problema…

Se eu abro a conexão em cada DAO… e dou commit em cada DAO… os que funcionarem vão persistir no banco…e os que derem erro não…

Como alternativa, penso em criar a conexão no SERVICE…abrir a conexão no sERVICE e fazer o commit ou rollback no SERVICE… mas os DAOs precisam de conexão…como mando a conexão do SERVICE para o DAO usar? Através do construtor do DAO? Através de um metodo setConexao do DAO? Essa seria a melhor forma?

P

Pq eu abriria uma conexão no filtro e fecharia tbm no filtro… se tudo desse certo faria o commit e em caso de erro eu faria o roolback…mas como eu enviaria essa conexão do filtro para o DAO?

L

Como disse anteriormente, há exemplos no link que mostrei…

// "pendura um objeto no Request"    
request.setAttribute("connection", connection);
P

@LostSoldier sim… depois que eu colocar a conexão na request…eu terei que mandá-la para o meu DAO… (No meu caso antes para o meu SERVICE e depois para o DAO) e continuo com a mesma dúvida…

Envio a conexão pelo construtor? Por um método setConexao? Qual a melhor forma de fazer isso?

L
Solucao aceita

O ideal seria via construção, assim o DAO não tem responsabilidade de abrir, fechar, etc, apenas usa a conexão, dessa forma você está aplicando o conceito de Inversão de Controle

Além do mais, nesse caso o DAO não precisa de um setConexao, métodos set a grosso modo são para mudar o estado do objeto, e no seu caso creio que não se aplica, já que vocẽ precisa de uma conexão pronta e inalterada…

D

@picklesdog70 me parece que você precisa de algo como o Open Session In View, embora não esteja utilizando um framework JPA, pode adaptar essa abordagem à tua necessidade.

Criado 7 de março de 2017
Ultima resposta 10 de mar. de 2017
Respostas 19
Participantes 3