pessoal o que vcs acham deste singleton que eu fiz pra poder simplificar minhas execuções sql? ta funcionando corretamente e nao cria mais de uma conexão no banco
/* * To change this template, choose Tools | Templates * and open the template in the editor. */packagebr.com.util;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;/** * * @author Minarini */publicclassSingletonMysql{Connectioncon;privatestaticSingletonMysqlsingleton;privateStringurl;privateStringuser;privateStringpass;privateStringdriverName="com.mysql.jdbc.Driver";privateSingletonMysql()throwsClassNotFoundException,SQLException{url="jdbc:mysql://ip/banco";user="user";pass="senha";Class.forName(driverName);con=(Connection)DriverManager.getConnection(url,user,pass);}/** * * @return * @throws SQLException * @throws ClassNotFoundException */publicstaticSingletonMysqlgetInstance()throwsSQLException,ClassNotFoundException{if(singleton==null){singleton=newSingletonMysql();}returnsingleton;}/** * * @param sql * @return * @throws SQLException * @throws ClassNotFoundException */publicstaticResultSetexecutarSQL(Stringsql)throwsSQLException,ClassNotFoundException{SingletonMysqlstance=SingletonMysql.getInstance();Connectioncon=stance.con;Statementstm=(Statement)con.createStatement();ResultSetrs=(ResultSet)stm.executeQuery(sql);returnrs;}}
para usar foi simples
List<Vector>listaRetorno=newArrayList<Vector>();Stringsql="select * from pessoa order by nome";ResultSetrs=SingletonMysql.executarSQL(sql);while(rs.next()){Vectorv=newVector();v.add(rs.getString("nome"));listaRetorno.add(v);}rs.close();returnlistaRetorno;
reparem que os statments ficam abertos. sera que quando eu fecho meus resultset e minha conexao, isso é fechado tbm?
O singleton parece estar certo, mas eu acho que essas configurações do BD vc poderia colocar em um .properties, fica mais profissional…
B
biro
Se por acaso precisasse utilizá-la em uma aplicação web, em vez de abrir uma conexão(como você fez no construtor), você teria que recuperá-la do pool. Sendo assim, a referência estática de SingletonMysql dentro da sua classe não poderia mais ser estática, visto que ela seria “enxergada” por todas as instâncias que estivessem acessando a aplicação e, consequentemente, todas utilizariam a mesma referência para executar operações com o banco. Se em algum momento uma das instâncias devolver a conexão para o pool, as outras que estiverem utilizando-a para consultas e outras operações com o banco ficarão sem conexão, causando uma SQLException : Conexão fechada!!!
^^
gomesrod
Olá,
A intenção de reaproveitar a conexão para melhorar a performance é até boa, mas tem dois problemas:
A conexão acontece uma so vez na inicialização do aplicativo, se ela der uma falhada já era, você não consegue fazer mais nada a não ser que saia do programa e comece tudo de novo.
Se o aplicativo for Web o impacto é maior ainda, pois além do item anterior ser mais crítico (tem que derrubar a aplicação para todo mundo) vai dar os erros mais estranhos quando mais de uma pessoa estiver usando ao mesmo tempo - pois a conexão é uma só.
Neste tópico aprendi um monte de coisas sobre Singleton, e uma dessas coisas é que o Singleton não é o padrão apropriado quando se tem a intenção de reaproveitar um objeto por motivo de performance ou economia de recursos. Dá uma passada lá no tópico, será bastante esclarecedor.
M
mhc.sor
Apenas um detalhe a acrescentar…
Você poderia adicionar synchronized ao método getInstance()…
Dessa forma você não corre o risco de múltiplas threads gerarem diferentes instâncias para seu Singleton, o que seria um contra-censo.
Se você gosta de estudar mais a fundo os design patterns… dê uma pesquisada a respeito do comportamento de um singleton em múltiplos class loaders…
Precisei estudar sobre isso para corrigir uma funcionalidade no projeto no qual trabalho!
[]s
ViniGodoy
Um jeito ainda melhor é criar o Singleton diretamente:
É tão eficiente quanto, garantido contra código multi-threaded, e mais simples.
Adolpho_Alves
O singleton é muito bacana, o objetivo é criar um obj único para toda a aplicação. Como o ViniGodoy explicou ta perfeito, porem eu já ouvi falar que dá para burlar isso estendendo a classe, isso possibilitaria vc pegar outra lista. Um final na declaração da classe impediria isso. Um experimento bacana é testar sem o final e ver se vc consegue duas conexções para o msm banco, se sim colocar o final e proteger ela contra esteções. Alem de aprimorar seus conhecimentos.
Eu acho possível que msm estendendo a lista permaneça a mesma, já que uma variável estática é uma variável de classe e não de instância.
publicfinalclassSingletonMysql
É uma brincadeira legal.
ViniGodoy
O final não faz a menor diferença, pq o Singleton tem um construtor privado. E isso impede herança sobre o Singleton.
Pode-se burlar um getInstance() usando lazy-loading (diferente do que expliquei), quando usa-se múltiplas threads, caso seu getInstance() não seja sincronizado.
Na verdade, é muitíssíssimo raro sua aplicação precisar de um Singleton. E guardar a conexão MySQL não é uma dessas razões.
arthurminarini
Um jeito ainda melhor é criar o Singleton diretamente:
É tão eficiente quanto, garantido contra código multi-threaded, e mais simples.
criar diretamente onde? no contrutor? se for onde ficam atributos não dá pois da erro
must be caught or declared to be thrown
parece que eu não posso continuar com esse meu contrutor por isso que ele esta apitando
arthurminarini
ivandasilva:
Pow cara usar Vector é mal hein…
O singleton parece estar certo, mas eu acho que essas configurações do BD vc poderia colocar em um .properties, fica mais profissional…
o que vc recomenda ale do vector, pois uso dwr e fazendo um list de vector me retorno um json
arthurminarini
biro:
Se por acaso precisasse utilizá-la em uma aplicação web, em vez de abrir uma conexão(como você fez no construtor), você teria que recuperá-la do pool. Sendo assim, a referência estática de SingletonMysql dentro da sua classe não poderia mais ser estática, visto que ela seria “enxergada” por todas as instâncias que estivessem acessando a aplicação e, consequentemente, todas utilizariam a mesma referência para executar operações com o banco. Se em algum momento uma das instâncias devolver a conexão para o pool, as outras que estiverem utilizando-a para consultas e outras operações com o banco ficarão sem conexão, causando uma SQLException : Conexão fechada!!!
^^
opa eu estou em uma aplicação web com hibernate no sqlserver, contruir um singleton para consulta em uma base mysql simples
minha aplicação não usa este banco para dados pesados. o hibernate eu tenho um poll no glassfish mas para o mysql não tenho
arthurminarini
gomesrod:
Olá,
A intenção de reaproveitar a conexão para melhorar a performance é até boa, mas tem dois problemas:
A conexão acontece uma so vez na inicialização do aplicativo, se ela der uma falhada já era, você não consegue fazer mais nada a não ser que saia do programa e comece tudo de novo.
Se o aplicativo for Web o impacto é maior ainda, pois além do item anterior ser mais crítico (tem que derrubar a aplicação para todo mundo) vai dar os erros mais estranhos quando mais de uma pessoa estiver usando ao mesmo tempo - pois a conexão é uma só.
Neste tópico aprendi um monte de coisas sobre Singleton, e uma dessas coisas é que o Singleton não é o padrão apropriado quando se tem a intenção de reaproveitar um objeto por motivo de performance ou economia de recursos. Dá uma passada lá no tópico, será bastante esclarecedor.
e se no meu getstance eu verificas se tem conexao caso nao eu crio uma nova o qeu vc acha
ViniGodoy
arthurminarini:
ivandasilva:
Pow cara usar Vector é mal hein…
O singleton parece estar certo, mas eu acho que essas configurações do BD vc poderia colocar em um .properties, fica mais profissional…
o que vc recomenda ale do vector, pois uso dwr e fazendo um list de vector me retorno um json
Sim, no construtor. Você pode fazer lá um try…catch e disparar essas exceptions dentro de uma RuntimeException:
privateSingletonMysql(){url="jdbc:mysql://ip/banco"; user = "user"; pass = "senha"; try { Class.forName(driverName); con = (Connection) DriverManager.getConnection(url, user, pass); } catch (Exception e) { throw new RuntimeException("Impossívelcriarconexão",e);}}
a) Você trabalhe com um Pool de Conexões (veja o C3P0 ou o Jakarta DBCP);
b) Você feche ResultSets, Statements e Conexões por padrão (o pool irá evitar o fechamento imediato, mas não manterá conexões ociosas para sempre);
Se quiser facilitar a manipulação disso, dê uma olhada nas classes de BD do Spring. Elas facilitam muito o uso de BD, mas mantém uma sintaxe bem parecida com a do Java. Por padrão, o Spring lançara RuntimeExceptions (evitando esses try e throws todos), além de fechar automaticamente statements e resultsets.
mas estou com apenas um problema que foi citado por um dos companheiros. Se a conexão falhar ja era. como posso fazer um adaptação para conectar em caso de falha na conexão durante o dia ou um periodo de tempo?
ViniGodoy
Agora que vc captura a exception e lança um Runtime no lugar, pode tirar fora o throws do seu construtor. Aliás, evite ficar dando "throws" cegamente em suas exceptions. Pense em como trata-las corretamente.
Além disso, é imprescindível fechar Statements e o ResultSet o mais rápido possível.
Finalmente, se você vai fazer um método dentro da própria classe do Singleton, não é obrigado a ficar chamando SingletonMysql.getInstance(). Use a propriedade interna diretamente.
agora parece que ta bom. pelo menos nao tem nada aberto mais o que vc acha
publicfinalclassSingletonMysql{privatestaticSingletonMysqlsingleton=newSingletonMysql();privateSingletonMysql(){try{Class.forName("com.mysql.jdbc.Driver");}catch(Exceptione){thrownewRuntimeException("Driver de conexão não encontrado",e);}}publicstaticSingletonMysqlgetSingleton(){returnsingleton;}publicstaticCachedRowSetexecutarSQL(Stringsql){try{Connectioncon=(Connection)DriverManager.getConnection("jdbc:mysql://ip/banco","user","senha");try{Statementstm=null;ResultSetrs=null;try{stm=con.createStatement();rs=stm.executeQuery(sql);CachedRowSetrowset=newCachedRowSetImpl();rowset.populate(rs);returnrowset;}finally{if(stm!=null){stm.close();}if(rs!=null){rs.close();}if(con!=null){con.close();}}}catch(SQLExceptione){thrownewRuntimeException("Impossível executar consulta: "+sql,e);}}catch(Exceptione){thrownewRuntimeException("Impossível criar conexão",e);}}}
arthurminarini
ow vou ter que tirar o CachedRowSet ! ele é deprecated. não posso arrirscar de colocar no meu sistema pois futuramente ele será removido :shock:
tenho que fazer algo com o ResultSet mesmo mas tendo alguma forma de fechar igual ao codigo acima, com o resultset não deixa, ele só funciona se a conexao estiver aberta isso é ruim pra mim. pois vou ficar com uma conexao aberta atoa ate o fim dela
Andre_Fonseca
arthurminarini:
ow vou ter que tirar o CachedRowSet ! ele é deprecated. não posso arrirscar de colocar no meu sistema pois futuramente ele será removido :shock:
tenho que fazer algo com o ResultSet mesmo mas tendo alguma forma de fechar igual ao codigo acima, com o resultset não deixa, ele só funciona se a conexao estiver aberta isso é ruim pra mim. pois vou ficar com uma conexao aberta atoa ate o fim dela
o fato de ser deprecated não quer dizer que vai ser removido, existe a questão da compatibilidade… mas sim que este código nao vai mais sofrer correções e melhorias…
ViniGodoy
arthurminarini:
ow vou ter que tirar o CachedRowSet ! ele é deprecated. não posso arrirscar de colocar no meu sistema pois futuramente ele será removido :shock:
tenho que fazer algo com o ResultSet mesmo mas tendo alguma forma de fechar igual ao codigo acima, com o resultset não deixa, ele só funciona se a conexao estiver aberta isso é ruim pra mim. pois vou ficar com uma conexao aberta atoa ate o fim dela
Sugestão mesmo? Use o Spring. O código fica quase igual, mas sem esse monte de try…catch. E vc ainda coloca um conection pool integrado.
B
breno500as
Em relação aos Statements ou PrepareStatements, acho importante que eles sejam fechados,
se você não fecha um statement um cursor fica aberto no seu banco de dados…
Já tive alguns problemas de inserções e updates feitos ao mesmo tempo e várias vezes na aplicação sem fechar
os statements, consumindo todos os cursores que estavam disponíveis no Oracle…
arthurminarini
André Fonseca:
arthurminarini:
ow vou ter que tirar o CachedRowSet ! ele é deprecated. não posso arrirscar de colocar no meu sistema pois futuramente ele será removido :shock:
tenho que fazer algo com o ResultSet mesmo mas tendo alguma forma de fechar igual ao codigo acima, com o resultset não deixa, ele só funciona se a conexao estiver aberta isso é ruim pra mim. pois vou ficar com uma conexao aberta atoa ate o fim dela
o fato de ser deprecated não quer dizer que vai ser removido, existe a questão da compatibilidade… mas sim que este código nao vai mais sofrer correções e melhorias…
onde posso achar uma fonte sobre isso? o que eu ja vi ate hj era que ia ser removida em alguma versão futura
arthurminarini
veja
warning: com.sun.rowset.CachedRowSetImpl is Sun proprietary API and may be removed in a future release
Se você não quer usar o CachedRowSetImpl (esse warning está desde o Java 2), então procure o Spring, que já comentei, ou use uma API de persistência, como o Hibernate. Outra alternativa é fazer você mesmo uma classe que faça a leitura integral do ResultSet e transforme tudo em objetos, garantindo o fechamento de tudo ao final.
O que não pode fazer é deixar coisas abertas. Isso provocará o estouro da sua aplicação, cedo ou tarde.