前言

在开发过程中,我们不难发现,客户的需求以及产品的定位对开发内容的走向有很大的决策作用,而这些往往需要在一开始就尽可能考虑周全和设计完善。为什么说是尽可能,因为我们都知道,需求这种东西,一言难尽...作为开发者,既然无法掌控需求的变更等因素,那我们就要把握好自身能决定的工具资源等,架构设计、技术选型等等。有的人可能会说,我才多久经验之类,架构什么的不都是leader们大佬们的事情么,选什么数据库用什么技术又不是我能决定的。如果你有这种想法,我只能觉得你说得很对。不知道大家在开发过程中,有没有遇到,某个场景或者效果用现有的工具技术你觉得无法实现或者很难实现,又或者你知道又可以实现的技术框架却不会用?echarts、POI等,对于我来说,都符合上述场景。总的来说,有的东西在开发过程中可以当作学习,有些东西却需要你额外花时间在工作之外去研究。当然,如果你说你工作中不管需要什么新技术,你一天之类就可以掌握,那也是能力。而且这不是嘲讽什么的,是实实在在的,我现在愈发觉得学习能力的重要性,他对一个人的潜在能力增长曲线的影响太大,当然你有能力却不学习,那也注定是一条直线射穿。Spring、Strus 2、Hibernate、Mybatis、Spring MVC是比较常见的Web项目会用到的框架,持久层目前来看主要有Hibernate、Mybatis、Spring data jpa等,目前我在用Spring data jpa,这个东西真的厉害,用起来比我以前的想法又上了一个台阶,而且跟hibernate支持的也很好,Hibernate本身也是jpa规范的实现。接下来文中项目中类与方法设计的思路是之前基于Hibernate的,正好回顾一下,认识下其中的不足,好结合现在用的Jpa改进。

  项目结构一览

以web项目技术框架选型为Spring+Hibernate+Spring MVC为例,忽略配置以及web前端文件,后台结果最精简情况大致如下:

从数据库方向依次向前介绍:

1.domain层,这个东西的标准解释是领域模型,我们orm对象关系映射的实体类一般就放在该层下,即实体层,类似的叫法,entity、model、pojo等作用大抵如此;

2.repository层,数据库访问层,这个就是dao层,存放数据库访问操作的方法;

3.service层,业务逻辑层,用于存放业务逻辑方法的地方,与dao层相比,有的人可能开始会觉得这个service层没有什么必要,或者不太清楚两者的区别。首先关于两者区别:业务逻辑层,故名思意,他的重要定位是业务,业务需求什么,他就要提供什么,举个例子,dao层提供了你删除商品的方法和添加日志的方法,这两个方法分别对应有两个实体对象商品和日志,操作的也是数据库相应的单个表,但是实际情况是你通过单个方法总感觉哪里不对劲,业务场景下,如果需要你删除东西后会有相应的日志记录,而日志又不会凭空捏造,需要有事件对应。这时候,service层的作用就体现出来了,简单的可以这么理解,复杂的数据库处理你靠单个dao方法无法实现的时候,你在service层去构造这个方法就行,通过SpringIOC特性,在service层注入你需要的调用的dao方法所在的类或者接口,实际场景一般都是接口。其次关于必要性,我曾经也想过,直接在controller里面注入多个dao类或者接口不是也能达到想要的效果吗?Controller顾名思义,控制器,它在web结果中,主要起到一个接受和转发请求并控制的作用,当你的业务逻辑相对简单的时候,你觉得看不出多大区别,当实际项目业务逻辑相对复杂很多的情况下,这个controller就有点炸了,像个身兼多职操劳过度的苦工,另外结合上一个疑惑,还有一个很重要的概念就是事务,而Spring的事务管理做得也很到位,通过编程式事务管理或者声明式事务管理都可以实现,而事务一般就设置在业务逻辑也就是service层上,关于事务也是很重要和精髓的一块,需要学习也值得学习。

4.controller层,控制层,用struts 2也许会叫action层吧,或者通用点,叫web层其实也可以。他可以接收不同的请求url,调用相应的service层代码,操作数据库,跳转到制定页面,也可以不跳转,直接返回数据,这里的数据目前用json的比较多,典型的应用场景:ajax发起异步请求,DispatcherServlet捕获请求后对url进行解析,分发到相应的控制类中的相应方法中执行其中代码,该方法上加上@ResponseBody即可。

  关于Hibernate在项目中的定位

Hibernate是一个典型的ORM持久层框架,ORM即Object Relational Mapping(对象关系映射),即实体类与数据库表之间的关系映射,通俗的讲,一张表对应一个实体类,一条记录对应一个实体类对象,字段对应实体类属性。对数据库的操作在Hibernate中有一个重要对象session,通过session封装一系列数据库操作方法在数据库访问层,所以在上面的结构中,Hibernate主要操作和作用的有domain层和repository层,下面示例也省略其他层代码。

  示例

domain层,这里简单使用,Mysql数据库主键也用的int自增型,实际应用数据量较大等情况下会用varchar,保存使用UUID赋值主键。

 @Entity
@Table(name="TBL_USER")
public class User {
private Integer id;
private String username;
private String password;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
} }

repository层

BaseDao泛型接口

public interface BaseDao<T> {
public void edit(Object obj); //添加或者更新一条记录
public void delete(int id); //根据主键删除一条记录
public T load(int id); //根据主键查找一条记录(懒加载)
public T get(int id); //根据主键查找一条记录(非懒加载)
}

BaseDao泛型实现类

public class BaseDaoImpl<T> implements BaseDao<T> {
@Resource
private SessionFactory factory;
private Class<T> clazz = GeneriscUtil.getGenericType(this.getClass()); protected Session getSession() {
return factory.getCurrentSession();
} public void edit(Object obj) {
getSession().saveOrUpdate(obj);
} public void delete(int id) {
Object object = getSession().get(clazz, id);
if(object != null) {
getSession().delete(object);
}
} public T load(int id) {
return (T) getSession().load(clazz, id);
} public T get(int id) {
return (T) getSession().get(clazz, id);
} }

泛型工具类

public class GeneriscUtil {
@SuppressWarnings("rawtypes")
public static Class getGenericType(Class clazz){
Type genType = clazz.getGenericSuperclass();//获取泛型父类
Type[] types = ((ParameterizedType) genType).getActualTypeArguments();
if (!(types[0] instanceof Class)) {
return Object.class;
}
return (Class) types[0];
}
}

最后:UserDao接口和UserDaoImpl实现类

public interface UserDao extends BaseDao<User> {
User login(String username, String password);
}
@Repository("UserDao")
public class UserDaoImpl extends BaseDaoImpl<User> implements UserDao { public User login(String username, String password) {
String hql = "from User u where u.username=:un and u.password=:pwd";
Query query = getSession().createQuery(hql);
query.setString("un", username)
.setString("pwd", password);
Object obj = query.uniqueResult();
return obj != null ? (User)obj : null;
} }

  还有其的XXXDao和XXXDaoImpl,通过继承和实现,可以让全部Impl实现类很轻松地就拥有基本的CRUD等通用数据库操作方法,如果某个实体有特殊的Dao操作只需要在相应Dao接口实现,然后在Impl实现类中实现该特殊方法就行,以前认识到的知识点在这里有了深入理解。

  泛型是一种思想,也是一种技术,动态的获取类型,让编程更加灵活,这里利用泛型,我们可以先不制定实体类对象具体类型,构造一个泛型的Dao接口和实现类,让后面各自具体的实体Dao去继承泛型的时候再确定类型,从而也得到了泛型中定义的基本方法。

  继承体现的是代码重用思想,当一个方法被构造多次的时候我们就要思考代码重用的问题了,在这里每个实体对象都需要基本的数据库操作方法,如果一个个的去定义将会十分繁琐和枯燥,通过继承我们可以省去很多代码。

  实现不同于继承,它没有节省代码,而且又涉及到抽象的概念,在单个父类与多个子类的继承关系中,父类某个方法对应的子类实现有差异时,我们对于父类的该方法,即可定义为抽象方法,子类各自实现具体细节即可。举个例子:动物父类,子类有鸟、鱼等,定义动物时,会定义睡觉方法,但是每种动物睡觉情况都不一样,鸟睡树上,鱼睡水下,你没法指定具体实现细节,所以就可以定义一个抽象的睡觉方法void sleep();具体的动物实现接口后,重写该抽象方法,展示实现细节。

  总结继承和实现:继承通用的,实现特殊的。在文中构造的持久层中,我们的所有实体通过继承轻松地拥有了所有的通用数据库操作方法,各自特殊的操作需求可在各自接口中生命然后在实现类中实现即可。

  最后,文中的项目中其实还存在许多不足的地方,主键的类型其实也可以用泛型,dao层有通用组件,service层是否应该也有通用的,若是有该如何构造等等,一些问题我在现在用的spring data jpa中得到了答案,所以应该会另外梳理一下写出来。

通过hibernate封装数据库持久化过程回顾泛型/继承/实现等概念的更多相关文章

  1. Hibernate入门5持久化对象关系和批量处理技术

    Hibernate入门5持久化对象关系和批量处理技术 20131128 代码下载 链接: http://pan.baidu.com/s/1Ccuup 密码: vqlv 前言: 前面学习了Hiberna ...

  2. hibernate操作数据库总结

    这篇文章用于总结hibernate操作数据库的各种方法 一.query方式 1.hibernate使用原生态的sql语句执行数据库查询 有些时候有些开发人员总觉得用hql语句不踏实,程序出现了错误,就 ...

  3. hibernate学习之持久化对象

    Hibernate对其持久化对象实现了缓存管理,来提高系统性能,Hibernate支持两级缓存管理,一级缓存 是由Session提供的,因此它只存在于Session的生命周期中,是Session所内置 ...

  4. android数据库持久化框架, ormlite框架,

    前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写复杂的SQL语句.虽然这样 ...

  5. Spring+Redis集成+关系型数据库持久化

    本篇文章主要介绍了"Spring+Redis集成+关系型数据库持久化",主要涉及到Spring+Redis集成+关系型数据库持久化方面的内容,对于Spring+Redis集成+关系 ...

  6. 5 -- Hibernate的基本用法 --2 2 Hibernate的数据库操作

    在所有的ORM框架中有一个非常重要的媒介 : PO(持久化对象:Persistent Object).持久化对象的作用是完成持久化操作,简单地说,通过该对象可对数据执行增.删.改的操作 ------ ...

  7. Hibernate与数据库的触发器协同工作

    Hibernate 与数据库中的触发器协同工作时, 会造成两类问题 1触发器使 Session 的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中, 它执行的操作对 Session ...

  8. PHP封装数据库

    (1)按照步骤封装数据库 ①引入抽象类和抽象方法,即引入模板: ②继承抽象类,注意参数(规定几个就传入几个): ③逐个写入抽象方法,必须一一对应:(抽象方法必须一一引入,否则会报错-->有个抽象 ...

  9. 用myeclipse快速搭建hibernate实现数据库访问

    前言 hibernate使用的大致过程为引入jar包.配置主配置文件.配置映射文件.编写实体类.编写dao.但是每一步都需要知道的内容都相对不少,造成困难.如果使用myeclipse提供的支持将非常容 ...

随机推荐

  1. tesseract-ocr字库训练图文讲解

    第一步合成图片集 你需要把使用jTessBoxEditor工具把你的训练素材及多张图片合并成一张tif格式的图片集 第二步  生成box文件 运行tesseract命令,tesseract mjorc ...

  2. HDU1201 水题

    做多了年月日,现在基本就能水过了 18岁生日 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/O ...

  3. MVC中@RenderBody、@RenderSection、@RenderPage、@Html.RenderPartial、Html.RenderAction的作用和区别

    1.@RenderBody()   作用和母版页中的服务器控件类似,当创建基于此布局页面的视图时,视图的内容会和布局页面合并,而新创建视图的内容会通过布局页面的@RenderBody()方法呈现在标签 ...

  4. 第六章 JDBC

    第一章 JDBC 一.JDBC的简介 1.什么是JDBC JDBC是java数据库连接(java database connectivity)技术的简称,它充当了java应用程序与各个不同数据库之间进 ...

  5. px转vw和vh的工具(对前端同学有用)

    CSS3中有两个新尺寸单位vw和vh, 这两个单位非常适合于开发移动端自适应页面. 假如说有一个设计师做了一张1136x750px的页面,这长页面是针对iPhone6的屏幕设计的. 前端开发工程师将这 ...

  6. Java简单工厂模式以及来自lambda的优化

    前言    设计模式是软件工程中一些问题的统一解决方案的模型,它的出现是为了解决一些普遍存在的,却不能被语言特性直接解决的问题,随着软件工程的发展,设计模式也会不断的进行更新,本文介绍的是经典设计模式 ...

  7. 写博客 Why?

    博客?英文名字为blogger,它是一种网络日记. 一.我为什么要写博客? 这是我第一回写博客,写的可能不是非常的好,请多多给些意见.在平常的学习的时候,我怕忘掉自己学的知识,常常都会记录下来,但回头 ...

  8. JAVA编程入门

    java最早是由Sun公司基于C++开发而成的新一代编程语言也是现行下的主流行编程语言,其原始的主要用于嵌入式开发.java的第一个版本为JDK1.0,到2017年已经升级到JAK1.9版本.java ...

  9. LINUX 笔记-crontab命令

    用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下: minute   hour   da ...

  10. 【ASP.NET MVC 学习笔记】- 15 Unobtrusive Ajax

    本文参考:http://www.cnblogs.com/willick/p/3418517.html 1.Unobtrusive Ajax允许我们通过 MVC 的 Help mothod 来定义 Aj ...