Qual framework de persintência utilizar?

polui muito.

O iBatis ajuda exatamente nisso. Todos seus sqls ficarão em arquivos XMLs simples. Vc ainda terá uma camada de persistência (DAO) mas sua camada não fala jdbc. Ela simplismente delega isso pro ibatis.

Cara, para a configuração de aplicação que foi mencionada (uma aplicação orientada à banco), seira uma das possíveis soluções sim. Se é a melhor depende de muitos outros detalhes. Só pra dar um exemplo: é possível que sua equipe torça o nariz e nem tente aprender a usar a ferramenta e, por melhor que seja, pode acabar afundando seu projeto.

Eu sugiro iBatis pq é um dos mais utilizados mas existem outros. Não aconselho o hibernate pra esse caso pq seu banco foi modelado sem levar em consideração qq necessidade desse framework.

Já cansei de ver gente reclamando do hibernate simplesmente por telo adotado em situações onde ele não é recomendado:

  • Se vc tem baixo controle do modelo de dados (o modelo é legado, possui regras rígidas de alteração ou limitação da utilização de recursos do banco)
  • O hibernate gera querys (DDL, MDL, sei lá) dinâmicamente - por essas serem geradas dinâmicamente não são passíveis de tunning (algumas empresas grandes proíbem o hibernate por isso).

O hibernate é ótimo - não me entenda mal. Só não é recomendado para seu caso.

[quote=ddduran]não, não seria tão ruim uma coisa legal do hibernate é que ele lhe permite sempre que for preciso passar por cima do framework.
Apenas analise seu sistema melhor para não acabar usando hibernate (ou qualquer outro framework) só por usar[/quote]

Desculpe, não concordo. IMO.
JDBC puro só pra coisas muito simples (não comerciais) …
Então acho que no caso de persistência, só por usar, ainda vale.

veja:
http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=78&t=000939

Woody

Toda regra de negócios no banco já não é uma boa solução pra todos os casos, então: não irá resolver todos seus problemas mas não vai te limitar na implementação da solução.

quanto ao aprendizado da equipe nao vejo problemas somos apenas dois, mas de inicio sou eu quem vai dar o pontape inicial estou mesmo tirando o maior número de duvidas possiveis para nao me arrepender depois, por exemplo eu pretendo trabalhar com as seguintes ferramentas Struts2 + Spring + iBatis que conforme estou vendo e a melhor solucao para mim.

estava lendo o manual do iBatis existe alguma forma de eu usar o Insert Into Teste(descricao) Values (‘xxxx’) Returning Id e uma construcao na qual eu posso utilizar no oracle, ou eu tenho que utilizar o selectKey que ele demonstra do manual ?

Desde já agradeço a todos pelas opiniões…

Atenciosamente …

Luciano Antunes

Só a título de exemplo:

Arquivo projeto.xml[code]<?xml version=“1.0” encoding=“ISO-8859-1” ?>
<!DOCTYPE sqlMap PUBLIC
“-//ibatis.apache.org//DTD SQL Map 2.0//EN”
http://ibatis.apache.org/dtd/sql-map-2.dtd”>

<!–
Author: Anaximandro de Godinho.
Versão: $Revision: 1.20 $
–>

<sqlMap namespace=“Projeto”>

&lt;!-- Alias do "Transfer Object" da entidade "Projeto Base" utilizado nos resultados. --&gt;
&lt;typeAlias alias="ProjetoTO" type="br.com.cvrd.igrm.to.ProjetoTO" /&gt;

&lt;!-- Mapeamento do "Transfer Object" da entidade "Projeto". --&gt;
&lt;resultMap id="ProjetoResult" class="ProjetoTO"&gt;
	&lt;result property="idProjeto"		column="FVGIDPRO" /&gt;
	&lt;result property="idModelo"			column="FVGIDMOD" /&gt;
	&lt;result property="idProjetoPai"		column="FVGIDPRF" /&gt;
	&lt;result property="nome"				column="FVGNMPRO" /&gt;
	&lt;result property="idAlternativo"	column="FVGALPRO" /&gt;
	&lt;result property="contexto"			column="FVGCXPRO" /&gt;
&lt;/resultMap&gt;

&lt;sql id="_selectProjeto"&gt;
	SELECT	FVGIDPRO,
			FVGIDMOD,
			FVGIDPRF,
			FVGNMPRO,
			FVGALPRO,
			${DBALIAS}.IGRM.obterContextoCorporativo( FVGNMPRO, FVGIDPRF, FVGIDMOD ) as FVGCXPRO
	FROM	${DBALIAS}.FVGPROJT
&lt;/sql&gt;

&lt;sql id="_orderByNomeProjeto"&gt;
	ORDER
	BY		FVGNMPRO
&lt;/sql&gt;

&lt;select id="obter_Projetos" resultSetType="FORWARD_ONLY" fetchSize="50" resultMap="ProjetoResult"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	&lt;include refid="_orderByNomeProjeto" /&gt;
&lt;/select&gt;

&lt;select id="obter_Projeto" resultSetType="FORWARD_ONLY" fetchSize="1" resultMap="ProjetoResult" parameterClass="Integer"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGIDPRO = #idProjeto#
&lt;/select&gt;

&lt;select id="obter_ProjetoPorIdAlternativo" resultSetType="FORWARD_ONLY" fetchSize="1" resultMap="ProjetoResult" parameterClass="String"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGALPRO = #idAlternativo#
&lt;/select&gt;

&lt;select id="obter_ProjetoPorNome" resultSetType="FORWARD_ONLY" fetchSize="1" resultMap="ProjetoResult" parameterClass="String"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGNMPRO = #nomeProjeto#
&lt;/select&gt;

&lt;select id="contar_ProjetosRaiz" resultSetType="FORWARD_ONLY" fetchSize="1" resultClass="Integer"&gt;
	SELECT	Count( 1 ) AS Quantidade
	FROM	${DBALIAS}.FVGPROJT
	WHERE	FVGIDPRF IS NULL
&lt;/select&gt;

&lt;select id="obter_ProjetosRaiz" resultSetType="FORWARD_ONLY" fetchSize="50" resultMap="ProjetoResult"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGIDPRF IS NULL
	&lt;include refid="_orderByNomeProjeto" /&gt;
&lt;/select&gt;

&lt;select id="contar_ProjetosPorProjetoPai" resultSetType="FORWARD_ONLY" fetchSize="1" resultClass="Integer" parameterClass="Integer"&gt;
	SELECT	COUNT( FVGIDPRO )
	FROM 	${DBALIAS}.FVGPROJT
	WHERE 	FVGIDPRF = #idProjetoPai#
&lt;/select&gt;

&lt;select id="obter_ProjetosPorProjetoPai" resultSetType="FORWARD_ONLY" fetchSize="50" resultMap="ProjetoResult" parameterClass="Integer"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGIDPRF = #idProjetoPai#
	&lt;include refid="_orderByNomeProjeto" /&gt;
&lt;/select&gt;

&lt;insert id="incluir_Projeto" parameterClass="ProjetoTO"&gt;
	&lt;selectKey type="pre" resultClass="Integer" keyProperty="idProjeto"&gt;
		SELECT ${DBALIAS}.FVGPROJT_S01.NextVal AS ID FROM DUAL
	&lt;/selectKey&gt;
	INSERT 
	INTO	${DBALIAS}.FVGPROJT(
			FVGIDPRO,
			FVGIDMOD,
			FVGIDPRF,
			FVGNMPRO,
			FVGALPRO
	) VALUES (
			#idProjeto#,
			#idModelo#,
			#idProjetoPai#,
			#nome#,
			#idAlternativo#
	)
&lt;/insert&gt;

&lt;update id="alterar_Projeto" parameterClass="ProjetoTO"&gt;
	UPDATE	${DBALIAS}.FVGPROJT
	SET		FVGIDMOD = #idModelo#,
			FVGIDPRF = #idProjetoPai#,
			FVGALPRO = #idAlternativo#,
			FVGNMPRO = #nome#
	WHERE	FVGIDPRO = #idProjeto#
&lt;/update&gt;

&lt;delete id="excluir_Projeto" parameterClass="Integer"&gt;
	DELETE
	FROM	${DBALIAS}.FVGPROJT
	WHERE	FVGIDPRO = #idProjeto#
&lt;/delete&gt;

<!-- especificos -->

&lt;select id="contar_ProjetosPorModelo" resultSetType="FORWARD_ONLY" fetchSize="1" resultClass="Integer" parameterClass="Integer"&gt;
	SELECT	COUNT( FVGIDPRO )
	FROM 	${DBALIAS}.FVGPROJT
	WHERE 	FVGIDMOD = #idModelo#
&lt;/select&gt;

&lt;select id="obter_ProjetosPorModelo" resultSetType="FORWARD_ONLY" fetchSize="50" resultMap="ProjetoResult" parameterClass="Integer"&gt;
	&lt;include refid="_selectProjeto" /&gt;
	WHERE	FVGIDMOD = #idModelo#
	AND 	FVGIDPRF IS NULL 
	&lt;include refid="_orderByNomeProjeto" /&gt;
&lt;/select&gt;

</sqlMap>[/code]

Classe AbstractProjeto.[code]package br.com.cvrd.igrm.dao.comum;

import java.sql.SQLException;
import java.util.List;

import br.com.cvrd.igrm.to.IProjetoTO;
import br.com.cvrd.igrm.util.AbstractDAO;
import br.com.cvrd.igrm.util.PersistenceException;

/**

  • Template das classes de persistência das entidades dos projetos do modelo base e

  • corporativo.

  • @author Anaximandro de Godinho.

  • @version $Revision: 1.2 $
    /
    public abstract class AbstractProjetoDAO extends AbstractDAO
    {
    /
    / constantes públicas /*/
    public static final String P_Projeto = “Projeto.”;
    public static final String P_ProjetoBase = “ProjetoBase.”;

    /**

    • Construtor.

    • @param namespace o namespace do xml do sqlMaps a ser utilizado.
      */
      public AbstractProjetoDAO( final String namespace )
      {
      _obter_Projeto = namespace + “obter_Projeto”;
      _obter_ProjetoPorIdAlternativo = namespace + “obter_ProjetoPorIdAlternativo”;
      _obter_ProjetoPorNome = namespace + “obter_ProjetoPorNome”;

      _contar_ProjetosRaiz = namespace + “contar_ProjetosRaiz”;
      _obter_ProjetosRaiz = namespace + “obter_ProjetosRaiz”;

      _contar_ProjetosPorProjetoPai = namespace + “contar_ProjetosPorProjetoPai”;
      _obter_ProjetosPorProjetoPai = namespace + “obter_ProjetosPorProjetoPai”;

      _incluir_Projeto = namespace + “incluir_Projeto”;
      _alterar_Projeto = namespace + “alterar_Projeto”;
      _excluir_Projeto = namespace + “excluir_Projeto”;
      }

    /**

    • Retorna o TO com os dados da linha da entidade projeto correspondente à chave fornecida.
    • @param idProjeto a chave do projeto.
    • @return o TO com os dados da linha da entidade projeto correspondente à chave fornecida.
    • @throws PersistenceException
      */
      public IProjetoTO obterProjeto( final Integer idProjeto ) throws PersistenceException
      {
      try
      {
      return (IProjetoTO) _sqlMap.queryForObject( _obter_Projeto, idProjeto );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna o TO com os dados da linha da entidade projeto correspondente à chave alternativa fornecida.
    • @param idAlernativo a chave alternativa do projeto.
    • @return o TO com os dados da linha da entidade projeto correspondente à chave alternativo fornecida.
    • @throws PersistenceException
      */
      public IProjetoTO obterProjetoPorIdAlternativo( final String idAlternativo ) throws PersistenceException
      {
      try
      {
      return (IProjetoTO) _sqlMap.queryForObject( _obter_ProjetoPorIdAlternativo, idAlternativo );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna o TO com os dados da linha da entidade projeto correspondente ao nome fornecido.
    • @param nomeProjeto o nome do projeto.
    • @return o TO com os dados da linha da entidade projeto correspondente ao nome fornecido.
    • @throws PersistenceException
      */
      public IProjetoTO obterProjetoPorNome( final String nomeProjeto ) throws PersistenceException
      {
      try
      {
      return (IProjetoTO) _sqlMap.queryForObject( _obter_ProjetoPorNome, nomeProjeto );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna a quantidade de linhas na entidade projeto com projetos no raiz.
    • @return a quantidade de linhas na entidade projeto com projetos no raiz.
    • @throws PersistenceException
      */
      public int contarProjetosRaiz() throws PersistenceException
      {
      try
      {
      return ( (Integer) _sqlMap.queryForObject( _contar_ProjetosRaiz ) ).intValue();
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna uma lista de TOs com os dados das linhas da entidade projeto com projetos no raiz.
    • @return uma lista de TOs com os dados das linhas da entidade projeto com projetos no raiz.
    • @throws PersistenceException
      */
      public List obterProjetosRaiz() throws PersistenceException
      {
      try
      {
      return _sqlMap.queryForList( _obter_ProjetosRaiz );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna a quantidade de linhas na entidade projeto com o idProjetoPai fornecido.
    • @param idProjetoPai a chave do projeto pai.
    • @return a quantidade de linhas na entidade projeto com o idProjetoPai fornecido.
    • @throws PersistenceException
      */
      public int contarProjetosPorProjetoPai( final Integer idProjetoPai ) throws PersistenceException
      {
      try
      {
      return ( (Integer) _sqlMap.queryForObject( _contar_ProjetosPorProjetoPai, idProjetoPai ) ).intValue();
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Retorna uma lista de TOs com os dados das linhas da entidade projeto com o idProjetoPai fornecido.
    • @param idProjetoPai a chave do projeto pai.
    • @return uma lista de TOs com os dados das linhas da entidade projeto com o idProjetoPai fornecido.
    • @throws PersistenceException
      */
      public List obterProjetosPorProjetoPai( final Integer idProjetoPai ) throws PersistenceException
      {
      try
      {
      return _sqlMap.queryForList( _obter_ProjetosPorProjetoPai, idProjetoPai );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Inclui uma linha na entidade projeto com os dados do TO fornecido.
    • @param projeto o TO com os dados a incluir, exceto o campo chave.
    • @return o TO com a chave da linha incluída.
    • @throws PersistenceException
      */
      public IProjetoTO incluirProjeto( final IProjetoTO projeto ) throws PersistenceException
      {
      try
      {
      final Integer key = (Integer) _sqlMap.insert( _incluir_Projeto, projeto );
      projeto.setIdProjeto( key );
      return projeto;
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Altera os dados da linha da entidade projeto correspondente à chave fornecida.
    • @param projeto o TO preenchido com os dados a alterar, inclusive sua chave.
    • @return a quantidade de linhas alteradas.
    • @throws PersistenceException
      */
      public int alterarProjeto( final IProjetoTO projeto ) throws PersistenceException
      {
      try
      {
      return _sqlMap.update( _alterar_Projeto, projeto );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    /**

    • Exclui a linha da entidade projeto correspondente à chave fornecida.
    • @param idProjeto a chave da linha a excluir.
    • @return a quantidade de linhas excluídas.
    • @throws PersistenceException
      */
      public int excluirProjeto( final Integer idProjeto ) throws PersistenceException
      {
      try
      {
      return _sqlMap.delete( _excluir_Projeto, idProjeto );
      }
      catch( final SQLException e )
      {
      throw new PersistenceException( e );
      }
      }

    // constantes privadas //
    private final String _obter_Projeto;
    private final String _obter_ProjetoPorIdAlternativo;
    private final String _obter_ProjetoPorNome;

    private final String _contar_ProjetosRaiz;
    private final String _obter_ProjetosRaiz;

    private final String _contar_ProjetosPorProjetoPai;
    private final String _obter_ProjetosPorProjetoPai;

    private final String _incluir_Projeto;
    private final String _alterar_Projeto;
    private final String _excluir_Projeto;
    }
    [/code]

eu vi que no seu insert você chama a sequence antes de fazer o insert, so que no meu caso a sequence vai ser disparada por uma trigger no banco de dados eu tenho que fazer com que o valor gerado pela “trigger” retorne para mim.

Um exemplo com JDBC puro seria assim:

String sql = “insert into A(NAME) values(‘something’)”;
CallableStatement ps = this.conn.prepareCall(“begin “+sql+” returning ID into ?; end;”);
ps.registerOutParameter(1, Types.VARCHAR);
ps.executeUpdate();
System.out.println(“ID=”+ps.getString(1));

existe alguma forma de fazer isto com o iBatis ?

[quote=luciano_guedes_antunes]eu vi que no seu insert você chama a sequence antes de fazer o insert, so que no meu caso a sequence vai ser disparada por uma trigger no banco de dados eu tenho que fazer com que o valor gerado pela “trigger” retorne para mim.

Um exemplo com JDBC puro seria assim:

String sql = “insert into A(NAME) values(‘something’)”;
CallableStatement ps = this.conn.prepareCall(“begin “+sql+” returning ID into ?; end;”);
ps.registerOutParameter(1, Types.VARCHAR);
ps.executeUpdate();
System.out.println(“ID=”+ps.getString(1));

existe alguma forma de fazer isto com o iBatis ?
[/quote]

se vc estiver usando oracle cuidado com as trigger mutantes!!!

porquê que vc precisa fazer isso??? trigger gerando sequence??? explica um pouco isso pra vermos se dá pra fazer alguma outra coisa …

como eu falei no inicio o banco de dados contem toda a regra de negocio dos nossos sistemas portanto nos temos triggers que fazem com que as sequences sejam atribuidas, por exemplo eu nao hora de um insert eu nao passo a chave primaria passo somente os campos requeridos pela tabela a trigger que esta por traz dessa tabela que faz o trabalho de atribuir a chave primaria para o registro que estou fazendo insert portanto para mim seria fundamental fazer com que na hora do insert o valor que fosse gerado pela trigger fosse devolvido para mim a nivel de front-end (tela), quanto as triggers mutantes nao e motivo de preocupacao todas as nossas triggers estao em perfeito funcionamento sem mutantes
nao ha motivo para preocupacao.

uma soluação possível para o que vc está querendo fazer:

  1. vc vai fazer seu insert normalmente.
  2. o banco, em meio ao insert, vai executar sua trigger e atualizar/calcular os campos necessários.
  3. normalmente o ibatis, para operação de insert, retorna a chave primária criada só que como isso foi feito pela trigger não sei se esse retorno vai realmente conter o valor da trigger - melhor testar.
  4. em último caso, se o retorno não corresponder ao id da trigger, vc pode, no dao, buscar a linha incluída.

Acho melhor testar pra não quebrar a cara.

Te adianto que pra campos obrigatórios vc fai ter que ainda específica-los nos sqls pois no momento de sua execução o banco não sabe o quê a trigger faz e, como de costume, irá reclamar da ausência de valores pra esses campos.

Esse é o comportamento do Oracle, não sei qual banco vc está usando.

como faco para buscar a linha incluida no dao basta fazer um select ? pelo que ? se a chave e gerada pelo banco de dados.

select mesmo.

vc tem todos os outros dados no transfer object, se isso não for suficiente ou vc não tiver uma chave alternativa (normalmente o nome) vc então tem um problema. Perceba que isso não tem nada a ver com iBatis, mas sim com a sua forma de trabalho.

uma outra situação que temos aqui é a seguinte:

ItemPedido -> Tabela

NumPedido NumItemPedido
1 1
2 1
2 2

a chave primaria desta tabela é NumPedido + NumItemPedido sendo que o NumItemPedido é uma trigger que gera (sem mutante) no after como fazer neste caso ? faco um select tambem para recuperar o valor ?

cara, seu item de pedido não tem nenhum outro campo que possa ser utilizado pra identificá-lo?

Sua trigger gera apenas o número do item de pedido certo? então vc poderia, no dao, buscar todos itens desse pedido e deduzir qual das linhas retornadas é o seu item …
Isso é medonho!!!

Não consigo parar de pensar na possibilidade de jogar fora essas triggers e chamar o chamar o nextval nos inserts direto. Acho que seria muito mais fácil pra vc.

Qual a necessidade de se manter essas trigger? Qual o esforço pra remover essas trigger e fazer que sua vida social não corra sérios riscos de ser extirpada??? :sunglasses:

nao é so os pedidos o banco inteiro tem estes tipos de construcao ou seja as situacoes sao muitas, estou procurando a melhor solucao estou seriamente disposto a abandonar qualquer framework de persistencia e usar o JDBC puro mesmo por exemplo utilizando o JdbcTemplate do spring o que voce acha ?

eu faria isso.

E não acredite em quem fale que JDBC puro é só pra sistemas simples e não comerciais. Aqui na empresa usamos assim, e pode acreditar, as aplicações aqui não são nem um pouco simples, muito pelo contrário.

Frameworks ORM são excelentes. Mas pra este seu caso, você pode começar a ter q contornar(fazer gambiarra) as limitações do framework para esse seu caso, e isso pode virar um inferno.

[]'s

concordo vou partir para o JDBC puro com o JdbcTemplate do spring.

E quanto a camada de visualização o Struts2 e a melhor opção para o meu caso ou tenho dar uma olhada em outras opções ?

se suas regras estão todas no banco, acho que utilizar um framework ORM so vai acrescenar complexidade aoseu projeto.
sugiro usar JDBC com o DaoSupport do Spring. se quiser utilise o controlde de transações do Spring que funciona muito bem tmb, deixando vc livre para se preocupar com sua logica de negocio.

quanto a camada de visão, utilizei bastante o WebWork(atual Struts2), por isso acho uma boa escolha.

[]'s

como faco o controle de transacoes no spring para o meu caso que vai ser somente jdbc ?

Isso não é competição. É minha opinião.
Antes de mandar uma frase dessa pense bem.

Cara, pode-se fazer um prédio com palitos e outro com tijolos não é mesmo???
Mesmo no prédio com tijolos depende-se muito da mão de obra …
Não acredito em desenvolvedor estrela, acredito em equipe. Para projetos grandes vc tem de pensar no melhor pra equpe (ou fábrica).

jdbc puro, isso é fato, aumenta a quantidade de código consideravelmente …
quanto maior a quantidade de código maior o esforço na manutenção.