hibernate作为一款优秀的数据库持久化框架,在现实的运用中是非常广泛的。它的出现让不熟悉sql语法的程序员能开发数据库连接层成为一种可能,但是理想与现实永远是有差距的。开发过程中如果只使用hql进行操作,并且表之间的关联配置很复杂的话,这将成为一种噩梦。还好我们伟大的hibernate支持原生的sql操作,这也大大的增加了hibernate的灵活性。下面我们探讨一下hibernate的dao层的通用设计。

首先阐明一下显示情况中遇到的问题。假设数据库中有一张表,表名叫tbl_user,项目中对应的实体User,根据MVC的分层设计,我们会有UerDao的接口层,以及UserDaoImpl的接口实现层。对数据库最多的操作就是增删改查,我们的UserDao和UserDaoImpl中会有增删改查的方法。如果有多张表的时候,我们会发现Dao的接口层以及实现层充斥着大量的增删改查的代码,而且大部分情况这些代码都是类似的,那我们能不能将这些代码进行封装呢?答案是肯定的。

下面进入正题,数据库使用mysql,创建一张名为tbl_user的表。

  1. CREATE TABLE `tbl_user` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `name` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
  4. `login_name` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
  5. `pass_word` char(32) COLLATE utf8_unicode_ci DEFAULT NULL,
  6. `role_id` bigint(20) DEFAULT NULL,
  7. `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  8. `last_login_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  9. `del_flag` enum('0','1') COLLATE utf8_unicode_ci DEFAULT '0',
  10. PRIMARY KEY (`id`)
  11. ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户表';

然后我们创建一个实体User对应这张表。

@Entity
@Table(name = "tbl_user")
public class User extends IdEntity implements Serializable {
private static final long serialVersionUID = 1L;

// 创建时间
private Date createTime;

// 删除标记
private String delFlag;

// 最后登录时间
private Date lastLoginTime;

// 登录名
private String loginName;

// 姓名
private String name;

// 密码
private String passWord;

// 角色id
private Long roleId;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "create_time")
public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

@Column(name = "del_flag")
public String getDelFlag() {
return delFlag;
}

public void setDelFlag(String delFlag) {
this.delFlag = delFlag;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "last_login_time")
public Date getLastLoginTime() {
return lastLoginTime;
}

public void setLastLoginTime(Date lastLoginTime) {
this.lastLoginTime = lastLoginTime;
}

@Column(name = "login_name")
public String getLoginName() {
return loginName;
}

public void setLoginName(String loginName) {
this.loginName = loginName;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@Column(name = "pass_word")
public String getPassWord() {
return passWord;
}

public void setPassWord(String passWord) {
this.passWord = passWord;
}

@Column(name = "role_id")
public Long getRoleId() {
return roleId;
}

public void setRoleId(Long roleId) {
this.roleId = roleId;
}

}

好了,下一步我们要进行要进行dao层代码的编写。但是现在不能写,我们的解决方案还没有理出来。首先我们可以肯定的是常规的CRUD代码不能写在UserDao和UserDaoImpl中了,那写在哪里呢。遇到这种情况首先想到的就是继承,如果有一个父类具有这种能力的话,再去继承这个父类,问题就迎刃而解了。好,方案确定,动手操作吧。我们先创建一个接口,命名为BaseDao,这里用到了接口泛型的概念。

  1. public interface BaseDao<T> {
  2.  
  3. /*
  4. * 持久化对象的方法
  5. */
  6. public long add(T t);
  7.  
  8. /*
  9. * 修改对象
  10. */
  11. public void update(T t);
  12.  
  13. /*
  14. * 删除对象
  15. */
  16. public int delete(long id);
  17.  
  18. /*
  19. * 查找所有对象的方法
  20. */
  21. public List<T> getAll();
  22.  
  23. /*
  24. * 根据id查找对象
  25. */
  26. public T getById(long id);
  27.  
  28. /*
  29. * 根据map条件查找对象
  30. */
  31. public List<T> getByMap(Map<String,Object> map);
  32.  
  33. /*
  34. * 查询条数
  35. */
  36. public int countBySql(String sql);
  37.  
  38. /*
  39. * 执行hql语句
  40. */
  41. public int executeHql(String hql);
  42.  
  43. /*
  44. * 执行sql语句
  45. */
  46. public int executeSql(String sql);
  47.  
  48. /*
  49. *根据sql语句查询map集合
  50. */
  51. public List<Map<String,Object>> getMapListBySql(String sql);
  52. }

上面的顶层接口BaseDao定义了一些常用的dao层操作。我们在接口层再定义一个实体User对应的dao接口UserDao。

  1. public interface UserDao extends BaseDao<User> {
  2.  
  3. }

接口UserDao中什么方法都没有定义,只是去继承了BaseDao。接下来我们要编写dao实现层的代码了,首先我们编写dao实现层整个父类的BaseDaoImpl的代码,这个时候我们停一下整理一下思路。父类BaseDaoImpl要具有CRUD的操作,并且要是动态的,就是不同的操作要相应的操作不同的表,在hibernate中我们也可以说是操作不同的实体。如何实现这种想法呢?答案还是泛型,在继承父类BaseDaoImpl的时候注入自己的真实类型。下面就是BaseDaoImpl的代码, 这也是最核心的地方。

  1. public class BaseDaoImpl<T> implements BaseDao<T>{
  2.  
  3. @Autowired
  4. private SessionFactory sessionFactory;
  5.  
  6. protected Class<T> clazz;
  7.  
  8. /**
  9. * 构造方法自动注入真实的对象类型
  10. */
  11. public BaseDaoImpl() {
  12. ParameterizedType type = (ParameterizedType) this.getClass().getGenericSuperclass();
  13. clazz = (Class<T>) type.getActualTypeArguments()[0];
  14. }
  15.  
  16. public Session getCurrentSession() {
  17. return this.sessionFactory.getCurrentSession();
  18. }
  19.  
  20. @Override
  21. public long add(T t){
  22. if (t!=null) {
  23. return (Long) this.getCurrentSession().save(t);
  24. }
  25. return 0;
  26. }
  27.  
  28. @Override
  29. public void update(T t){
  30. if (t!=null) {
  31. this.getCurrentSession().update(t);
  32. }
  33. }
  34.  
  35. @Override
  36. public int delete(long id){
  37. String hql = "delete "+clazz.getSimpleName()+" where id="+id;
  38. return this.getCurrentSession().createQuery(hql).executeUpdate();
  39. }
  40.  
  41. @Override
  42. public List<T> getAll(){
  43. String hql = "from "+clazz.getSimpleName();
  44. return this.getCurrentSession().createQuery(hql).list();
  45. }
  46.  
  47. @Override
  48. public T getById(long id){
  49. String hql = "from "+clazz.getSimpleName()+" where id="+id;
  50. return (T) this.getCurrentSession().createQuery(hql).uniqueResult();
  51. }
  52.  
  53. @Override
  54. public List<T> getByMap(Map<String,Object> map){
  55. Set<String> set = map.keySet();
  56. if (set.size()>0) {
  57. List<String> list = new ArrayList<String>();
  58. for (String string : set) {
  59. list.add(string);
  60. }
  61. String hql = "from "+clazz.getSimpleName()+" where ";
  62. for(int i=0;i<=list.size()-1;i++){
  63. if (i==0) {
  64. hql += list.get(i)+"='"+map.get(list.get(i))+"'";
  65. }
  66. else{
  67. hql += " and "+list.get(i)+"='"+map.get(list.get(i))+"'";
  68. }
  69. }
  70. return this.getCurrentSession().createQuery(hql).list();
  71. }
  72. return null;
  73. }
  74.  
  75. @Override
  76. public int countBySql(String sql){
  77. SQLQuery q = this.getCurrentSession().createSQLQuery(sql);
  78. return ((BigInteger) q.uniqueResult()).intValue();
  79. }
  80. @Override
  81. public int executeHql(String hql){
  82. Query q = this.getCurrentSession().createQuery(hql);
  83. return q.executeUpdate();
  84. }
  85.  
  86. @Override
  87. public int executeSql(String sql){
  88. SQLQuery q = this.getCurrentSession().createSQLQuery(sql);
  89. return q.executeUpdate();
  90. }
  91.  
  92. @Override
  93. public List<Map<String, Object>> getMapListBySql(String sql) {
  94. SQLQuery query = this.getCurrentSession().createSQLQuery(sql);
  95. query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
  96. return(List<Map<String, Object>>) query.list();
  97. }
  98.  
  99. }

BaseDao中的方法上已经写了注释,所以下面的实现类我就偷懒没有写注释了。我们重点研究其中一个方法

我们在BaseDaoImpl中定义了一个全局变量clazz,利用BaseDaoImpl的构造方法将通过泛型传进来的真是类型的Class传到此变量中。此时,在这里可能会产生一个疑问,如果使用了spring,所有的bean管理都是由spring来完成的话,此处的构造方法会得到调用吗?答案是肯定的,spring创建bean的时候也是通过调用构造方法创建bean实例的。得到此class后我们就可以利用反射机制得到实体的真实名称进行hql的拼接。好了,我们可以去实现UserDao这个接口了。

  1. @Repository
  2. public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao {
  3.  
  4. }

我们只要在实现UserDao接口的同时同时继承BaseDaoImpl这个父类,把实体的真实类型传进去就行了。虽然UserDaoImpl中一个方法都没有,实际上它已经具有父类中的所有方法了。BaseDao代码中只是示例了几个常用的方法,现实中可以进行扩充,比如分页的方法之类的,在BaseDaoImpl去实现就可以了。如果UserDaoImpl需要的方法在父类中没有,并且方法具有特殊性的话,可以在UserDao定义此方法,在UserDaoImpl中去实现就可以了。其他实体所对应的Dao层操作也是一样。

————————————————
版权声明:本文为CSDN博主「小哥被占用了」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_26800725/article/details/52032537

Hibernate的Dao层通用设计的更多相关文章

  1. DAO层基础设计原理

    在实际的开发中有一种项目的程序组织架构方案叫做MVC模式,按照程序 的功能将他们分成三个层,如下图 Modle层(模型层).View层(显示层).Controller层(控制层). Modle层:可以 ...

  2. Java SE 之 DAO层接口设计思想

    用图说话 好处 1.只需要定义好IBaseDao的接口方法,并只需要实现BaseDaoImpl的方法,而具体的业务类和业务类/接口的方法的基本方法(IBaseDao已定义的)并不需要再考虑实现. 2. ...

  3. SSH框架整合中Hibernate实现Dao层常用结构

    一.疑惑 一直以来,我在使用SSH框架的时候经常会发现后者有疑虑到底使用hibernate的那种方法或者如何配置hibernate来操作数据库,经过 一段时间的学习下面我来总结一下,常用的dao层配置 ...

  4. SpringMVC + Hibernate + MySQL 的简易网页搭建(Dao层 实现篇)

    首先在搭建一个网站后台前,需要明确出一个合理的网页搭建的结构框架,即从DB  ==>  Dao层 ==>Service层 ==>Control层 ==>View层(该层严格意义 ...

  5. DAO层设计Junit测试

    DAO层的设计: 在实际的开发中有一种项目的程序组织架构方案叫做MVC模式. MVC模式就是按照程序的功能将它们分成三层,分别是Modle层 (模型层).View(显示层).Controller(控制 ...

  6. hibernate+pageBean实现分页dao层功能代码

    今天闲来无事,摆弄了一下分页,突然发现很多代码长时间不用就生梳了,虽然有些基础,但没有一篇整合的.这里还是简单示例,主要是以后自己翻着看不用百度找啊找找不到一篇想要的 1.PageBean实体类,一页 ...

  7. [原创]java WEB学习笔记21:MVC案例完整实践(part 2)---DAO层设计

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. 分层 DAO层,Service层,Controller层、View层

    前部分摘录自:http://blog.csdn.net/zdwzzu2006/article/details/6053006 DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务 ...

  9. DAO层,Service层,Controller层、View层 的分工合作

    DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可在模块中调用此接口 ...

随机推荐

  1. SASS CSS3 koala

    CSS with superpowers Sass: Syntactically Awesome Style Sheets http://sass-lang.com/ Sass is the most ...

  2. Object & prototype & __proto__ All In One

    Object & prototype & proto All In One js 原型,原型链,原型对象 const obj ={}; // {} const obj = new Ob ...

  3. Koa & WebSocket inAction

    Koa & WebSocket inAction node.js https://koajs.com/ ping / pong socket.io client send 2 as ping ...

  4. CSS clip-path in action

    CSS clip-path in action <!DOCTYPE html> <html lang="en"> <head> <meta ...

  5. React Hooks 实现一个计时器组件

    React Hooks 实现一个计时器组件 useEffect https://reactjs.org/docs/hooks-reference.html#useeffect import React ...

  6. React Hooks & React v16.8.6

    React Hooks Hooks are a new addition in React 16.8 const [state, setState] = useState(initialState); ...

  7. taro 禁用滚动事件

    taro 禁用滚动事件 禁止 Modal 蒙层下面的页面的内容跟随滚动 https://github.com/NervJS/taro/issues/3980 https://github.com/Ne ...

  8. Java开发的得力助手---Guava

    导语 guava是google出品的java类库,被google广泛用于内部项目,该类库经过google大牛们的千锤百炼,以优雅的设计在java世界流行.版本迭代至今,很多思想甚至被JDK标准库借鉴, ...

  9. 新手不能忽视的MFC编程之CString

    首发文章 | 公众号:lunvey 作为一个新手,刚接触C++没多久.赶鸭子上架完成项目,鉴于之前有几年编程基础,所以很快就接触到了界面开发,由于用的是VC++6.0,所以自然而然就将MFC作为图形界 ...

  10. net里面using的使用

    起初using就明白一个作用  那就是引用命名空间.当面试官听到我回答这个问题的时候,马上就还问我,还有什么作用?我就只能摇头了,今天在网上看了下using的作用. 1.using指令.using + ...