Você não gosta do Hibernate? Eu tb não! Leia para entender o porquê

Banco-de-dados é algo bastante simples. Qualquer programador deveria se sentir confortável em trabalhar com SQL, índices, transações, cache, lazy loading, etc. Mas infelizmente não é isso que acontece. O tal do Hibernate virou PADRÃO de mercado. Segundo esse heavyweight framework, banco-de-dados é algo muito complicado e precisa ser abstraído. Então o que ele propõe? Sai SQL e entra HQL ou Criteria. Transações, cache, lazy loading, pode esquecer. Isso vai acontecer via mágica. E se algo não sair como esperado? Aí se vira amigo! Como vc pode ser tão burro de não configurar aquelas anotações direito? É o que eu chamo de trocar uma complexidade por outra maior/pior, com pouquíssimas vantagens.

Abaixo irei argumentar contra as vantagens oferecidas pelo Hibernate e apresentar uma alternativa muito mais simples e lightweight, para aqueles programadores que já ouviram falar em coisas "muito complexas" como um JOIN e um DAO.

Uma grande falácia! A não ser para aqueles CRUDs simples, com o Hibernate você tem que escrever isso em HQL ou Criteria. Se você nunca viu SQL talvez vc goste dessas alternativas específicas do Hibernate. Agora se você entende bem SQL é como chegar para uma pessoa que fala português e dizer: "Esquece português, agora você vai falar espanhol. São parecidos, não se preocupe. Pode começar. E nem pense em tentar falar em português comigo!".

Vamos deixar claro uma coisa: Ninguém vai defender o uso de JDBC puro no século XXI. Claro que seria um tédio e muito código desnecessário para manter. Bem-vindo ao mundo dos query helpers e SQL builders.

Faltou completar: Hibernate vai fazer o mapeamento dos seus objetos para as tabelas do banco-de-dados junto com TODOS os seus relacionamentos, das maneiras mais complexas que você for inexperiente o bastante para imaginar. É muito fácil usar o Hibernate. Basta colocar umas anotações nos seus objetos e sair usando. Quanta inocência! Se as pessoas usassem esse mapeamento da maneira mais simples possível talvez isso fosse verdade. Mas o que acontece na prática é uma tentativa de configurar tudo, todos os relacionamentos, todas as relações entre os objetos em ambas as direções, chaves estrangeiras, estratégia de chave primária, etc. via XML ou Annotation. O resultado prático é uma zona de XML ou anotações onde a coisa funciona sem que vc saiba muito bem como. Alguém aí já ouviu falar de configuração programática?

Claro, claro. É sempre importante para qualquer projeto poder trocar o banco-de-dados a qualquer momento. Em vários projetos que eu trabalhei, pelo menos uma vez por mês o gerente chegava e falava assim: "Pô, esse MySQL é legal e tal, mas vamos experimentar SQLServer um pouco para ver como ele se sai. Tenho certeza que nenhum relatório, nenhum cronjob, nenhum backend, nenhum esquema de replicação vai notar a diferença. Troca aí no Hibernate, vai." Realmente uma piada engraçada. Aí o cara lá no fundo grita desesperado. "Pelo amor de Deus!, você quer poder trocar o banco-de-dados para poder rodar os testes unitários em memória, com outro banco-de-dados." Então agora realmente temos que usar o Hibernate! Não vale a pena considerar o fato de que o ideal seria rodar os testes contra um database de testes do mesmo tipo que o database de produção. Também não vale a pena considerar o fato de que alguns databases em memória como o H2 possuem mode de compatibilidade com outros bancos. Temos que rodar os testinhos unitários num banco-de-dados em memória logo não podemos deixar de usar o Hibernate e escrever todas as nossas queries de acesso ao banco em HQL ou Criteria e confiar no seu dialect. É triste, mas esses argumentos são recorrentes.

[size=30][color=blue]O que usar então?[/color][/size]

Bom, se você não entendeu nada do que foi escrito aí em cima, se você não sabe o que é um JOIN, nunca codificou um DAO, não gosta de SQL mas gosta de HQL (!!??), prefere fazer queries usando objetos (ah! Criteria é fácinho, se vira né!) (!!??), gosta de configurar as coisas com XML e Annotations até que elas funcionam sem você saber muito como, adora a flexibilidade e clareza do pom.xml do Maven, quer saber a ferramenta padrão do mercado para aumentar a sua empregabilidade, ou porque o seu chefe te obrigou (já aconteceu comigo!) então você vai usar o Hibernate e ser feliz.

Ou então você pode usar iBatis ou o MentaBean, que irei apresentar abaixo. (Obs: Os exemplos abaixo foram extraídos dos testes automatizados (não confundir isso com teste unitário) do MentaBean, que você pode visualizar aqui)

[color=blue]Nosso bean:[/color] (Repare um efeito colateral legal da configuração programática: O seu bean fica limpinho, totalmente desacoplado de qualquer código relacionado a persistência)

	public class User {

		public static enum Status {
			BASIC, PREMIUM, GOLD
		}

		private int id;
		private String username;
		private Date birthdate;
		private Status status = Status.BASIC;
		private boolean deleted;
		private Date insertTime;

		public User() {
		}

		public User(int id) {
			this.id = id;
		}

		public User(String username, String birthdate) {
			this.username = username;
			this.birthdate = fromString(birthdate);
		}

		// um monte de getters and setters
	}

[color=blue]Mapeamento Programático:[/color] (Pergunte ao Google Guice ou ao Martin Fowler porque configuração programática é legal)

	private void createTables(Connection conn) throws SQLException {

		execUpdate(conn, "create table Users(id integer primary key auto_increment, username varchar(25), bd datetime, status varchar(20), deleted tinyint, insert_time timestamp)");
	}

	private BeanConfig getUserBeanConfig() {

		// programmatic configuration for the bean... (no annotation or XML)

		BeanConfig config = new BeanConfig(User.class, "Users");
		config.pk("id", DBTypes.AUTOINCREMENT);
		config.field("username", DBTypes.STRING);
		config.field("birthdate", "bd", DBTypes.DATE); // note that the database column name is different
		config.field("status", new EnumValueType(User.Status.class));
		config.field("deleted", DBTypes.BOOLEANINT);
		config.field("insertTime", "insert_time", DBTypes.TIMESTAMP).defaultToNow("insertTime");

		return config;
	}

[color=blue]CRUD:[/color] (Para o básico vc não precisa escrever nenhum SQL)

			BeanManager beanManager = new BeanManager();
			BeanConfig userConfig = getUserBeanConfig();
			beanManager.addBeanConfig(userConfig);

			conn = getConnection();
			BeanSession session = new H2BeanSession(beanManager, conn); // ou MySQLBeanSession, OracleBeanSession (via IoC, claro)

			createTables(conn);

			// INSERT:

			User u = new User("saoj", "1980-03-01");
			u.setStatus(User.Status.GOLD);

			session.insert(u);

			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("saoj", u.getUsername());
			Assert.assertEquals("1980-03-01", BD_FORMATTER.format(u.getBirthdate()));
			Assert.assertEquals(false, u.isDeleted());
			Assert.assertEquals(User.Status.GOLD, u.getStatus());

			// SELECT:

			u = new User(1);

			boolean loaded = session.load(u);

			Assert.assertEquals(true, loaded);

			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("saoj", u.getUsername());
			Assert.assertEquals("1980-03-01", BD_FORMATTER.format(u.getBirthdate()));
			Assert.assertEquals(false, u.isDeleted());
			Assert.assertEquals(User.Status.GOLD, u.getStatus());
			Assert.assertTrue((new Date()).getTime() >= u.getInsertTime().getTime());

			// UPDATE:

			u.setUsername("soliveira");

			int modified = session.update(u);

			Assert.assertEquals(1, modified);

			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("soliveira", u.getUsername());
			Assert.assertEquals("1980-03-01", BD_FORMATTER.format(u.getBirthdate()));
			Assert.assertEquals(false, u.isDeleted());
			Assert.assertEquals(User.Status.GOLD, u.getStatus());
			Assert.assertTrue((new Date()).getTime() >= u.getInsertTime().getTime());

			// make sure the new username was saved in the database

			u = new User(1);

			loaded = session.load(u);

			Assert.assertEquals(true, loaded);

			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("soliveira", u.getUsername());
			Assert.assertEquals("1980-03-01", BD_FORMATTER.format(u.getBirthdate()));
			Assert.assertEquals(false, u.isDeleted());
			Assert.assertEquals(User.Status.GOLD, u.getStatus());
			Assert.assertTrue((new Date()).getTime() >= u.getInsertTime().getTime());

			// DELETE:

			boolean deleted = session.delete(u);

			Assert.assertEquals(true, deleted);

			// make sure the bean is deleted from the database...

			u = new User(1);

			loaded = session.load(u);

			Assert.assertEquals(false, loaded);

[color=blue]Outro bean:[/color] (com um relacionamento OneToOne com o User)

	public class Post {

		private int id;
		private int userId;
		private User user; // contém User (one-to-one relationship)
		private String title;
		private String body;
		private Date insertTime;

		public Post() {
		}

		public Post(int id) {
			this.id = id;
		}

		public Post(int userId, String title, String text) {
			this.userId = userId;
			this.title = title;
			this.body = text;
		}
		
		// setters and getters here...
	}

[color=blue]Mapeamento Programático:[/color]

	private void createTables(Connection conn) throws SQLException {

		execUpdate(conn, "create table Posts(id integer primary key auto_increment, user_id integer, title varchar(200), body text, insert_time timestamp)");
	}

	private BeanConfig getPostBeanConfig() {

		// programmatic configuration for the bean... (no annotation or XML)

		BeanConfig config = new BeanConfig(Post.class, "Posts");
		config.pk("id", DBTypes.AUTOINCREMENT);
		config.field("userId", "user_id", DBTypes.INTEGER);
		config.field("title", DBTypes.STRING);
		config.field("body", DBTypes.STRING);
		config.field("insertTime", "insert_time", DBTypes.TIMESTAMP).defaultToNow("insertTime");

		return config;
	}

[color=blue]SQL:[/color] (Não precisa fazer bind em PreparedStatement ou get de ResultSet nenhum!)

			BeanManager beanManager = new BeanManager();
			BeanConfig userConfig = getUserBeanConfig();
			BeanConfig postConfig = getPostBeanConfig();
			beanManager.addBeanConfig(userConfig);
			beanManager.addBeanConfig(postConfig);

			conn = getConnection();
			JdbcBeanSession session = new H2BeanSession(beanManager, conn);

			createTables(conn);

			User u = new User("saoj", "1980-01-02");
			session.insert(u);

			Assert.assertEquals(1, u.getId());

			// Now insert a post for this user...
			Post p = new Post(1, "Test", "This is a test!");
			session.insert(p);

			Assert.assertEquals(1, p.getId());

			// Load from the database...
			p = new Post(1);
			boolean loaded = session.load(p);
			Assert.assertEquals("Test", p.getTitle());
			Assert.assertEquals(1, p.getUserId());
			Assert.assertNull(p.getUser()); // you did NOT load any user from the database here... (we like manual lazy loading, not automatic lazy loading!)

			// Load user for this post... (let's do our manual lazy loading)
			u = new User(p.getUserId());
			loaded = session.load(u);
			Assert.assertEquals(true, loaded);
			p.setUser(u); // manual lazy loading (forget about automatic lazy loading, you want control!)

			// Use JOIN to load all dependencies with a single query... (you know how to make a join, right?)

			p = new Post(1);

			StringBuilder query = new StringBuilder(256);
			query.append("select ");
			query.append(session.buildSelect(Post.class, "p"));
			query.append(", ");
			query.append(session.buildSelect(User.class, "u"));
			query.append(" from Posts p join Users u on p.user_id = u.id");
			query.append(" where p.id = ?");

			stmt = conn.prepareStatement(query.toString());
			stmt.setInt(1, p.getId());

			rset = stmt.executeQuery();

			if (rset.next()) {

				session.populateBean(rset, p, "p");

				u = new User();

				session.populateBean(rset, u, "u");

				p.setUser(u); // manual lazy loading (we prefer to have control!)
			}

			Assert.assertEquals(1, p.getId());
			Assert.assertEquals("Test", p.getTitle());
			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("saoj", p.getUser().getUsername());
			Assert.assertTrue((new Date()).getTime() >= p.getInsertTime().getTime());

			rset.close();
			stmt.close();

			// Deleting => No cascade deletes, if you want that implement in the database level...

			u = new User(1);
			boolean deleted = session.delete(u);
			Assert.assertEquals(true, deleted);

			// Post of course is still there...
			p = new Post(1);
			loaded = session.load(p);
			Assert.assertEquals(true, loaded);
			Assert.assertEquals(1, p.getUserId()); // of course this user is gone!

			u = new User(1);
			loaded = session.load(u);
			Assert.assertEquals(false, loaded); // use was deleted above...

[color=blue]Outros:[/color]

      - loadList - Carregamento de listas baseadas em propiedades de um bean
      - loadUnique - Fazer query com checagem automático se ela retorna um  bean apenas
      - buildSelectMinus - Quando vc quer carregar apenas algumas propriedades de um bean (e não as 1000)
      - Vários tipos de dados para serem configurados
      - Vários tipos de bancos suportados
      - Update dinâmico (só faz update dos campos que foram alterados no bean)
      - Interface MentaBean para que o seu bean implemente persistencia in-place via user.load(), user.insert(), user.update(), user.delete().

[color=blue]Desvantagens:[/color] (sendo imparcial)

      - Não suporta lazy loading automático como o Hibernate faz via cglib. Lazy Loading é sempre o padrão quando vc carrega um bean. Ex: se vc carrega um Post ele virá apenas com o ID do User autor. Se você precisar do User inteiro, você faz o lazy loading na mão (via um DAO, claro) e preenche a referencia no Post. Esse user pode vir de um cache por exemplo. O que eu geralmente faço é um JOIN que me retorna o ID e o USERNAME do user e eu guardo esses valores no Post.  Assim posso listar posts com o username e um link para o gara visualizar o User inteiro caso ele queira, e só aí o Lazy Loading MANUAL acontece. Para um discussão extensa sobre Lazy Loading Manual x Automático veja aqui: http://www.guj.com.br/java/57590-ser-lazy-preguicoso-ou-nao-ser

[color=blue]DISCLAIMER:[/color]

      - Isso é apenas minha opinião pessoal e o meu ponto de vista, condicionados pela minhas experiência, preferência e estilo. Caso você ame o Hibernate e ache que é a melhor coisa do mundo, você não deixará de ir para o céu por causa disso. Também não vejo problema em sermos amigos.

[color=blue]URL do Projeto:[/color]

       http://mentabean.soliveirajr.com

[color=red][size=18]"Em tudo na vida a perfeição é finalmente atingida, não quando nada mais existe para acrescentar, mas quando não há mais nada para retirar."[/size][/color] - Antoine de Saint-Exupéry (Complexity Kills so Kiss!)

Achei interessante suas suposições, agora vou dar algumas opiniões a favor do nosso amigo hibernate!!

Bom eu ja escrevi milhões de queries sql em tudo que é tipo de banco , me considerava pró em queries apesar de não ser DBA , sei a fundo como são executadas o que utiliza indice ou não , como ele executa e melhores soluções , não achei a migração pra uma api de query no caso criteria tão complexa assim ,até pq não sou fã do hql que é bem menos "orientado a objetos", tão diferente assim de falar "ESPANHOL PRA PORTUGUES" e isso aqui "E nem pense em tentar falar em português comigo!" só utilizar native queries…voce vai falar o portugues com o seu banco. Até pq o hql deixa de ser uma simples "query" e vira uma "query orientada a objeto" o que é totalmente diferente ela não navega apenas em suas tabelas mas tb nos seus relacionamento de classes…

Acho que esse ponto nem é discutivel a quantidade de código que se produz a mais indo pra um JDBC da vida.

Pensa se que ninguem se propõe a usar algo que não conhece sem ao menos ter o mínimo de bom senso e dar uma olhada na documentação , de como funciona o processo todo da coisa. Eu particularmente não gosto de usar xml pra configurar prefiro bem mais anotação e não vejo nenhuma zona nisso ate pq suas anotação não atravessam sua camada de modelo. Quanto a configuração programática , eu acho muito mais complexo , alias nunca gostei , ficar dando set pra cá set prá lá e dalhe java doc pra saber o que cada coisa faz no fim o esforço foi igual pra ambas as coisas. Tanto annotation quanto programaticamente.

Esse argumento de trocar banco de dados pra mim tb não cola , nunca colou , não existe empresa que se arrisque a esse nível. Assim como é o mesmo argumento de estar usando o hibernate e falar … "Pô esse hibernate ta legal mas vou mudar pra ibatis pra ver se melhora", quando se define uma tecnologia ou framework a ser utilizada dificilmente se troca , a não ser que o projeto seja refeito em sua maior parte e seja provado que a nova tecnologia vai resolver os problemas de vez.

Agora vamos aos trechos de código

Hibernate

        @Entity
	public class User {

                @Enumerated
		public static enum Status {
			BASIC, PREMIUM, GOLD
		}

                @Id
                @GeneratedValue
		private int id;
		private String username;
		private Date birthdate;
		private Status status = Status.BASIC;
		private boolean deleted;
		private Date insertTime;
                .
                .
		
	}

Legal acoplei meu código a javax.persistence , ou seja tenho que carregar essa jar pra tudo que é canto . Bem vindo ao mundo das anotações.

BeanConfig config = new BeanConfig(User.class, "Users");
		config.pk("id", DBTypes.AUTOINCREMENT);
		config.field("username", DBTypes.STRING);
		config.field("birthdate", "bd", DBTypes.DATE); // note that the database column name is different
		config.field("status", new EnumValueType(User.Status.class));
		config.field("deleted", DBTypes.BOOLEANINT);
		config.field("insertTime", "insert_time", DBTypes.TIMESTAMP).defaultToNow("insertTime");

Pô mais acabei de falar qual meu tipo de dado …tenho que falar de novo ??? Multiplique esse trabalho x 50 entidades e seus relacionamento …alem do que tem o problema de não ser o lado esquerdo typesafe … coisa que o hibernate ao fazer query peca tb por enquanto…ate pq ja tem solução pra isso…MetaModel generator…apesar deu achar que isso deveria ser nativo da api.

			BeanManager beanManager = new BeanManager();
			BeanConfig userConfig = getUserBeanConfig();
			BeanConfig postConfig = getPostBeanConfig();
			beanManager.addBeanConfig(userConfig);
			beanManager.addBeanConfig(postConfig);

			conn = getConnection();
			JdbcBeanSession session = new H2BeanSession(beanManager, conn);

			createTables(conn);

			User u = new User("saoj", "1980-01-02");
			session.insert(u);

			Assert.assertEquals(1, u.getId());

			// Now insert a post for this user...
			Post p = new Post(1, "Test", "This is a test!");
			session.insert(p);

			Assert.assertEquals(1, p.getId());

			// Load from the database...
			p = new Post(1);
			boolean loaded = session.load(p);
			Assert.assertEquals("Test", p.getTitle());
			Assert.assertEquals(1, p.getUserId());
			Assert.assertNull(p.getUser()); // you did NOT load any user from the database here... (we like manual lazy loading, not automatic lazy loading!)

			// Load user for this post... (let's do our manual lazy loading)
			u = new User(p.getUserId());
			loaded = session.load(u);
			Assert.assertEquals(true, loaded);
			p.setUser(u); // manual lazy loading (forget about automatic lazy loading, you want control!)

			// Use JOIN to load all dependencies with a single query... (you know how to make a join, right?)

			p = new Post(1);

			StringBuilder query = new StringBuilder(256);
			query.append("select ");
			query.append(session.buildSelect(Post.class, "p"));
			query.append(", ");
			query.append(session.buildSelect(User.class, "u"));
			query.append(" from Posts p join Users u on p.user_id = u.id");
			query.append(" where p.id = ?");

			stmt = conn.prepareStatement(query.toString());
			stmt.setInt(1, p.getId());

			rset = stmt.executeQuery();

			if (rset.next()) {

				session.populateBean(rset, p, "p");

				u = new User();

				session.populateBean(rset, u, "u");

				p.setUser(u); // manual lazy loading (we prefer to have control!)
			}

			Assert.assertEquals(1, p.getId());
			Assert.assertEquals("Test", p.getTitle());
			Assert.assertEquals(1, u.getId());
			Assert.assertEquals("saoj", p.getUser().getUsername());
			Assert.assertTrue((new Date()).getTime() >= p.getInsertTime().getTime());

			rset.close();
			stmt.close();

			// Deleting => No cascade deletes, if you want that implement in the database level...

			u = new User(1);
			boolean deleted = session.delete(u);
			Assert.assertEquals(true, deleted);

			// Post of course is still there...
			p = new Post(1);
			loaded = session.load(p);
			Assert.assertEquals(true, loaded);
			Assert.assertEquals(1, p.getUserId()); // of course this user is gone!

			u = new User(1);
			loaded = session.load(u);
			Assert.assertEquals(false, loaded); // use was deleted above...

Quanto ao resto recaimos quase na mesma quantidade de código e nos mesmos nomes … tirando que isso …

StringBuilder query = new StringBuilder(256);
			query.append("select ");
			query.append(session.buildSelect(Post.class, "p"));
			query.append(", ");
			query.append(session.buildSelect(User.class, "u"));
			query.append(" from Posts p join Users u on p.user_id = u.id");
			query.append(" where p.id = ?");

			stmt = conn.prepareStatement(query.toString());
			stmt.setInt(1, p.getId());

			rset = stmt.executeQuery();

			if (rset.next()) {

				session.populateBean(rset, p, "p");

				u = new User();

				session.populateBean(rset, u, "u");

				p.setUser(u); // manual lazy loading (we prefer to have control!)
			}

é muito maior e complexo que isso ;

Criteria criteria = session.createCriteria(Post.class);
criteria.createCriteria("user",Criteria.INNER_JOIN);
criteria.add(Restrictions.eq("id",id));
List<Post> posts = criteria.list();
for(Post post:posts){
       System.out.println(post);
}

Ps : Não revisei o código , to fazendo de cabeça aqui.

Esse é meu ponto de vista dos dois mundos apresentados , isso pq num foi falado de um monte de conceitos como auditoria,cache,validações,transações que o hibernate tem ferramentas prontas ja quase que embutidas com ele pra melhorar a produtividade.

Ha mais de 1 ano nem trabalho com banco relacional mais ,só com cloud agora, e chega uma hora que ate isso voce para de perder o foco em mapeamento etcetc e tem que voltar aos conceitos basicos de banco de dados onde não existe de novo lazy loading , etc…

Sinceramente… prefiro colocar Annotations do que fazer todas aquelas coisas programáticas. Sei SQL, JOIN e blá blá blá, mas ainda prefiro o Hibernate.
E quanto a ser raro trocar de banco de dados… é raro, mas não é impossível. Ainda prefiro portabilidade, também.

Olha, gosto é gosto e não se discute!

Mas teus argumentos são inválidos. Na verdade, o seu mapeamento programático, não tem nada haver com o que o Fowler falou! O que ele disse é que usar arquivos de configuração nem sempre faz sentido, e fazer a configuração via código pode ser a melhor opção.

O que você está fazendo ali é trocar uma ferramenta ORM por outra. Eu aindo prefiro o JPA e anotações. A meu ver essa forma da mais trabalho além do que o MentaBean só se aplicar a casos simples:

[quote]

  1. Qual a diferença do MentaBean para o Hibernate?

R: O MentaBean, assim como o Hibernate e o iBatis, é um framework de ORM, ou seja, de mapeamento de objetos Java para tabelas de um banco-de-dados relacional. A diferença é que o MentaBean foca apenas nas questões simples de qualquer framework ORM, ou seja, CRUD (Create, Read, Update, Delete) de beans, load, add e remove de relacionamentos e carregamento de listas de beans com suporte a sorting e limit. O MentaBean não trata por exemplo de situações mais avançadas que o Hibernate trata como remoção em cascata, lazy-loading automático, locks, herança, etc. Na verdade o MentaBean está mais para um gerador automatizado de queries SQL (como o iBatis) do que para um framework completo de ORM (como o Hibernate). [/quote]Fonte: http://www.mentaframework.org/mentabean.jsp

Mesmo para aplicações simples eu usaria o Hibernate, pois um sisteminha tente a se tornar um “sistemão” e isso facilita a evolução natural do projeto.

Claro que hibernate não é bala de prata, existem alguns casos em que ele não é melhor opção, mas esses casos são raros e é facilmente contornável fazendo o mapemanto na mão.

A utilização do MentaBean não invalida o uso de DAOs também. O DAO serve para fazer a separação de responsabilidade. Na verdade não é porque você usa hibernate que necessita usar DAO, você pode usar o padrão Active Record do Martin Fowler (http://martinfowler.com/eaaCatalog/activeRecord.html).

Realmente o Hibernate não é um framework simples, é bem complexo e para dominá-lo é necessário um bom estudo. Mas dizer que “Segundo esse heavyweight framework, banco-de-dados é algo muito complicado e precisa ser abstraído” é uma falácia. Se for assim o qualquer Framework ORM, inclusive o MentaBean, se propõe a isso. O que qualquer framework ORM se propõe é retirar essa tarefa do programador! Pra quem já leu o livro do Martin Fowler, Padrões de Arquitetura de Aplicações Corporativas, sabe disso. A finalidade de um framework ORM é justamente fazer com que o programador não se preocupe com a mapeamento objeto relacional, que se preocupe com o dominio da aplicação. O que é complicado e necessita ser abstraído é o Mapeamento Objeto Relacional e não o banco de dados (quem já fez isso, sabe bem o quão complicado pode ser)!

Não é por que se usa um framework ORM que não se deve conhecer SQL, bem pelo contrário.

[quote=saoj]Banco-de-dados é algo bastante simples. Qualquer programador deveria se sentir confortável em trabalhar com SQL, índices, transações, cache, lazy loading, etc. Mas infelizmente não é isso que acontece. O tal do Hibernate virou PADRÃO de mercado. Segundo esse heavyweight framework, banco-de-dados é algo muito complicado e precisa ser abstraído. Então o que ele propõe? Sai SQL e entra HQL ou Criteria. Transações, cache, lazy loading, pode esquecer. Isso vai acontecer via mágica. E se algo não sair como esperado? Aí se vira amigo! Como vc pode ser tão burro de não configurar aquelas anotações direito? É o que eu chamo de trocar uma complexidade por outra maior/pior, com pouquíssimas vantagens.
[/quote]

Essa vai pro meu professor de banco de dados que já faz 2 bimestres que esta falando(enchendo lingüiça na verdade) sobre Hibernate, logo eu que estava tão entusiasmado com a possibilidade de escrever algo em PL/SQL …(desculpa ai o momento desabafo :slight_smile: ).

Em nome dos ditos ‘padrões de mercado’ é deixado de lado o estudo mais profundo do funcionamento de um banco de dados por essa gambiarra (bem feita …mas não deixa de ser uma gambiarra).

Enfim … excelente texto.

[quote=x@ndy]Olha, gosto é gosto e não se discute!

Mas teus argumentos são inválidos. Na verdade, o seu mapeamento programático, não tem nada haver com o que o Fowler falou! O que ele disse é que usar arquivos de configuração nem sempre faz sentido, e fazer a configuração via código pode ser a melhor opção.

O que você está fazendo ali é trocar uma ferramenta ORM por outra. Eu aindo prefiro o JPA e anotações. A meu ver essa forma da mais trabalho além do que o MentaBean só se aplicar a casos simples:

Concordo completamente!

E, também, se fosse ruim, não seria especificação JPA ;]

Gosto de usar JDBC puro, acredito por eu ser um DBA.

Não ach complicado usar JDBC puro junto com um DAO.

Prefiro minha aplicação rodando sem algo “desnecessário” que pese no desempenho final da aplicação.

Hoje em dia o pessoal prefere menos trabalho, mesmo que isto signifique uma certa qualidade menor no final.

Pessoal prefere usar anotações simples. por que você não precisa perder mais tempo fazendo um DAO completo via JDBC e não pensa e fica cego para as desavantagens…

São dois caminhos diferentes:

:arrow: ou vc decide aprender e entender o Hibernate, com todas as sua complexidades e mágica e fazer todas as suas queries com HQL e Criteria (não faz sentido usar SQL com Hibernate).

:arrow: ou vc conclui que banco-de-dados não é um bicho de sete cabeças e vai de SQL + JDBC + MentaBean (ou iBatis).

A vantagem da última opção é que você vai estar no controle e vai saber exatamente o que acontece e quando. E mais linhas de código não é necessariamente pior. E essas linhas estarão abstraídas dentro dos seus DAOs, assim como o código do Hibernate estaria.

Se o cara não sabe SQL, não sabe banco de dados, nunca escreveu um DAO, Hibernate será uma grande pedida. O meu ponto é que para o cara que sabe essas coisas e se sente confortável em falar diretamente com o banco-de-dados, precisa fazer queries complexas, etc. usar Hibernate é um grande contra-senso. É trazer para o seu projeto uma complexidade desnecessária através de um framework heavyweight. A linguagem que todos os banco-de-dados entendem é SQL, então seria legal utilizar essa linguagem.

E mais uma coisa: veja como a abstração feita pelo Hibernate cai na questão de “trocar uma complexidade por outra maior/pior”. Para constatar isso veja quantas perguntas e problemas relacionados ao Hibernate há aqui no GUJ. De simples, e rápido não tem absolutamente nada. O meu ponto é que as pessoas não deveriam ser obrigados a usá-lo, principalmente se entendem de banco-de-dados. Abstração só é bem-vinda quando ela consegue abstrair reduzindo drasticamente a complexidade sem comprometer a flexibilidade. Se não o Maker seria e a melhor coisa do mundo.

Gosto dos tópicos do saoj, porque mesmo não concordando algumas vezes com o que ele diz, ele induz a um debate saudável sobre coisas interessantes.

Muito legal o tópico saoj, parabéns.

Eu, como não sou nenhum expert em BD achei excelentes os dois pontos de vista!
Estou dando uma estudada nos dois lados da moeda!
Essa discussão é muito mais produtiva que essas piadas que ficam postando no fórum!
Valeu! :slight_smile:

Tópico interessante.

Entre escolher os primos pobres(Ibatis ou MentaBean), ou o primo rico(Hibernate), com toda certeza
iria de Hibernate, pois tem mais funcionalidades (remoção em cascata, lazy-loading automático, etc).
Mas isso é opinião pessoal, pois prefiro errar pelo excesso do que pela falta e ter que reinventar a roda.

Trabalho com JDBC puro e pelo o que percebi para quem ja tem um fonte legado com JDBC puro o MentaBean parece ser o mais fácil para se migrar entre o hibernate, iBatis e o próprio MentaBean.

Vi que possui download separado do MentaFramework aqui, mas este jar esta 100% com o estado do projeto? (já que ali marca que é um beta)

[quote=Jose111]Trabalho com JDBC puro e pelo o que percebi para quem ja tem um fonte legado com JDBC puro o MentaBean parece ser o mais fácil para se migrar entre o hibernate, iBatis e o próprio MentaBean.

Vi que possui download separado do MentaFramework aqui, mas este jar esta 100% com o estado do projeto? (já que ali marca que é um beta)[/quote]

O projeto agora é independente do Mentawai e pode ser baixado aqui: http://mentabean.soliveirajr.com/

Pra mim Criteria é o que há!

Tenho queries tão dinâmicas que possuem cerca de 20 ifs e dependendo do if que entra, ele ja faz o join com a tabela X, senão faz com a tabela Y e por ai vai, fazer isso com StringBuilder é um saco! isso é fato.

Mapeamento tanto com xml, annotation ou programático, é um ônus de inicio de projeto, eu mesmo só mexo em annotation hoje para adicionar mais um campo etc, e é coisa simples de se fazer.

Antes não usava JPA por não possuir Criteria, tinha que fazer gambiarras, mas com o JPA2 apesar das Criterias serem mais complicadas ao meu ver, ainda sim vejo vantagem.

Subqueries com Critéria é mão na roda.

Enfim, cada um tem um costume, cultura etc…

Você sempre dá a entender que quem usar Hibernate, é porque não sabe SQL puro, mexer com banco de dados, etc.

Já desenvolvi um projeto inteiro com JDBC puro (o que deu muito trabalho, gastei bastante tempo, etc.), depois tive que mudar de PostgreSQL para MySQL (deu mais trabalho ainda mudar todas as SQLs). Com Hibernate, qualquer mudança no mapeamento é muito mais simples.

Realmente tem perda de desempenho, se comparar com trabalhar diretamente com JDBC. Mas o cache do Hibernate já ajuda no desempenho…

Enfim, ainda não me convenceu a parar de usar Hibernate. E enquanto Hibernate é construído em cima de uma especificação, esses 2 ai não.

aqui usamos ibatis

[quote=Markus Alemao][quote=saoj]Banco-de-dados é algo bastante simples. Qualquer programador deveria se sentir confortável em trabalhar com SQL, índices, transações, cache, lazy loading, etc. Mas infelizmente não é isso que acontece. O tal do Hibernate virou PADRÃO de mercado. Segundo esse heavyweight framework, banco-de-dados é algo muito complicado e precisa ser abstraído. Então o que ele propõe? Sai SQL e entra HQL ou Criteria. Transações, cache, lazy loading, pode esquecer. Isso vai acontecer via mágica. E se algo não sair como esperado? Aí se vira amigo! Como vc pode ser tão burro de não configurar aquelas anotações direito? É o que eu chamo de trocar uma complexidade por outra maior/pior, com pouquíssimas vantagens.
[/quote]

Essa vai pro meu professor de banco de dados que já faz 2 bimestres que esta falando(enchendo lingüiça na verdade) sobre Hibernate, logo eu que estava tão entusiasmado com a possibilidade de escrever algo em PL/SQL …(desculpa ai o momento desabafo :slight_smile: ).

Em nome dos ditos ‘padrões de mercado’ é deixado de lado o estudo mais profundo do funcionamento de um banco de dados por essa gambiarra (bem feita …mas não deixa de ser uma gambiarra).

Enfim … excelente texto.
[/quote]
Chamar o JPA/Hibernate de gambiarra é não conhecer a importância do Mapeamento Objeto Relacional. Na verdade é não conhecer OOP. Pois se você programa orientado o objeto e não usar uma ferramenta ORM se torna praticamente impossível, pois você acaba se desviando do domínio da aplicação para desenvolver o mapeamento.
Outra coisa, usar um framework ORM, não inválida a utilização de PL/SQL. O banco de dados continua existindo e pode ser necessário criar triggers e stored procedures. Algumas tarefas devem ser feitas no banco de dados e não no sistema, pois esse é muitas vezes mais eficientes. Fora a criação das próprias tabelas, índices ,etc.

Eu uso DAOs para abstrair a camada de persistência. O mapeamento (seja via Ibatis, Hibernate ou MentaBean) só me ajuda a escrever os DAOs.

[quote=saoj][quote=x@andy]
Realmente o Hibernate não é um framework simples, é bem complexo e para dominá-lo é necessário um bom estudo. Mas dizer que “Segundo esse heavyweight framework, banco-de-dados é algo muito complicado e precisa ser abstraído” é uma falácia. Se for assim o qualquer Framework ORM, inclusive o MentaBean, se propõe a isso. O que qualquer framework ORM se propõe é retirar essa tarefa do programador! Pra quem já leu o livro do Martin Fowler, Padrões de Arquitetura de Aplicações Corporativas, sabe disso. A finalidade de um framework ORM é justamente fazer com que o programador não se preocupe com a mapeamento objeto relacional, que se preocupe com o dominio da aplicação. O que é complicado e necessita ser abstraído é o Mapeamento Objeto Relacional e não o banco de dados (quem já fez isso, sabe bem o quão complicado pode ser)!

Não é por que se usa um framework ORM que não se deve conhecer SQL, bem pelo contrário.
[/quote]

São dois caminhos diferentes:

:arrow: ou vc decide aprender e entender o Hibernate, com todas as sua complexidades e mágica e fazer todas as suas queries com HQL e Criteria (não faz sentido usar SQL com Hibernate).

:arrow: ou vc conclui que banco-de-dados não é um bicho de sete cabeças e vai de SQL + JDBC + MentaBean (ou iBatis).

A vantagem da última opção é que você vai estar no controle e vai saber exatamente o que acontece e quando. E mais linhas de código não é necessariamente pior. E essas linhas estarão abstraídas dentro dos seus DAOs, assim como o código do Hibernate estaria.

Se o cara não sabe SQL, não sabe banco de dados, nunca escreveu um DAO, Hibernate será uma grande pedida. O meu ponto é que para o cara que sabe essas coisas e se sente confortável em falar diretamente com o banco-de-dados, precisa fazer queries complexas, etc. usar Hibernate é um grande contra-senso. É trazer para o seu projeto uma complexidade desnecessária através de um framework heavyweight. A linguagem que todos os banco-de-dados entendem é SQL, então seria legal utilizar essa linguagem.

E mais uma coisa: veja como a abstração feita pelo Hibernate cai na questão de “trocar uma complexidade por outra maior/pior”. Para constatar isso veja quantas perguntas e problemas relacionados ao Hibernate há aqui no GUJ. De simples, e rápido não tem absolutamente nada. O meu ponto é que as pessoas não deveriam ser obrigados a usá-lo, principalmente se entendem de banco-de-dados. Abstração só é bem-vinda quando ela consegue abstrair reduzindo drasticamente a complexidade sem comprometer a flexibilidade. Se não o Maker seria e a melhor coisa do mundo.
[/quote]

Olha, você continua usando de falácias ao dizer que hibernate faz mágica e que com ele não é necessário conhecer o banco de dados.
Como não conhecer o banco de dados se muitas vezes é necessário entender como uma consulta criada pelo se framework ORM favorito (Seja o Hibernate, MentaBeans, IBatis, etc) está lenta e é necessário otimiza-la?
O uso de um framework ORM não substitui o conhecimento do banco de dados, pois ainda é necessário criar as tabelas, índices, storeds procedures, etc! O conhecimento de um não invalida o conhecimento do outro. Conhecimento de banco de dados não se limita ao conhecimento de DQL.

Como disse antes, gosto é gosto e não se discute.

Mas o impacto de usar um framework ORM mais simples, como MentaBeans, em conjunto com JDBC, se da em aplicações complexas, com relacionamentos complexos entre classes.
O MentaBeans é bom para simples CRUD, mas uma aplicação complexa não é feito de simples CRUD. Então você pode usar JDBC para os casos mais complexos, como para mapear herança. Mas ai você está fazendo uma gambia para resolver um problema que deveria ser feito pelo seu ORM! Você não está usando a ferramenta certa para o problema certo.

O problema da utilização do JDBC do modo tradicional é a replicação de código entre diversas classes. A adição de um campo novo no banco cria um problema, pois diversas consultas devem ser alteradas, e como saber onde tudo deve ser alterado? Eu já tive esses problemas milhares de vezes em sistema com interface inteligente. Ai entra a programação orientada a objetos. Só que isso não resolve o problema, você pode criar um Active Record, só que você continuará tendo código replicado. Você então começa a buscar padrões e criar objetos especializados para realizar suas consultas, inserções, etc. A cada passo você se desvia mais do seu problema original que é o domínio da sua aplicação para fazer o mapeamento objeto relacional. O desenvolvimento do sistema se torna um exercício para criar um ORM!

Não que isso invalide o uso de um framework mais simples. Se você tem uma aplicação simples que faz uso direto de CRUDs e pouquíssimos casos complexos pode ser uma boa.
O uso de JDBC em uma aplicação muito simples também é válido. Na verdade o problema está em resolver o problema certo com a ferramenta certa. Usando as palavras do Martin Fowler:

[quote]Embora possamos identificar as três camadas usuais, apresentação,domínio e fonte de dados, em cada aplicação corporativa, a maneira simples para extrair dados de um único banco de dados e exibi-lo na Web pode, todo ele, consistir de um único procedimento. Eu ainda me esforçaria para separar as três camadas, mas, neste caso, poderia fazê-lo simplesmente colocando o comportamento de cada camada em sub-rotinas separadas. Se o sistema se tornasse mais complexo, quebraria as três camadas em classes separadas. Se a complexidade aumenta-se ainda mais, dividira as classes em pacotes separados[/quote].

Seus comentários, são depreciativos em relação ao Hibernate e isso não está certo. Se em seus sistemas ele não se faz necessário ótimo para você, mas o mundo não é feito só das só dos seus sistemas!

[quote=saoj][quote=x@ndy]
Chamar o JPA/Hibernate de gambiarra é não conhecer a importância do Mapeamento Objeto Relacional. Na verdade é não conhecer OOP. Pois se você programa orientado o objeto e não usar uma ferramenta ORM se torna praticamente impossível, pois você acaba se desviando do domínio da aplicação para desenvolver o mapeamento.
[/quote]

Eu uso DAOs para abstrair a camada de persistência. O mapeamento (seja via Ibatis, Hibernate ou MentaBean) só me ajuda a escrever os DAOs.
[/quote]

A meu está faltando um conhecimento em padrões para você! Não é por que você usa um framework que necessita usar um DAO. Você pode usar um Active Record. Assim como pode usar JDBC para fazer o mesmo.

Você sabe para que serve um DAO? Para a coisa mais óbvia da orientação a objetos, a separação de responsabilidades! Quando você está criando um DAO está passando a responsabilidade pela persistência para outro objeto. Então você compõe sua entidade com seu DAO, fazendo com ele se torne um Repository. Utlizando um DAO, você não precisa se preocupar como seus dados serão persistidos se concentrando no dominio da aplicação.