• 关于项目中的DAL数据接入层架构设计


    摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate、Spring、Hessian这三大工具对DAL层的具体实现方法,也是对之前使用的一个总结
    关键词:Hibernate, Spring, Hessian, DAL, 数据接入层, 架构设计

    注意:以下配置代码运行在Hibernate4.2.5,Spring3.2.4,Hessian4.0.37,Tomcat7.0.47环境下
     
    一、Model们
    做数据接入,最根本的就是数据了,数据库中的数据和JAVA中的对象完美映射是ORM-Hibernate做的事。一般项目中是先定义Model,再通过Model在数据库中生成表结构,也有动态生成表结构、对象的需求,关于这点将在以后的博客中专门讲述。下面的代码段是比较普遍的基础的“角色类”的Model定义,我们使用Spring通过标签的形式注入,注意Entity和 Id标签。我们一般还可以通过@Column(name = "tableName", length = 50, nullable = false, unique = true)这一标签定义某一属性在数据库中映射字段的名称、长度等信息,时间将通过Calendar这一JAVA类型映射,关于Model的定义还有很多其它理论,比如一对多、多对一、多对多的关系、延迟加载等,这里还是交给Hibernate相关书籍吧。
    /**
     * 角色对象
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2013年7月30日上午10:32:55
     */
    @SuppressWarnings("serial")
    @Entity
    public class Role implements Serializable
    {
        private Long id;
        private String name;
        private String description;
     
        // ********************** Accessor Methods ********************** //
        @Id
        @GeneratedValue
        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;
        }
     
        public String getDescription()
        {
            return description;
        }
     
        public void setDescription(String description)
        {
            this.description = description;
        }
    }
     
    别忘了写完Model要在hibernate.cfg.xml里把它给配置上,要不然打死你也不能在数据库中找到Role这张表的。hibernate.cfg.xml配置文件,配置了连接数据库、如何使用Hibernate的配置信息,如下所示。
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                             "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
        <session-factory>
            <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
            <property name="hibernate.connection.username">username</property>
            <property name="hibernate.connection.password">password</property>
            <property name="hibernate.connection.url">jdbc:mysql://IP地址:3306/schema名</property>        
            <!-- <property name="hibernate.connection.characterEncoding">gbk</property> -->
            <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
            <property name="hibernate.c3p0.max_size">1</property>
            <property name="hibernate.c3p0.min_size">1</property>
            <property name="hibernate.c3p0.timeout">180</property>
            <property name="hibernate.c3p0.max_statements">50</property>
            <property name="hibernate.show_sql">true</property>
            <property name="hibernate.format_sql">true</property>
            <property name="hibernate.jdbc.fetch_size">50</property>
            <property name="hibernate.jdbc.batch_size">50</property>
            <property name="hibernate.hbm2ddl.auto">update</property>
            <!-- <property name="hibernate.connection.autocommit">true</property> -->
            <mapping class="com.wang.anqi.model.Role" />        
        </session-factory>
    </hibernate-configuration>
     
    二、DAO层
    先定义RoleDAO这一接口,RoleDAO比较简单,它在GenericDAO的基础上增添了它独有的接口:findByRoleName,按照角色名称查找对应的用户列表。GenericDAO是各个DAO的通用模板,它包含了各基本数据访问操作,如增删改查CRUD等,继承自它的类必然会支持这些操作。
    /**
     * DAO层接口-角色
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2013年7月30日下午6:13:29
     */
    public interface RoleDAO extends GenericDAO<Role, Long>
    {
        /**
         * 按照角色名称查找其对应的用户列表
         * 
         * @param roleNmae 角色名称
         * @return 用户列表 List<User>
         * @throws DatabaseException 异常
         */
        List<User> findByRoleName(String roleName) throws DatabaseException;
    }
    /**
     * 各个DAO的通用模板接口。
     * <p>
     * 增删改查(create, read, update, delete)这几种基本数据访问操作放在这个接口中。
     * <p>
     * @author wanganqi
     * @version v1.0
     * 
     * @since 2012年12月1日下午2:49:50
     * @param <T> 模板类型
     * @param <ID> 主键
     */
     
    public interface GenericDAO<T, ID extends Serializable>
    {
        /**
         * 添加
         * 
         * @param entity 实体类
         * @return 实体类
         */
        T saveOrUpdate(T entity);
     
        /**
         * 根据给定的id,以lock规定的锁模式,查找并返回对应的实体对象。
         * 
         * @param id 主键
         * @param lock 是否加锁
         * @return T 查找到的对象
         */
        T findById(ID id, boolean lock);
     
        /**
         * 按条件查找
         * 
         * @param criterion 条件
         * @return 实体对象列表
         */
        List<T> findByCriteria(Criterion... criterion);
     
        /**
         * 返回T类型的所有对象。
         * 
         * @return List<T> T对象的列表
         */
        List<T> findAll();
     
        /**
         * 查询
         * 
         * @param exampleInstance 条件
         * @param excludeProperty 条件
         * @return 实体对象列表
         */
        List<T> findByExample(T exampleInstance, String... excludeProperty);
     
        /**
         * 将实体entity持久化。(添加或更新)
         * 
         * @param entity 需持久化的实体
         * @return 持久化对象
         */
        T makePersistent(T entity);
     
        /**
         * 将持久化实体entity从数据库中删除。
         * 
         * @param entity 需删除的实体。
         */
        void makeTransient(T entity);
     
        /**
         * 根据ID删除实体
         * 
         * @param id ID
         */
        void delete(ID id);
     
        /**
         * 同步对象在内存与数据库中的状态。
         */
        void flush();
     
        /**
         * 彻底清理当前session。
         */
        void clear();
     
        /**
         * 统一抛出数据库操作异常
         * 
         * @param e 异常
         * @throws DatabaseException 数据库异常
         */
        void throwDatabaseException(Exception e) throws DatabaseException;
     
        /**
         * 执行数据表结构更新
         * 
         * @return 是否更新成功
         * @throws DatabaseException 数据库异常
         */
        boolean excuteUpdateShema() throws DatabaseException;
    }
     
    在DAO层还需要实现RoleDAO接口,在这里只有一个实现,其它的功劳都要记在GenericDAOImpl身上。GenericDAOImpl是对GenericDAO的具体实现,GenericDAOImpl是各个DAOImpl的通用模板,它包含了各基本数据访问操作,如增删改查CRUD,其它DAOImpl通过继承GenericDAOImpl来获得CRUD的功能。注意,我们使用Spring实例化、注入各个DAOImpl和SessionFactory,由于Hessian支持Spring方式发布,故Spring配置文件这里放在Hessian层,当然也可以放在BLL层,放在BLL层需要自己控制Spring上下文。
    /**
     * DAO层接口实现-角色访问
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2013年7月30日下午6:18:41
     */
    @Repository("RoleDAOImpl")
    public class RoleDAOImpl extends GenericDAOImpl<Role, Long> implements RoleDAO
    {
        @SuppressWarnings("unchecked")
        @Override
        public List<User> findByRoleName(String roleName) throws DatabaseException
        {
            return getSession().createCriteria(User.class)
                .add(Restrictions.eq("roleName"roleName)).list();
        }
    }
    /**
     * You have to inject a current Hibernate <tt>Session</tt> to use a DAO.
     * Otherwise, this generic implementation will use
     * <tt>HibernateUtil.getSessionFactory()</tt> to obtain the curren
     * <tt>Session</tt>.
     
     * @author wanganqi
     * @version v1.0
     * @since 2012年8月1日下午2:46:08
     * @param <T> 模板类
     * @param <ID> 模板ID
     * 
     */
    public abstract class GenericDAOImpl<T, ID extends Serializable> implements GenericDAO<T, ID>
    {
        private Class<T> m_persistentClass;
     
        @Autowired
        private SessionFactory m_sessionFactory;
     
        @Autowired
        private LocalSessionFactoryBean m_sessionFactoryBean;
     
        /**
         * 构造函数
         * 
         */
     
        @SuppressWarnings("unchecked")
        public GenericDAOImpl()
        {
     
            // 运用反射机制,获取当前具体的类的类型。
            this.m_persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        }
     
        /**
         * 获取sessionFactory
         * 
         * @return SessionFactory
         */
        public SessionFactory getSessionFactory()
        {
            return m_sessionFactory;
        }
     
        protected Session getSession()
        {
            return m_sessionFactory.getCurrentSession();
        }
     
        /**
         * 获取模板类
         * 
         * @return 模板类
         */
        public Class<T> getPersistentClass()
        {
            return m_persistentClass;
        }
        @SuppressWarnings("unchecked")
        @Override
        public T findById(ID id, boolean lock)
        {
            T entity;
            if (lock)
            {
                entity = (T) getSession().get(getPersistentClass(), id, LockOptions.UPGRADE);
            }
            else
            {
                entity = (T) getSession().get(getPersistentClass(), id);
            }
            return entity;
        }
        @Override
        public List<T> findAll()
        {
            List<T> result = findByCriteria();
            return result;
        }
        @SuppressWarnings("unchecked")
        @Override
        public List<T> findByExample(T exampleInstance, String... excludeProperty)
        {
            Criteria crit = getSession().createCriteria(getPersistentClass());
            Example example = Example.create(exampleInstance);
            for (String exclude : excludeProperty)
            {
                example.excludeProperty(exclude);
            }
            crit.add(example);
            return crit.list();
        }
        @SuppressWarnings("unchecked")
        @Override
        public T makePersistent(T entity)
        {
            return (T) getSession().merge(entity);
     
        }
        @Override
        public void makeTransient(T entity)
        {
     
            getSession().delete(entity);
     
        }
     
        @SuppressWarnings("unchecked")
        @Override
        public void delete(ID id)
        {
            T entity = (T) getSession().get(getPersistentClass(), id);
            if (entity != null)
            {
                getSession().delete(entity);
            }
        }
        @Override
        public void flush()
        {
            getSession().flush();
        }
     
        @Override
        public void clear()
        {
            getSession().clear();
        }
     
        @SuppressWarnings("unchecked")
        @Override
        public List<T> findByCriteria(Criterion... criterion)
        {
            Criteria crit = getSession().createCriteria(getPersistentClass());
     
            for (Criterion c : criterion)
            {
                crit.add(c);
            }
            crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
            return crit.list();
        }
        @SuppressWarnings("unchecked")
        protected T queryForObject(String hql, Object[] params)
        {
            Query query = getSession().createQuery(hql);
            setQueryParams(query, params);
            return (T) query.uniqueResult();
        }
     
        private void setQueryParams(Query query, Object[] params)
        {
            if (null == params)
            {
                return;
            }
            for (int i = 0; i < params.length; i++)
            {
                query.setParameter(i, params[i]);
            }
        }
     
        @Override
        public T saveOrUpdate(T entity)
        {
            getSession().saveOrUpdate(entity);
            return entity;
        }
     
        @Override
        public void throwDatabaseException(Exception e) throws DatabaseException
        {
            DatabaseException de = new DatabaseException(new ErrMsg("数据库操作异常", (e.getCause() != null ? e.getCause().getMessage()
                : e.getMessage())));
            throw de;
        }
     
        private FilenameFilter filter(final String extension)
        {
            return new FilenameFilter()
            {
                @Override
                public boolean accept(File file, String path)
                {
                    String filename = new File(path).getName();
                    return filename.indexOf(extension) != -1;
                }
            };
        }
     
        @Override
        public boolean excuteUpdateShema() throws DatabaseException
        {
            try
            {
                org.hibernate.cfg.Configuration config = new Configuration();
                config.configure("classpath:hibernate.cfg.xml");
     
                String path = URLDecoder.decode(this.getClass().getClassLoader().getResource("").getPath(), "utf-8");
                path += "resource/";
                File hbmDir = new File(path);
                if (hbmDir.exists())
                {
                    List<File> fList = Arrays.asList(hbmDir.listFiles(filter(".hbm.xml")));
                    if (null != fList && fList.size() > 0)
                    {
                        for (File f : fList)
                        {
                            config.addResource("resource/" + f.getName());
                        }
                    }
                }
                new SchemaUpdate(config).execute(truetrue);
            }
            catch (Exception e)
            {
                throwDatabaseException(e);
            }
            return true;
        }
    }
    三、BLL层
    BLL层便是可以发布成Hessian服务的代码,它也需要定义接口以及实现,下面是RoleBLL接口,独自拥有的方法只有一个,就是列出指定角色下面的所有用户。通用的方法以模版的方式定义在GenericBLL中。
    /**
     * 逻辑层BLL接口-角色
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2013年7月30日下午6:19:38
     */
    public interface RoleBLL extends GenericBLL<Role, Long>
    {
        /**
         * 列出指定角色下面的所有用户
         * 
         * @param role 角色名称
         * @return 用户列表 List<User>
         * @throws DatabaseException DAO层异常
         * @throws BusinessException 逻辑层异常
         */
        List<User> listUsers(String roleName) throws DatabaseException,
            BusinessException;    
    }
     
    /**
     * 各个BLL的通用模板
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2012年8月8日上午9:33:41
     * @param <T>
     * @param <ID>
     */
    public interface GenericBLL<T, ID extends Serializable>
    {
        List<T> findALL();
     
        T findById(ID id);
     
        T addT(T t);
     
        T editT(T t);
     
        boolean deleteT(T t);
     
        boolean deleteById(ID id);
    }
     
    RoleBLL接口的实现,GenericBLL接口的实现如下所示。GenericBLLImpl帮助我们完成了七八成的功能,感谢GenericBLLImpl。要注意的是,事务是在这一层统一配置的,在下面的代码里给每一个业务逻辑都配置了事务,在类头以Transactional标签设置,只有当异常抛出时,回滚。同样使用Spring标签,将RolDAOImp对象和GenericBLLImpl对象注入进来。
    /**
     * 逻辑BLL层-角色处理
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2013年7月30日下午6:36:10
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    @Component("RoleBLLImpl")
    public class RoleBLLImpl extends GenericBLLImpl<Role, Long> implements RoleBLL
    {
        @Autowired
        @Qualifier("RoleDAOImpl")
        private RoleDAO          m_roleDAO;
        /**
         * 注入
         */
        @PostConstruct
        public void postConstruct()
        {
            super.setGenericDAO(m_roleDAO);
        }
        @Override
        public List<User> listRoleUsers(Role role) throws DatabaseException, BusinessException
        {
            List<User> users = m_roleDAO.findByRoleId(role.getId());
            return users;
        }
    }
     
    /**
     * 各个BLLImpl的通用模板
     * 
     * @author wanganqi
     * @version v1.0
     * @since 2012年8月8日下午2:20:29
     * @param <T>
     * @param <ID>
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public abstract class GenericBLLImpl<T, ID extends Serializable> implements
        GenericBLL<T, ID>
    {
        private GenericDAO<T, ID> genericDAO;
     
        public void setGenericDAO(GenericDAO<T, ID> genericDAO)
        {
            this.genericDAO = genericDAO;
        }
     
        public GenericBLLImpl(GenericDAO<T, ID> gd)
        {
            genericDAO = gd;
        }
     
        public GenericBLLImpl()
        {
        }
        public List<T> findALL()
        {
            List<T> retList = genericDAO.findAll();
            return retList;
        }
     
        public T findById(ID id)
        {
            T retT = genericDAO.findById(id, false);
            return retT;
        }
     
        public T addT(T t)
        {
            T rt = genericDAO.makePersistent(t);
            return rt;
        }
     
        public T saveOrUpdate(T entity)
        {
            T resultT = addT(entity);
            return resultT;
        }
     
        public T editT(T t)
        {
     
            return addT(t);
        }
     
        public boolean deleteT(T t)
        {
            if (null == t)
            {
                return true;
            }
            genericDAO.makeTransient(t);
            return true;
        }
     
        public boolean deleteById(ID id)
        {
            return deleteT(findById(id));
        }
    }
     
    四、发布成Hessian服务
     
    由于使用了Spring框架,我们需要Spring相关的配置。下面是基本的Spring配置,可以配置在Hessian服务层,也可以配置在DAL代码层,由代码维护Spring上下文。
    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:p="http://www.springframework.org/schema/p" 
        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-3.2.xsd 
                            http://www.springframework.org/schema/context  
                            http://www.springframework.org/schema/context/spring-context-3.2.xsd  
                            http://www.springframework.org/schema/tx  
                            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd  
                            http://cxf.apache.org/jaxws   
                            http://cxf.apache.org/schemas/jaxws.xsd">            
        <bean id="sessionFactory"
            class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
            p:configLocation="/WEB-INF/hibernate.cfg.xml">
        </bean>
     
        <bean id="transactionManager"
            class="org.springframework.orm.hibernate4.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory" />
        </bean>
        <tx:annotation-driven transaction-manager="transactionManager" />    
        <context:component-scan base-package="com.wang.anqi.model" />
        <context:component-scan base-package="com.wang.anqi.dao.impl" />      
        <!-- 发布bean -->      
        <bean id="roleBLLImpl" class="com.wang.anqi.dataBll.impl.RoleBLLImpl" />       
        <!-- 发布bean --> 
    </beans>  
     
    我们还需要hibernate.cfg.xml文件,这在“Model们”就已经说明了。如何发布成Hessian服务,发布Hessian服务需要注意些什么问题,如何调用Hessian服务,网上也有很多,我也会在以后的文章中总结出来,希望大家还能继续关注。
    上面的代码虽然稍多了,有堆代码的嫌疑,但毕竟这是必需的,要不然解释不清。 





  • 相关阅读:
    node.js中的全局变量——global
    Element-UI库 源码架构浅析
    如何搭建一个自己cli
    webpack实践之DLLPlugin 和 DLLReferencePlugin
    HappyPack优化
    线程和进程
    kafka?kafaka! kafka...
    Dubbo的初步理解和使用
    Redis的安装和启动
    解析Spring MVC上传文件
  • 原文地址:https://www.cnblogs.com/wgp13x/p/3900096.html
Copyright © 2020-2023  润新知