通过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提供的支持将非常容 ...
随机推荐
- 解决子级用css float浮动 而父级div没高度不能自适应高度
解决子级对象使用css float浮动 而父级div不能自适应高度,不能被父级内容撑开解决方法,父级div没有高度解决方法. 最外层的父级DIV不能自适应高度-不能随对象撑开没有高度 当在对象内的盒子 ...
- HTTPS与MITM
HTTPS:基于SSL/TSL的HTTP协议 MITM:Man-In-The-Middle中间人攻击 Https下中间人攻击的思路: 1 去https化 2 向CA申请相似域名的证书 防范: 睁大双眼
- ZPL条码打印类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...
- python re模块findall()详解
今天写代码,在写到郑泽的时候遇到了一个坑,这个坑是re模块下的findall()函数. 下面我将结合代码,记录一下 import re string="abcdefg acbdgef abc ...
- 笨鸟先飞之ASP.NET MVC系列之过滤器(04认证过滤器过滤器)
概念介绍 认证过滤器是MVC5的新特性,它有一个相对复杂的生命周期,它在其他所有过滤器之前运行,我们可以在认证过滤器中创建一个我们定义的认证方法,也可以结合授权过滤器做一个复杂的认证方法,这个方法可以 ...
- webview的javascript与Native code交互
http://my.oschina.net/u/1376187/blog/172296 项目中使用了webview显示网页,其中需要网页和native方法有交互,搜索到一篇文章,转发分享一下: === ...
- BZOJ-3709-[PA2014]Bohater(贪心)
Description 在一款电脑游戏中,你需要打败n只怪物(从1到n编号).为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药,使你恢复a[i]点生命值.任何时候你的生命值都不能降 ...
- Django(一)
Django 一.什么是web框架 框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演 ...
- Cocos2d-x Lua游戏开发Mac环境搭建以及一点点感悟
接触Cocos2d-x 最近由于公司项目的需要,自己开始接触Cocos,开始做一些简单的轻量级的游戏,以前没有接触过这一块的东西,也是借助这个机会学习一下游戏的开发,由于以前自己接触的全都是iOS和A ...
- 微信退款流程,以及在过程中遇见的错误和解决方式(php 语言)
官方下载demo 1:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1 开发步骤 : https://pay.weix ...