hibernate泛型Dao

【前言】hibernate作为持久层ORM技术,它对JDBC进行非常轻量级对象封装,使得我们可以随心所欲的使用面向对象的思想来操作数据库。同时,作为后台开发的支撑,的确扮演了一个举足轻重的角色,那么我们在项目中如何灵活应用hibernate,也会给项目维护以及项目开发带来便利,下面我将展示我们项目中是如何来对hibernate进行应用和操作。
【目录】 
            -----1. 自定义异常
            -----2. 泛型Dao搭建(SimpleHibernateDao)
            -----3. hibernate与spring整合

【内容】

              一、自定义异常(BussienssException),相信大家对Java异常处理机制还是比较熟悉,我们在业务层定义异常,那么可以对Jdbc中出现的如SqlException,DataAccessException进行统一处理,这样做的好处是,便于我们向前台发送异常消息,记录异常信息日志,控制事务回滚,下面就讲BussienssException罗列出来,其实很简单:

[java]  view plain  copy
  1. /** 
  2.  * @author fisher 
  3.  * @description 自定义业务异常 
  4.  */  
  5.   
  6. public class ServiceException extends RuntimeException {  
  7.   
  8.         /** 
  9.          *  
  10.          */  
  11.         private static final long serialVersionUID = 1L;  
  12.   
  13.         public ServiceException() {  
  14.    super();  
  15.         }  
  16.   
  17.         public ServiceException(String message) {  
  18.                 super(message);  
  19.         }  
  20.   
  21.         public ServiceException(Throwable cause) {  
  22.     super(cause);  
  23.         }  
  24.   
  25.         public ServiceException(String message, Throwable cause) {  
  26.    super(message, cause);  
  27.         }  
  28. }  
二:hibernate泛型Dao(SimpleHibernateDao),封装了原生hibernateAPI操作,实现了对不同Pojo对象进行操作,解决了常用的Crud,代码注释写得很详细,我就不啰嗦了,具体看代码:

[java]  view plain  copy
  1. /** 
  2.  * 封装Hibernate原生API的DAO泛型基类. 
  3.  *  
  4.  * 可在Service层直接使用, 也可以扩展泛型DAO子类使用, 见两个构造函数的注释. 参考Spring2.5自带的Petlinc例子, 
  5.  * 取消了HibernateTemplate, 直接使用Hibernate原生API. 
  6.  *  
  7.  * @param <T> 
  8.  *            DAO操作的对象类型 
  9.  * @param <PK> 
  10.  *            主键类型 
  11.  *  
  12.  * @author 
  13.  */  
  14. @SuppressWarnings("unchecked")  
  15. public class SimpleHibernateDao<T, PK extends Serializable> {  
  16.   
  17.     protected Logger logger = LoggerFactory.getLogger(getClass());  
  18.   
  19.     protected SessionFactory sessionFactory;  
  20.   
  21.      protected Class<T> entityClass;  
  22.   
  23.         /** 
  24.          * 用于Dao层子类使用的构造函数. 通过子类的泛型定义取得对象类型Class. eg. public class UserDao extends 
  25.          * SimpleHibernateDao<User, Long> 
  26.          */  
  27.         public SimpleHibernateDao() {  
  28.       this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());  
  29.         }  
  30.   
  31.         /** 
  32.          * 用于用于省略Dao层, 在Service层直接使用通用SimpleHibernateDao的构造函数. 在构造函数中定义对象类型Class. 
  33.          * eg. SimpleHibernateDao<User, Long> userDao = new SimpleHibernateDao<User, 
  34.          * Long>(sessionFactory, User.class); 
  35.          */  
  36.         public SimpleHibernateDao(final SessionFactory sessionFactory,  
  37.      final Class<T> entityClass) {  
  38.       this.sessionFactory = sessionFactory;  
  39.        this.entityClass = entityClass;  
  40.         }  
  41.   
  42.         /** 
  43.          * 取得sessionFactory. 
  44.          */  
  45.         public SessionFactory getSessionFactory() {  
  46.       return sessionFactory;  
  47.         }  
  48.   
  49.         /** 
  50.          * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数. 
  51.          */  
  52.         @Autowired  
  53.         public void setSessionFactory(final SessionFactory sessionFactory) {  
  54.    this.sessionFactory = sessionFactory;  
  55.         }  
  56.   
  57.         /** 
  58.          * 取得当前Session. 
  59.          */  
  60.         public Session getSession() {  
  61.    return sessionFactory.getCurrentSession();  
  62.         }  
  63.   
  64.         /** 
  65.          * 保存新增或修改的对象. 
  66.          */  
  67.         public void save(final T entity) {;  
  68.    getSession().saveOrUpdate(entity);  
  69.    logger.debug("save entity: {}", entity);  
  70.         }  
  71.   
  72.         /** 
  73.          * 删除对象. 
  74.          *  
  75.          * @param entity 
  76.          *            对象必须是session中的对象或含id属性的transient对象. 
  77.          */  
  78.         public void delete(final T entity) {  
  79.      getSession().delete(entity);  
  80.       logger.debug("delete entity: {}", entity);  
  81.         }  
  82.   
  83.         /** 
  84.          * 按id删除对象. 
  85.          */  
  86.         public void delete(final PK id) {  
  87.      delete(get(id));  
  88.      logger.debug("delete entity {},id is {}", entityClass.getSimpleName(),  
  89.                                 id);  
  90.         }  
  91.   
  92.         /** 
  93.          * 按id获取对象. 
  94.          */  
  95.         public T get(final PK id) {  
  96.     return (T) getSession().load(entityClass, id);  
  97.         }  
  98.   
  99.         /** 
  100.          * 按id列表获取对象列表. 
  101.          */  
  102.         public List<T> get(final Collection<PK> ids) {  
  103.     return find(Restrictions.in(getIdName(), ids));  
  104.         }  
  105.   
  106.         /** 
  107.          * 获取全部对象. 
  108.          */  
  109.         public List<T> getAll() {  
  110.    return find();  
  111.         }  
  112.   
  113.         /** 
  114.          * 获取全部对象, 支持按属性行序. 
  115.          */  
  116.         public List<T> getAll(String orderByProperty, boolean isAsc) {  
  117.     Criteria c = createCriteria();  
  118.     if (isAsc) {  
  119.       c.addOrder(Order.asc(orderByProperty));  
  120.      } else {  
  121.     c.addOrder(Order.desc(orderByProperty));  
  122.                 }  
  123.       return c.list();  
  124.         }  
  125.   
  126.         /** 
  127.          * 按属性查找对象列表, 默认匹配方式为Like. 
  128.          */  
  129.         public List<T> findByProperty(final String propertyName, final Object value) {  
  130.       Assert.hasText(propertyName, "propertyName不能为空");  
  131.       Criterion criterion = Restrictions.like(propertyName, (String) value,  
  132.         MatchMode.ANYWHERE);  
  133.       return find(criterion);  
  134.         }  
  135.   
  136.         /** 
  137.          * 按属性查找唯一对象, 默认匹配方式为Like. 
  138.          */  
  139.         public T findUniqueByProperty(final String propertyName, final Object value) {  
  140.          Assert.hasText(propertyName, "propertyName不能为空");  
  141.         Criterion criterion = Restrictions.like(propertyName, (String) value,  
  142.          MatchMode.ANYWHERE);  
  143.        return (T) createCriteria(criterion).uniqueResult();  
  144.         }  
  145.   
  146.         /** 
  147.          * 按HQL查询对象列表. 
  148.          *  
  149.          * @param <X> 
  150.          *  
  151.          * @param values 
  152.          *            数量可变的参数,按顺序绑定. 
  153.          */  
  154.         public <X> List<X> find(final String hql, final Object... values) {  
  155.       return createQuery(hql, values).list();  
  156.         }  
  157.   
  158.         /** 
  159.          * 按HQL查询对象列表. 
  160.          *  
  161.          * @param values 
  162.          *            命名参数,按名称绑定. 
  163.          */  
  164.         public <X> List<X> find(final String hql, final Map<String, ?> values) {  
  165.       return createQuery(hql, values).list();  
  166.         }  
  167.   
  168.         /** 
  169.          * 按HQL查询唯一对象. 
  170.          *  
  171.          * @param values 
  172.          *            数量可变的参数,按顺序绑定. 
  173.          */  
  174.         public <X> X findUnique(final String hql, final Object... values) {  
  175.       return (X) createQuery(hql, values).uniqueResult();  
  176.         }  
  177.   
  178.         /** 
  179.          * 按HQL查询唯一对象. 
  180.          *  
  181.          * @param values 
  182.          *            命名参数,按名称绑定. 
  183.          */  
  184.         public <X> X findUnique(final String hql, final Map<String, ?> values) {  
  185.      return (X) createQuery(hql, values).uniqueResult();  
  186.         }  
  187.   
  188.         /** 
  189.          * 执行HQL进行批量修改/删除操作. 
  190.          *  
  191.          * @param values 
  192.          *            数量可变的参数,按顺序绑定. 
  193.          * @return 更新记录数. 
  194.          */  
  195.         public int batchExecute(final String hql, final Object... values) {  
  196.      return createQuery(hql, values).executeUpdate();  
  197.         }  
  198.   
  199.         /** 
  200.          * 执行HQL进行批量修改/删除操作. 
  201.          *  
  202.          * @param values 
  203.          *            命名参数,按名称绑定. 
  204.          * @return 更新记录数. 
  205.          */  
  206.         public int batchExecute(final String hql, final Map<String, ?> values) {  
  207.       return createQuery(hql, values).executeUpdate();  
  208.         }  
  209.   
  210.         /** 
  211.          * 根据查询HQL与参数列表创建Query对象. 与find()函数可进行更加灵活的操作. 
  212.          *  
  213.          * @param values 
  214.          *            数量可变的参数,按顺序绑定. 
  215.          */  
  216.         public Query createQuery(final String queryString, final Object... values) {  
  217.         Assert.hasText(queryString, "queryString不能为空");  
  218.       Query query = getSession().createQuery(queryString);  
  219.                 if (values != null) {  
  220.          for (int i = 0; i < values.length; i++) {  
  221.          query.setParameter(i, values[i]);  
  222.                         }  
  223.                 }  
  224.    return query;  
  225.         }  
  226.   
  227.         /** 
  228.          * 根据查询HQL与参数列表创建Query对象. 与find()函数可进行更加灵活的操作. 
  229.          *  
  230.          * @param values 
  231.          *            命名参数,按名称绑定. 
  232.          */  
  233.         public Query createQuery(final String queryString,  
  234.                         final Map<String, ?> values) {  
  235.   
  236.                 Query query = getSession().createQuery(queryString);  
  237.                 if (values != null) {  
  238.                         query.setProperties(values);  
  239.                 }  
  240.                 return query;  
  241.         }  
  242.   
  243.         /** 
  244.          * 按Criteria查询对象列表. 
  245.          *  
  246.          * @param criterions 
  247.          *            数量可变的Criterion. 
  248.          */  
  249.         public List<T> find(final Criterion... criterions) {  
  250.                 return createCriteria(criterions).list();  
  251.         }  
  252.   
  253.         /** 
  254.          * 按Criteria查询唯一对象. 
  255.          *  
  256.          * @param criterions 
  257.          *            数量可变的Criterion. 
  258.          */  
  259.         public T findUnique(final Criterion... criterions) {  
  260.                 return (T) createCriteria(criterions).uniqueResult();  
  261.         }  
  262.   
  263.         /** 
  264.          * 根据Criterion条件创建Criteria. 与find()函数可进行更加灵活的操作. 
  265.          *  
  266.          * @param criterions 
  267.          *            数量可变的Criterion. 
  268.          */  
  269.         public Criteria createCriteria(final Criterion... criterions) {  
  270.                 Criteria criteria = getSession().createCriteria(entityClass);  
  271.                 for (Criterion c : criterions) {  
  272.                         criteria.add(c);  
  273.                 }  
  274.                 return criteria;  
  275.         }  
  276.   
  277.         /** 
  278.          * 初始化对象. 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化. 如果传入entity, 
  279.          * 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. 如需初始化关联属性,需执行: 
  280.          * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合. 
  281.          * Hibernate.initialize 
  282.          * (user.getDescription()),初始化User的直接属性和延迟加载的Description属性. 
  283.          */  
  284.         public void initProxyObject(Object proxy) {  
  285.                 Hibernate.initialize(proxy);  
  286.         }  
  287.   
  288.         /** 
  289.          * Flush当前Session. 
  290.          */  
  291.         public void flush() {  
  292.                 getSession().flush();  
  293.         }  
  294.   
  295.         /** 
  296.          * 为Query添加distinct transformer. 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理. 
  297.          */  
  298.         public Query distinct(Query query) {  
  299.                 query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);  
  300.                 return query;  
  301.         }  
  302.   
  303.         /** 
  304.          * 为Criteria添加distinct transformer. 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理. 
  305.          */  
  306.         public Criteria distinct(Criteria criteria) {  
  307.                 criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);  
  308.                 return criteria;  
  309.         }  
  310.   
  311.         /** 
  312.          * 取得对象的主键名. 
  313.          */  
  314.         public String getIdName() {  
  315.                 ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);  
  316.                 return meta.getIdentifierPropertyName();  
  317.         }  
  318.   
  319.         /** 
  320.          * 判断对象的属性值在数据库内是否唯一. 
  321.          *  
  322.          * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较. 
  323.          */  
  324.         public boolean isPropertyUnique(final String propertyName,  
  325.                         final Object newValue, final Object oldValue) {  
  326.                 if (newValue == null || newValue.equals(oldValue)) {  
  327.                         return true;  
  328.                 }  
  329.                 Object object = findUniqueByProperty(propertyName, newValue);  
  330.                 return (object == null);  
  331.         }  
  332. }  

三、spring与hibernate整合,关于spring与hibernate的整合问题,我分两步来谈:
              1.配置spring的数据源Datasource,关系配置数据库连接,相信很多童鞋对它很熟悉,我们要获取数据库连接,首先是从连接池中去找,那么常用的连接池分3种(DBCP,C3P0,Proxool),这里以mysql与DBCP为例:

datasource.properties:

[plain]  view plain  copy
  1. jdbc.driver=com.mysql.jdbc.Driver  
  2. jdbc.url=jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf-8  
  3. jdbc.username=root  
  4. jdbc.password=  

 applicationContext.xml

[html]  view plain  copy
  1. <!-- 定义属性文件路径 -->  
  2.        <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  3.                <property name="locations">  
  4.                        <list>  
  5.                                <!-- 标准配置,路径都以项目classpath为准-->  
  6.                                <value>classpath:/datasource.properties</value>  
  7.                        </list>  
  8.                </property>  
  9.        </bean>  
  10.   
  11.        <!-- 数据源配置, 使用应用中的DBCP数据库连接池 -->  
  12.        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  13.                <!-- Connection Info -->  
  14.                <property name="driverClassName" value="${jdbc.driver}" />  
  15.                <property name="url" value="${jdbc.url}" />  
  16.                <property name="username" value="${jdbc.username}" />  
  17.                <property name="password" value="${jdbc.password}" />  
  18.   
  19.                <!-- Connection Pooling Info -->  
  20.                <property name="maxActive" value="${dbcp.maxActive}" />  
  21.                <property name="maxIdle" value="${dbcp.maxIdle}" />  
  22.                <property name="defaultAutoCommit" value="false" />  
  23.                <property name="timeBetweenEvictionRunsMillis" value="3600000"/>  
  24.                <property name="minEvictableIdleTimeMillis" value="3600000"/>  
  25.        </bean>  

 2.配置Sessionfactory、transactionManager,这样我们就有了对事务的控制、以及可以获取到hibernate的会话。

[html]  view plain  copy
  1.               <property name="sessionFactory" ref="sessionFactory"></property>  
  2.         </bean>          
  3.   
  4. <!--####{事务管理器}#### -->  
  5.         <bean id="transactionManager"  
  6.                 class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  7.                 <property name="sessionFactory" ref="sessionFactory" />  
  8.         </bean>  
  9.                   
  10.         <!-- ####{事务传播特性 }#### -->  
  11.         <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  12.                 <tx:attributes>  
  13.                         <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>  
  14.                         <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>  
  15.                         <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>  
  16.                         <tx:method name="get*" propagation="SUPPORTS" read-only="true" />  
  17.                         <tx:method name="*" read-only="false" />  
  18.                 </tx:attributes>  
  19.         </tx:advice>  
  20.         <!-- ####{配置切入点和通知}#### -->  
  21.         <aop:config>  
  22.                 <aop:pointcut id="allServiceMethod" expression="execution(* com.mis.service..*.*(..))" />  
  23.                 <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />  
  24.                 <aop:aspect id="logBean" ref="systemLogAspectService">  
  25.                         <aop:before method="beforeCut" pointcut-ref="allServiceMethod"/>  
  26.                         <aop:after method="afterCut" pointcut-ref="allServiceMethod"/>                          
  27.                 </aop:aspect>  
  28.         </aop:config>  
【总结】   关于持久层的技术,hibernat它的优势非常明显,能让java程序员很直观去通过对象去操作数据库,但是在处理报表或者非常复杂的数据库查询的时候也显得有点棘手,上面的泛型dao只是针对常用操作进行封装,对于处理特殊情况我建议还是采用原生Sql方式去处理,这篇文章也就差不多了。相信用过hibernate的人都知道如何去编写hbm映射文件,添加依赖包,这里我就没有详细介绍,也没有实际例子来实现,还是那句话,我是从项目架构出发,给大家在搭建系统的时候提供思路和参考。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值