通过hibernate封装数据库持久化过程回顾泛型/继承/实现等概念
前言
在开发过程中,我们不难发现,客户的需求以及产品的定位对开发内容的走向有很大的决策作用,而这些往往需要在一开始就尽可能考虑周全和设计完善。为什么说是尽可能,因为我们都知道,需求这种东西,一言难尽...作为开发者,既然无法掌控需求的变更等因素,那我们就要把握好自身能决定的工具资源等,架构设计、技术选型等等。有的人可能会说,我才多久经验之类,架构什么的不都是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封装数据库持久化过程回顾泛型/继承/实现等概念的更多相关文章
- Hibernate入门5持久化对象关系和批量处理技术
Hibernate入门5持久化对象关系和批量处理技术 20131128 代码下载 链接: http://pan.baidu.com/s/1Ccuup 密码: vqlv 前言: 前面学习了Hiberna ...
- hibernate操作数据库总结
这篇文章用于总结hibernate操作数据库的各种方法 一.query方式 1.hibernate使用原生态的sql语句执行数据库查询 有些时候有些开发人员总觉得用hql语句不踏实,程序出现了错误,就 ...
- hibernate学习之持久化对象
Hibernate对其持久化对象实现了缓存管理,来提高系统性能,Hibernate支持两级缓存管理,一级缓存 是由Session提供的,因此它只存在于Session的生命周期中,是Session所内置 ...
- android数据库持久化框架, ormlite框架,
前言 Android中内置了SQLite,但是对于数据库操作这块,非常的麻烦.其实可以试用第3方的数据库持久化框架对之进行结构上调整, 摆脱了访问数据库操作的细节,不用再去写复杂的SQL语句.虽然这样 ...
- Spring+Redis集成+关系型数据库持久化
本篇文章主要介绍了"Spring+Redis集成+关系型数据库持久化",主要涉及到Spring+Redis集成+关系型数据库持久化方面的内容,对于Spring+Redis集成+关系 ...
- 5 -- Hibernate的基本用法 --2 2 Hibernate的数据库操作
在所有的ORM框架中有一个非常重要的媒介 : PO(持久化对象:Persistent Object).持久化对象的作用是完成持久化操作,简单地说,通过该对象可对数据执行增.删.改的操作 ------ ...
- Hibernate与数据库的触发器协同工作
Hibernate 与数据库中的触发器协同工作时, 会造成两类问题 1触发器使 Session 的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中, 它执行的操作对 Session ...
- PHP封装数据库
(1)按照步骤封装数据库 ①引入抽象类和抽象方法,即引入模板: ②继承抽象类,注意参数(规定几个就传入几个): ③逐个写入抽象方法,必须一一对应:(抽象方法必须一一引入,否则会报错-->有个抽象 ...
- 用myeclipse快速搭建hibernate实现数据库访问
前言 hibernate使用的大致过程为引入jar包.配置主配置文件.配置映射文件.编写实体类.编写dao.但是每一步都需要知道的内容都相对不少,造成困难.如果使用myeclipse提供的支持将非常容 ...
随机推荐
- Myeclipse 配置Tomcat 出现 “Value must be an existing directory”错误
今天上午配了一下本机上的Myeclipse的tomcat,因为我本机上有两个版本的myeclipse,一个是用来公司开发的,一个是自己玩的,本机上装了两个版本jdk和两个版本的tomcat.配置自己玩 ...
- HTML的有序列表
针对HTML的有序列表,由于平常使用的不是很多,刚开始使用的时候也是有遇到一些坑,有几个小问题: 1.li的宽度不能设置为100%,这样的话就没办法看到前面的序号 2.如果设置li的颜色字体大小,前面 ...
- Win10系统下安装Ubuntu16.04.3教程与设置
在Win10上刚刚装好Ubuntu16.04.3,装了不下于10次,期间出现很多问题,趁着还有记忆,写下这篇教程,里面还有Ubuntu系统的优化与Win10的一些设置. Part 1 制作Ubuntu ...
- 深入浅出WPF——附加事件(Attached Event)
3.3 事件也附加——深入浅出附加事件 WPF事件系统中还有一种事件被称为附加事件(Attached Event),简言之,它就是路由事件.“那为什么还要起个新名字呢?”你可能会问. “身无彩凤双飞翼 ...
- riot.js教程【一】简介
Riotjs简介 Riotjs是一款简单的.优雅的.组件化UI前端开发框架: 他支持自定义标签(custom tags),拥有令人愉悦的语法,优雅的API和非常小的体积: 为什么需要一个新的界面库 前 ...
- mybatis 和hibernate的区别
mybaits 是不完全的orm(对象关系映射(Object Relational Mapping)框架,需要自己书写sql语句 mybatis学习难度必hibernate低适合关系型模型要求不高的软 ...
- 框架应用 : Spring MVC - 开发详述
软件开发中的MVC设计模式 软件开发的目标是减小耦合,让模块之前关系清晰. MVC模式在软件开发中经常和ORM模式一起应用,主要作用是将(数据抽象,数据实体传输和前台数据展示)分层,这样前台,后台,数 ...
- 窗口迅速关闭的解决办法/scanf/if/for/break
break if的格式 if(a>b) { printf("max=%d\n",a); } else printf("max=%d\n",b); scan ...
- FreeType in OpenCASCADE
FreeType in OpenCASCADE eryar@163.com Abstract. FreeType is required for text display in the 3D view ...
- Centos 7.0 execute yum update ——File "/usr/libexec/urlgrabber-ext-down", line 75, in <module> 解决方式
[打开这个文件:/usr/lib/python2.7/site-packages/urlgrabber/grabber.py找到elif errcode in (42, 55,56) 用 eli ...