前言

在开发过程中,我们不难发现,客户的需求以及产品的定位对开发内容的走向有很大的决策作用,而这些往往需要在一开始就尽可能考虑周全和设计完善。为什么说是尽可能,因为我们都知道,需求这种东西,一言难尽...作为开发者,既然无法掌控需求的变更等因素,那我们就要把握好自身能决定的工具资源等,架构设计、技术选型等等。有的人可能会说,我才多久经验之类,架构什么的不都是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. 正确使用Exception异常对象

    一.异常的构成 new Exception() 创建异常对象 throw 抛出异常对象(主要性能损耗位置) try{}catch{} 捕捉异常对象 C#里面异常对象分为两个子类ApplicationE ...

  2. python 多进程间交换信息与共享信息

    多线程调用函数,获取其返回值,个人总结了三种方法: 一.Queue(进程队列) 构造方法:multiprocessing.Queue([maxsize]) Queue.Queue类即是一个队列的同步实 ...

  3. javascript字典数据结构Dictionary实现

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat=&qu ...

  4. Java基础机试题

    package day8;import java.util.Scanner;/** * Java基础机试题 * @author:lyrand * */public class convert {   ...

  5. OpenWRT(RT5350) 路由客户模式(Routed Client) ,设置防火墙开放UDP指定端口

    /* *功     能: 本文主要功能是设置OpenWRT(RT5350) 系统实现路由客户模式,无线连接上级路由, * 无线释放AP客户端,实现伪装的中继(子网段与上级路由网段不同),同时更改防火墙 ...

  6. centos安装SWFtools服务(pdf2swf)

    第一步:下载swftools-0.9.2.tar.gz 第二步:swftools tar -xzvf swftools-0.9.2.tar.gz cd swftools-0.9.2 ./configu ...

  7. [SVN服务器搭建] 在myecplise下使用的 tortoise1.9 64位 跟 subversion1.9的服务器使用

    由于在公司经常用到SVN服务器,所以自己也想搭建在本机上面搭建一个SVN服务器玩玩,废话不多说,下面直接贴出来如何搭建的.  一.tortoise1.9 64位下载 直接百度下载即可,百度时候需要显示 ...

  8. ASP.NET Core 企业级开发架构简介及框架汇总

    企业开发框架包括垂直方向架构和水平方向架构.垂直方向架构是指一个应用程序的由下到上叠加多层的架构,同时这样的程序又叫整体式程序.水平方向架构是指将大应用分成若干小的应用实现系统功能的架构,同时这样的系 ...

  9. JAVA基础知识总结:八

    面向对象语言的三大特性;封装.继承.多态 一.面向对象语言特性之封装 1.什么是封装? 一个类中某些属性,如果不希望外界直接访问,我们可以将这个属性作为私有的,可以给外界暴露出来一个访问的方法 使用封 ...

  10. LeetCode 169. Majority Element (众数)

    Given an array of size n, find the majority element. The majority element is the element that appear ...