Usar a mesma conexão

Tenho a seguinte estrutura:

  • Uma única servlet

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
process(req, resp);
}

@Override
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 {
@Override
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 {

@Override
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 {

@Override
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…

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.

Vc diz criar um atributo Connection no DAO?

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í.

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?

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

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

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.

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?

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.

Você poderia me mostrar como fazer dessa forma?

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…

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…

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.

1 curtida

@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?

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?

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

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

@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?

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…

@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.