使用泛型写了一个通用的Hibernate DAO类。
GenericDao接口
package com.my.dao; import java.io.Serializable; import java.util.List; /** * Generic DAO interface * @author Robin * * @param <T> * @param <PK> */ public interface GenericDao<T extends Serializable, PK extends Serializable> { /** * Create entity * @param entity */ void create(T entity); /** * Update entity * @param entity */ void update(T entity); /** * Create or Update entity * @param entity POJO */ void saveOrUpdate(T entity); /** * Delete entity * @param entity */ void delete(T entity); /** * Find entity by id * @param id ID * @return Entity */ T find(PK id); /** * Find all entities * @return */ List<T> findAll(); /** * Find all entities by paging * @param pageNumber * @param pageSize * @return */ List<T> findList(int pageNumber, int pageSize); /** * All row count * @return */ Long count(); }
GenericDaoSupport主类:
package com.my.dao; import javax.annotation.Resource; import org.hibernate.Session; import org.hibernate.SessionFactory; /** * Generic Dao Base Class * @author Robin * */ public abstract class GenericDaoSupport { @Resource protected SessionFactory sessionFactory; /** * Get Hibernate Session * @return */ public Session getSession() { return this.sessionFactory.getCurrentSession(); } }
通用DAO类实现:
package com.my.dao.impl; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import org.hibernate.criterion.Projections; import com.my.dao.GenericDao; import com.my.dao.GenericDaoSupport; /** * Generic DAO class * @author Robin * * @param <T> * @param <PK> */ @SuppressWarnings("all") public class GenericDaoImpl<T extends Serializable, PK extends Serializable> extends GenericDaoSupport implements GenericDao<T, PK> { // Entity class private Class<T> entityClass; /** * Constructor */ public GenericDaoImpl() { // 通过反射获取T的类型信息实例 this.entityClass = (Class<T>) ((ParameterizedType) this.getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } /** * Create entity * @param entity */ @Override public void create(T entity) { getSession().save(entity); } /** * Update entity * @param entity */ @Override public void update(T entity) { getSession().update(entity); } /** * Create or Update entity * @param entity */ @Override public void saveOrUpdate(T entity) { getSession().saveOrUpdate(entity); } /** * Delete entity * @param entity */ public void delete(T entity){ getSession().delete(entity); } /** * Find entity by id * @param id * @return Entity */ @Override public T find(PK id) { return (T) getSession().get(entityClass, id); } /** * Find all entities * @return */ @Override public List<T> findAll() { return getSession().createCriteria(entityClass).list(); } /** * Find all entities by paging * @param pageNumber * @param pageSize * @return */ public List<T> findList(int pageNumber, int pageSize) { return getSession().createCriteria(entityClass) .setFirstResult((pageNumber - 1) * pageSize) .setMaxResults(pageSize) .list(); } /** * All row count * @return */ public Long count() { Long count = (Long)getSession().createCriteria(entityClass) .setProjection(Projections.rowCount()) .uniqueResult(); if(count == null) { return (long)0; } else { return count; } } }
Hibernate实体:
package com.my.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @SuppressWarnings("serial") @Entity @Table(name = "account") public class Account implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private long id; @Column(name = "name", length = 200) private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
实体类必需继承Serializable接口。
使用方法例子:
写一个AccountDao接口
package com.my.dao; import org.springframework.stereotype.Repository; import com.my.entity.Account; @Repository public interface AccountDao extends GenericDao<Account, Long> { }
AccountDao接口的实现:
package com.my.dao.impl; import org.springframework.stereotype.Repository; import com.my.dao.AccountDao; import com.my.entity.Account; @Repository(value = "accountDao") public class AccountDaoImpl extends GenericDaoImpl<Account, Long> implements AccountDao { }
Service的实现和使用:
package com.my.service; import java.util.List; import com.my.entity.Account; public abstract class AccountService { /** * Add new account * @param account Account */ public abstract void add(Account account); /** * Find entity by id * @param id * @return */ public abstract Account find(long id); /** * Find all entities * @return */ public abstract List<Account> findAll(); /** * Find all entities by paging * @param pageNumber * @param pageSize * @return */ public abstract List<Account> findList(int pageNumber, int pageSize); /** * All row count * @return */ public abstract long count(); }
package com.my.service.impl; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.my.dao.AccountDao; import com.my.entity.Account; import com.my.service.AccountService; @Service(value = "accountService") public class AccountServiceImpl extends AccountService { @Resource(name = "accountDao") private AccountDao accountDao; public void add(Account account) { accountDao.saveOrUpdate(account); } @Override public Account find(long id) { return accountDao.find(id); } @Override public List<Account> findAll(){ return accountDao.findAll(); } @Override public List<Account> findList(int pageNumber, int pageSize) { return accountDao.findList(pageNumber, pageSize); } @Override public long count() { return accountDao.count(); } }
可以看到上面Service的调用对应的AccountDao中,不需要再写其它方法。因为在通用DAO中已经实现了。AccountDao只需要加入其它额外的方法即可,比如说特例的查询。
当然可以把通用DAO封装得更加“完美”,比如把查询条件都写上。
网上有一些通用的DAO写法,会把HQL写在Service层,这种破坏了BLL和DAO的分离。
附上Spring的xml配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1/test" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan"> <list> <value>com.my.entity</value> </list> </property> <property name="hibernateProperties"> <value> hibernate.dialect=org.hibernate.dialect.MySQL5Dialect hibernate.hbm2ddl.auto=update hibernate.show_sql=true hibernate.format_sql=false hibernate.cache.use_second_level_cache=true hibernate.cache.use_query_cache=false hibernate.cache.provider_class=org.hibernate.cache.internal.NoCacheProvider hibernate.current_session_context_class= org.springframework.orm.hibernate4.SpringSessionContext </value> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <context:component-scan base-package="com.my" /> <tx:annotation-driven transaction-manager="txManager" /> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="*" read-only="true"/> <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception"/> <tx:method name="change*" propagation="REQUIRED" rollback-for="Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="allServiceMethods" expression="execution(* com.my.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="allServiceMethods"/> </aop:config> </beans>