zoukankan      html  css  js  c++  java
  • 《项目架构那点儿事》——Hibernate泛型Dao,让持久层简洁起来

    【前言】hibernate作为持久层ORM技术,它对JDBC进行非常轻量级对象封装,使得我们可以随心所欲的使用面向对象的思想来操作数据 库。同时,作为后台开发的支撑,的确扮演了一个举足轻重的角色,那么我们在项目中如何灵活应用hibernate,也会给项目维护以及项目开发带来便利, 下面我将展示我们项目中是如何来对hibernate进行应用和操作。
    【目录】 
                -----1.自定义异常
                -----2.泛型Dao搭建(SimpleHibernateDao)
                -----3.hibernate与spring整合
    【内容】
      一、自定义异常(BussienssException),相信大家对java异常处理机制还是比较熟悉,我们在业务层定义异常,那么可以对Jdbc中 出现的如SqlException,DataAccessException进行统一处理,这样做的好处是,便于我们向前台发送异常消息,记录异常信息日 志,控制事务回滚,下面就讲BussienssException罗列出来,其实很简单:
     
    /**
    * @author fisher
    * @description 自定义业务异常
    */
     
    public class ServiceException extends RuntimeException {
     
            /**
             * 
             */
            private static final long serialVersionUID = 1L;
     
            public ServiceException() {
       super();
            }
     
            public ServiceException(String message) {
                    super(message);
            }
     
            public ServiceException(Throwable cause) {
        super(cause);
            }
     
            public ServiceException(String message, Throwable cause) {
       super(message, cause);
            }
    }
      二:hibernate泛型Dao(SimpleHibernateDao),封装了原生hibernateAPI操作,实现了对不同Pojo对象进行操作,解决了常用的Crud,代码注释写得很详细,我就不啰嗦了,具体看代码:
    /**
    * 封装Hibernate原生API的DAO泛型基类.
    * 
    * 可在Service层直接使用, 也可以扩展泛型DAO子类使用, 见两个构造函数的注释. 参考Spring2.5自带的Petlinc例子,
    * 取消了HibernateTemplate, 直接使用Hibernate原生API.
    * 
    * @param <T>
    *            DAO操作的对象类型
    * @param <PK>
    *            主键类型
    * 
    * @author
    */
    @SuppressWarnings("unchecked")
    public class SimpleHibernateDao<T, PK extends Serializable> {
     
        protected Logger logger = LoggerFactory.getLogger(getClass());
     
        protected SessionFactory sessionFactory;
     
         protected Class<T> entityClass;
     
            /**
             * 用于Dao层子类使用的构造函数. 通过子类的泛型定义取得对象类型Class. eg. public class UserDao extends
             * SimpleHibernateDao<User, Long>
             */
            public SimpleHibernateDao() {
          this.entityClass = ReflectionUtils.getSuperClassGenricType(getClass());
            }
     
            /**
             * 用于用于省略Dao层, 在Service层直接使用通用SimpleHibernateDao的构造函数. 在构造函数中定义对象类型Class.
             * eg. SimpleHibernateDao<User, Long> userDao = new SimpleHibernateDao<User,
             * Long>(sessionFactory, User.class);
             */
            public SimpleHibernateDao(final SessionFactory sessionFactory,
         final Class<T> entityClass) {
          this.sessionFactory = sessionFactory;
           this.entityClass = entityClass;
            }
     
            /**
             * 取得sessionFactory.
             */
            public SessionFactory getSessionFactory() {
          return sessionFactory;
            }
     
            /**
             * 采用@Autowired按类型注入SessionFactory, 当有多个SesionFactory的时候在子类重载本函数.
             */
            @Autowired
            public void setSessionFactory(final SessionFactory sessionFactory) {
       this.sessionFactory = sessionFactory;
            }
     
            /**
             * 取得当前Session.
             */
            public Session getSession() {
       return sessionFactory.getCurrentSession();
            }
     
            /**
             * 保存新增或修改的对象.
             */
            public void save(final T entity) {;
       getSession().saveOrUpdate(entity);
       logger.debug("save entity: {}", entity);
            }
     
            /**
             * 删除对象.
             * 
             * @param entity
             *            对象必须是session中的对象或含id属性的transient对象.
             */
            public void delete(final T entity) {
         getSession().delete(entity);
          logger.debug("delete entity: {}", entity);
            }
     
            /**
             * 按id删除对象.
             */
            public void delete(final PK id) {
         delete(get(id));
         logger.debug("delete entity {},id is {}", entityClass.getSimpleName(),
                                    id);
            }
     
            /**
             * 按id获取对象.
             */
            public T get(final PK id) {
        return (T) getSession().load(entityClass, id);
            }
     
            /**
             * 按id列表获取对象列表.
             */
            public List<T> get(final Collection<PK> ids) {
        return find(Restrictions.in(getIdName(), ids));
            }
     
            /**
             * 获取全部对象.
             */
            public List<T> getAll() {
       return find();
            }
     
            /**
             * 获取全部对象, 支持按属性行序.
             */
            public List<T> getAll(String orderByProperty, boolean isAsc) {
        Criteria c = createCriteria();
        if (isAsc) {
          c.addOrder(Order.asc(orderByProperty));
         } else {
        c.addOrder(Order.desc(orderByProperty));
                    }
          return c.list();
            }
     
            /**
             * 按属性查找对象列表, 默认匹配方式为Like.
             */
            public List<T> findByProperty(final String propertyName, final Object value) {
          Assert.hasText(propertyName, "propertyName不能为空");
          Criterion criterion = Restrictions.like(propertyName, (String) value,
            MatchMode.ANYWHERE);
          return find(criterion);
            }
     
            /**
             * 按属性查找唯一对象, 默认匹配方式为Like.
             */
            public T findUniqueByProperty(final String propertyName, final Object value) {
             Assert.hasText(propertyName, "propertyName不能为空");
            Criterion criterion = Restrictions.like(propertyName, (String) value,
             MatchMode.ANYWHERE);
           return (T) createCriteria(criterion).uniqueResult();
            }
     
            /**
             * 按HQL查询对象列表.
             * 
             * @param <X>
             * 
             * @param values
             *            数量可变的参数,按顺序绑定.
             */
            public <X> List<X> find(final String hql, final Object... values) {
          return createQuery(hql, values).list();
            }
     
            /**
             * 按HQL查询对象列表.
             * 
             * @param values
             *            命名参数,按名称绑定.
             */
            public <X> List<X> find(final String hql, final Map<String, ?> values) {
          return createQuery(hql, values).list();
            }
     
            /**
             * 按HQL查询唯一对象.
             * 
             * @param values
             *            数量可变的参数,按顺序绑定.
             */
            public <X> X findUnique(final String hql, final Object... values) {
          return (X) createQuery(hql, values).uniqueResult();
            }
     
            /**
             * 按HQL查询唯一对象.
             * 
             * @param values
             *            命名参数,按名称绑定.
             */
            public <X> X findUnique(final String hql, final Map<String, ?> values) {
         return (X) createQuery(hql, values).uniqueResult();
            }
     
            /**
             * 执行HQL进行批量修改/删除操作.
             * 
             * @param values
             *            数量可变的参数,按顺序绑定.
             * @return 更新记录数.
             */
            public int batchExecute(final String hql, final Object... values) {
         return createQuery(hql, values).executeUpdate();
            }
     
            /**
             * 执行HQL进行批量修改/删除操作.
             * 
             * @param values
             *            命名参数,按名称绑定.
             * @return 更新记录数.
             */
            public int batchExecute(final String hql, final Map<String, ?> values) {
          return createQuery(hql, values).executeUpdate();
            }
     
            /**
             * 根据查询HQL与参数列表创建Query对象. 与find()函数可进行更加灵活的操作.
             * 
             * @param values
             *            数量可变的参数,按顺序绑定.
             */
            public Query createQuery(final String queryString, final Object... values) {
            Assert.hasText(queryString, "queryString不能为空");
          Query query = getSession().createQuery(queryString);
                    if (values != null) {
             for (int i = 0; i < values.length; i++) {
             query.setParameter(i, values[i]);
                            }
                    }
       return query;
            }
     
            /**
             * 根据查询HQL与参数列表创建Query对象. 与find()函数可进行更加灵活的操作.
             * 
             * @param values
             *            命名参数,按名称绑定.
             */
            public Query createQuery(final String queryString,
                            final Map<String, ?> values) {
     
                    Query query = getSession().createQuery(queryString);
                    if (values != null) {
                            query.setProperties(values);
                    }
                    return query;
            }
     
            /**
             * 按Criteria查询对象列表.
             * 
             * @param criterions
             *            数量可变的Criterion.
             */
            public List<T> find(final Criterion... criterions) {
                    return createCriteria(criterions).list();
            }
     
            /**
             * 按Criteria查询唯一对象.
             * 
             * @param criterions
             *            数量可变的Criterion.
             */
            public T findUnique(final Criterion... criterions) {
                    return (T) createCriteria(criterions).uniqueResult();
            }
     
            /**
             * 根据Criterion条件创建Criteria. 与find()函数可进行更加灵活的操作.
             * 
             * @param criterions
             *            数量可变的Criterion.
             */
            public Criteria createCriteria(final Criterion... criterions) {
                    Criteria criteria = getSession().createCriteria(entityClass);
                    for (Criterion c : criterions) {
                            criteria.add(c);
                    }
                    return criteria;
            }
     
            /**
             * 初始化对象. 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化. 如果传入entity,
             * 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. 如需初始化关联属性,需执行:
             * Hibernate.initialize(user.getRoles()),初始化User的直接属性和关联集合.
             * Hibernate.initialize
             * (user.getDescription()),初始化User的直接属性和延迟加载的Description属性.
             */
            public void initProxyObject(Object proxy) {
                    Hibernate.initialize(proxy);
            }
     
            /**
             * Flush当前Session.
             */
            public void flush() {
                    getSession().flush();
            }
     
            /**
             * 为Query添加distinct transformer. 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
             */
            public Query distinct(Query query) {
                    query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    return query;
            }
     
            /**
             * 为Criteria添加distinct transformer. 预加载关联对象的HQL会引起主对象重复, 需要进行distinct处理.
             */
            public Criteria distinct(Criteria criteria) {
                    criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
                    return criteria;
            }
     
            /**
             * 取得对象的主键名.
             */
            public String getIdName() {
                    ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);
                    return meta.getIdentifierPropertyName();
            }
     
            /**
             * 判断对象的属性值在数据库内是否唯一.
             * 
             * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
             */
            public boolean isPropertyUnique(final String propertyName,
                            final Object newValue, final Object oldValue) {
                    if (newValue == null || newValue.equals(oldValue)) {
                            return true;
                    }
                    Object object = findUniqueByProperty(propertyName, newValue);
                    return (object == null);
            }
    }
      三、spring与hibernate整合,关于spring与hibernate的整合问题,我分两步来谈:
      1.配置spring的数据源Datasource,关系配置数据库连接,相信很多童鞋对它很熟悉,我们要获取数据库连接,首先是从连接池中去找,那么 常用的连接池分3种(DBCP,C3P0,Proxool),这里以mysql与DBCP为例:
     
    datasource.properties:
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost/test?useUnicode=true&characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=
     
    applicationContext.xml 
    <!-- 定义属性文件路径 -->
            <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
                    <property name="locations">
                            <list>
                                    <!-- 标准配置,路径都以项目classpath为准-->
                                    <value>classpath:/datasource.properties</value>
                            </list>
                    </property>
            </bean>
     
            <!-- 数据源配置, 使用应用中的DBCP数据库连接池 -->
            <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
                    <!-- Connection Info -->
                    <property name="driverClassName" value="${jdbc.driver}" />
                    <property name="url" value="${jdbc.url}" />
                    <property name="username" value="${jdbc.username}" />
                    <property name="password" value="${jdbc.password}" />
     
                    <!-- Connection Pooling Info -->
                    <property name="maxActive" value="${dbcp.maxActive}" />
                    <property name="maxIdle" value="${dbcp.maxIdle}" />
                    <property name="defaultAutoCommit" value="false" />
                    <property name="timeBetweenEvictionRunsMillis" value="3600000"/>
                    <property name="minEvictableIdleTimeMillis" value="3600000"/>
            </bean>

      

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

    applicationContext.xml:
    <!-- Hibernate配置 -->
            <bean id="sessionFactory"
                    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"">
                       <property name="dataSource" ref="dataSource" />
                    <property name="mappingLocations">
                            <list>
                                    <value>这里是Hbm文件</value>
                            </list>
                    </property>
                    <property name="hibernateProperties">
                            <props>
                                    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                                    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                                    <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
                                    <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                                    <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache/ehcache-hibernate-local.xml</prop>
                            </props>
                    </property>
     
            </bean>
         <!--注入simplehibernateDao-->
            <bean id="simplehibernateDao" class="com.dao.SimpleHibernateDao">         
    复制代码
                  <property name="sessionFactory" ref="sessionFactory"></property>
            </bean>        
     
    <!--####{事务管理器}#### -->
            <bean id="transactionManager"
                    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                    <property name="sessionFactory" ref="sessionFactory" />
            </bean>
                    
            <!-- ####{事务传播特性 }#### -->
            <tx:advice id="txAdvice" transaction-manager="transactionManager">
                    <tx:attributes>
                            <tx:method name="save*" 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="get*" propagation="SUPPORTS" read-only="true" />
                            <tx:method name="*" read-only="false" />
                    </tx:attributes>
            </tx:advice>
            <!-- ####{配置切入点和通知}#### -->
            <aop:config>
                    <aop:pointcut id="allServiceMethod" expression="execution(* com.mis.service..*.*(..))" />
                    <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />
                    <aop:aspect id="logBean" ref="systemLogAspectService">
                            <aop:before method="beforeCut" pointcut-ref="allServiceMethod"/>
                            <aop:after method="afterCut" pointcut-ref="allServiceMethod"/>                        
                    </aop:aspect>
            </aop:config>
     

    【总 结】   关于持久层的技术,hibernat它的优势非常明显,能让java程序员很直观去通过对象去操作数据库,但是在处理报表或者非常复杂的数据库查询的时候 也显得有点棘手,上面的泛型dao只是针对常用操作进行封装,对于处理特殊情况我建议还是采用原生Sql方式去处理,这篇文章也就差不多了。相信用过 hibernate的人都知道如何去编写hbm映射文件,添加依赖包,这里我就没有详细介绍,也没有实际例子来实现,还是那句话,我是从项目架构出发,给 大家在搭建系统的时候提供思路和参考。  

  • 相关阅读:
    Hdu 5396 Expression (区间Dp)
    Lightoj 1174
    codeforces 570 D. Tree Requests (dfs)
    codeforces 570 E. Pig and Palindromes (DP)
    Hdu 5385 The path
    Hdu 5384 Danganronpa (AC自动机模板)
    Hdu 5372 Segment Game (树状数组)
    Hdu 5379 Mahjong tree (dfs + 组合数)
    Hdu 5371 Hotaru's problem (manacher+枚举)
    Face The Right Way---hdu3276(开关问题)
  • 原文地址:https://www.cnblogs.com/xinhudong/p/4913426.html
Copyright © 2011-2022 走看看