摘要:项目中对关系型数据库的接入再寻常不过,也有海量的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(true, true);
        }
        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服务,网上也有很多,我也会在以后的文章中总结出来,希望大家还能继续关注。
上面的代码虽然稍多了,有堆代码的嫌疑,但毕竟这是必需的,要不然解释不清。 

关于项目中的DAL数据接入层架构设计的更多相关文章

  1. 一个项目中说系统分为表现层、控制层、逻辑层、DAO层和最终数据库五层架构-转

    表现层就是看到的东西,比如你现在看到的当前页面控制层就将你的请求从页面传到后台代码逻辑层就是处理你的请求的代码DAO层就是将数据存到数据库中的代码数据库就是数据库了,存东西用的 ,DAO层就是将访问数 ...

  2. 加载的DAL数据访问层的类型

    using System; using System.Collections; using System.Reflection; using CSFrameworkV4_5.Core; using C ...

  3. 在项目中部署redis的读写分离架构(包含节点间认证口令)

    #### 在项目中部署redis的读写分离架构(包含节点间认证口令) ##### 1.配置过程 ---  1.此前就是已经将redis在系统中已经安装好了,redis utils目录下,有个redis ...

  4. 1.1 DAL数据访问层

    分布式(Distributed)数据访问层(Data Access Layer),简称DAL,是利用MySQL Proxy.Memcached.集群等技术优点而构建的一个架构系统.主要目的是解决高并发 ...

  5. vue-cli项目中怎么mock数据

    在vue项目中, mock数据可以使用 node 的 express模块搭建服务 1. 在根目录下创建 test 目录, 用来存放模拟的 json 数据, 在 test 目录下创建模拟的数据 data ...

  6. docker 使用mysqldump命令备份导出项目中的mysql数据

    下图为镜像重命名后的镜像名为uoj,现在要把这个镜像中的mysql导出 运行如下命令: docker exec -it uoj mysqldump -uroot -proot app_uoj233 & ...

  7. 三:基于Storm的实时处理大数据的平台架构设计

    一:元数据管理器==>元数据管理器是系统平台的“大脑”,在任务调度中有着重要的作用[1]什么是元数据?--->中介数据,用于描述数据属性的数据.--->具体类型:描述数据结构,数据的 ...

  8. 微软&中科大提出新型自动神经架构设计方法NAO

    近期,来自微软和中国科学技术大学的刘铁岩等人发表论文,介绍了一种新型自动神经架构设计方法 NAO,该方法由三个部分组成:编码器.预测器和解码器.实验证明,该方法所发现的架构在 CIFAR-10 上的图 ...

  9. 夺命雷公狗---node.js---20之项目的构建在node+express+mongo的博客项目5mongodb在项目中实现添加数据

    我们上一步就引入了mongodb了,那么下一步就要开始写添加数据了,不过有个前提是先将表单的数据处理好: 最基本的这部现在已经成功了,因为最基本的这步就是先将表单处的提交方式和提交地址给处理好,这里和 ...

随机推荐

  1. GIT 恢复单个文件到历史版本

    首先查看该文件的历史版本信息:git log <file> 恢复该文件到某个历史版本:git reset 版本号 <file> 检出改文件到工作区:git checkout - ...

  2. Linux中让普通用户拥有超级用户的权限

    问题 假设用户名为:ali 如果用户名没有超级用户权限,当输入 sudo + 命令 时, 系统提示: ali is not in the sudoers file.  This incident wi ...

  3. badboy详解篇

    上一篇学习了jmeter录制的两种方法,badboy是比较好用的一个,它本身就是个测试工具,今天具体来介绍一下: 1.检查点 检查点就是记录被测系统某个值的预期结果 以百度搜索gogomall为例子 ...

  4. Java入门系列-14-深入类和对象

    这篇文章用大量的代码帮你搞懂:值传递和引用传递.构造方法.方法重载.static关键字的使用 方法参数传递-值传递和引用传递 1.值传递 敲一敲: /** * 使用方法交换两个变量的值 * @auth ...

  5. [javaEE] EL表达式获取数据

    jsp标签: <jsp:include> <jsp:forward> 实现请求转发 <jsp:param> 给上面的添加参数的 EL表达式: 1.获取变量数据 &l ...

  6. javaweb之jsp标签

    1.JSP标签简介 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 2.JSP常用标签 ...

  7. Java并发—–深入分析synchronized的实现原理

    记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized,相对于当时的我们来说synchronized是这么的神奇而又强大,那个时候我们赋予它一个名字“同步”,也成为了我们解决多线 ...

  8. jquery获取下拉框中的循环值

    <select class="test" id="projectno" name="projectno"> <option ...

  9. 第11章 Media Queries 与Responsive 设计

    Media Queries--媒体类型(一) 随着科学技术不断的向前发展,网页的浏览终端越来越多样化,用户可以通过:宽屏电视.台式电脑.笔记本电脑.平板电脑和智能手机来访问你的网站.尽管你无法保证一个 ...

  10. cookie实现记住登录名和密码

    在最近学习的session作用域中,顺便了解了一下cookie, session是存放在服务器中,而cookie是存放在客户端中. 本篇文章主要是使用cookie来实现记住密码的功能. 简单的logi ...