【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:5.技术简介之Hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。——百度百科
序言
博主在《迷你微信》项目上对Hibernate的使用是通过注解方式配置进行增删改查操作、使用c3p0连接池、使用ehcache缓存。
配置
hibernate.cfg.xml配置文件
主要是有关和MySQL数据库连接的配置、Ehcache、C3P0的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://127.0.0.1:3306/MiniWechat?useUnicode=true&characterEncoding=UTF-8</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<property name="javax.persistence.validation.mode">none</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- C3P0连接池 -->
<property name="c3p0.acquire_increment">1</property>
<property name="c3p0.idle_test_period">100</property>
<property name="c3p0.max_size">5</property>
<property name="c3p0.max_statements">0</property>
<property name="c3p0.min_size">2</property>
<property name="c3p0.timeout">90</property>
<property name="c3p0.preferredTestQuery ">SELECT CURRENT_USER</property>
<property name="c3p0.idleConnectionTestPeriod ">18000</property>
<property name="c3p0.maxIdleTime">25000</property>
<property name="c3p0.testConnectionOnCheckout">true</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Ehcache 缓存配置 -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<mapping class="model.User"/>
<mapping class="model.Chatting"/>
<mapping class="model.Group"/>
</session-factory>
</hibernate-configuration>
加载hibernate.cfg.html配置文件并获取Session
public class HibernateSessionFactory {
private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new Configuration();
public static SessionFactory sessionFactory;
private static String configFile = CONFIG_FILE_LOCATION;
static {
try{
configuration.configure(configFile);
ServiceRegistry sr = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(sr);
}catch(Exception e){
e.printStackTrace();
}
}
private HibernateSessionFactory() {
}
public static Session getSession() {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
}
对象的注解配置
主要是类的注解配置、成员变量的注解配置、多对多的注解配置
1.在需要在数据库中建表存储的类型需要在类名前添加注解
@Entity
@Table(name="user")
2.在相关成员变量添加注解
@Column(name="user_id",columnDefinition = "char(20) COMMENT '微信号'")
如果是数据库对应的主键需要添加注解:
@Id
如果是自增主键需要添加主键:
@GeneratedValue(strategy = GenerationType.AUTO)
3.多对多关联注解配置
在数据库中我们需要好友关系、聊天群的成员表,但在项目代码中我们并没有定义这样的对象,这是通过多对多的注解配置实现的
例如:
@ManyToMany(targetEntity=User.class)
@JoinTable(name = "user_friends",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "friend_id"))
public List<User> getFriends() {
return friends;
}
public void setFriends(List<User> friends) {
this.friends = friends;
}
增删改查
在项目中为了更好的将有关数据库的操作和业务逻辑分离,同时也有利于BUG和异常的捕获,我们将有关数据库的操作进行了封装,下面的代码只展示了有关Hibernate的增删改查操作的代码,没有展示封装的代码。
具体的增删改查代码
增:
public void add(Object obj){
Session session = HibernateSessionFactory.getSession();
Transaction trans = session.beginTransaction();
session.save(obj);
trans.commit();
session.close();
}
删:
public void delete(Object obj){
Session session = HibernateSessionFactory.getSession();
Transaction trans = session.beginTransaction();
session.delete(o);
trans.commit();
session.close();
}
改:
public void update(Object obj){
Session session = HibernateSessionFactory.getSession();
Transaction trans = session.beginTransaction();
session.update(o);
trans.commit();
session.close();
}
查:
public void query(String paramName, Object paramValue, Class outputClass){
Session session = HibernateSessionFactory.getSession();
Criteria criteria = session.createCriteria(outputClass);
// 使用缓存
criteria.setCacheable(true);
criteria.add(Restrictions.eq(paramName, paramValue));
List list = criteria.list();
session.close();
}
注意:
1.使用了缓存 后面会更加详细的介绍
2.paramValue的类型需要和查询对象定义的类型相匹配,否则会出现类型无法转换的报错
数据库操作的封装
1.将所有的数据库操作放在同一个类中,并声明为静态方法
2.对所有的操作进行异常捕获 避免抛出数据库、Hibernate相关的异常
3.定义枚举类型的ResultCode 返回操作是否成功
4.重要:在项目中 聊天群类型中定义了 聊天成员对象的List,当查询一个聊天群对象时,Hibernate并没有将聊天成员对象的List也查询出来,而是当需要使用的时候再查询,但前面提到的查询方法中调用了session.close(),这时无法再用原来的聊天群对象直接get聊天成员对象的List(Hibernate的延迟加载导致)。所以在封装的数据库操作类中重载了需要使用到延迟加载的相关方法,即:调用相关方法时传入session,在查询等操作时不立即close掉session,待调用者的方法结束时再close。Session是通过sessionFactory.openSession()方法获取,其实通过这种方式获取的ession时Hibernate会自动关闭。
连接池
在项目开始时并没有使用连接池,但出现过一次数据库无法访问的异常。经过查阅资料发现了问题所在:Mysql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,Mysql将自动断开该 connection。Hibernate默认的连接池并不知道该connection已经失效,如果这时有 Client请求connection,Hibernate将该失效的Connection提供给Client,将会造成上面的异常。
解决办法:使用C3P0连接池,有关C3P0连接池的配置在hibernate.cfg.xml配置文件中可以查看,需要的jar包可以在Hibernate的安装包可以找到。
其实一开始使用的是C3P0连接池,使用的是Proxool连接池,但使用过程中遇到了连接池销毁连接时的相关报错,而且没有找到很好的解决办法。所以就改用了C3P0连接池
缓存
EhCache是Hibernate的二级缓存技术之一,可以把查询出来的数据存储在内存或者磁盘,节省下次同样查询语句再次查询数据库,大幅减轻数据库压力
1.有关EhCache的配置可以在hibernat.cfg.xml中查看
2.在需要使用缓存的类添加注解
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
3.在数据库的查询操作中设置使用缓存
// 使用缓存
criteria.setCacheable(true);
3.当用Hibernate的方式修改表数据(save,update,delete等等),这时EhCache会自动把缓存中关于此表的所有缓存全部删除掉(这样能达到同步)。但对于数据经常修改的表来说,可能就失去缓存的意义了(不能减轻数据库压力);所以EhCache一般要使用在比较少执行write操作的表(包括update,insert,delete等)[Hibernate的二级缓存也都是这样];
注:本篇来自于数据库调试员:王飞先生
欢迎阅读我的开源项目《迷你微信》服务器与《迷你微信》客户端
【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:5.技术简介之Hibernate的更多相关文章
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:0.概述
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 序言 帖主和队友仿制了一个简单版的微信,其中,队友是用Unity3D做前段,帖主用Java的Mina.Hiberna ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:7.项目介绍之架构(1)
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 前言 <迷你微信>服务器端是使用Java语言,Mina框架编写的,一个良好的架构关系到后期迭代的方便程度 ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:9.观察者模式
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 前言 在一个程序的迭代过程中,复杂度渐渐上升,可能会出现一些跨模块的调用的需求,若是直接得到引用来进行使用,会导致模 ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:8.自定义传输协议
欢迎阅读我的开源项目<迷你微信>服务器)与<迷你微信>客户端 前言 在上一篇中,我们讲到了<迷你微信>服务器)的主体架构,还讲到了如何在现有功能上进行拓展,但是拓展 ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:6.技术简介之Protobuf
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 protocolbuffer(以下简称Protobuf)是google 的一种数据交换的格式,它独立于语言,独立于平 ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统 :1.技术简介之Mina连接
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 Apache MINA(Multipurpose Infrastructure for Network Applic ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:4.技术简介之Spring
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 Spring是一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:3.技术简介之MinaFilter——LoggingFilter (转)
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 LoggingFilter 接下来,使我们对Filter介绍的最后一个——LoggingFilter. 与Proto ...
- 【迷你微信】基于MINA、Hibernate、Spring、Protobuf的即时聊天系统:10.项目介绍之架构(2)
欢迎阅读我的开源项目<迷你微信>服务器与<迷你微信>客户端 前言 前面我们讲到<迷你微信>服务器端的主架构,现在我们来描述一下它的模块详细信息. 网络模块 从上图我 ...
随机推荐
- es6基础系列三:解构赋值
解构就是ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值(只能用于数组,对象或迭代器).如果解构不成功,则等于undefined,但不能赋值为undefined和null,因为undefi ...
- sqlachemy知识点
mysql语句 1.GROUP BY基本语法格式: GROUP BY关键字可以将查询结果按照某个字段或多个字段进行分组.字段中值相等的为一组.基本的语法格式如下: GROUP BY 属性名 [HAVI ...
- MATLAB求微分
求微分 diff(函数) , 求的一阶导数;diff(函数, n) , 求的n阶导数(n是具体整数);diff(函数,变量名), 求对的偏导数;diff(函数, 变量名,n) ,求对的n阶偏导数; & ...
- 再回首HTML
前言 本阶段视频自己前后看了两遍,感觉效果还是不错的,鉴于昨天上午整理了一些笔记,对HTML的理解深刻了一些.所以在这篇博文中就不再解释关于HTML一些定义的东西,这篇博文主要记录一些常用标记,为以后 ...
- JavaWeb:Cookie处理和Session跟踪
JavaWeb:Cookie处理和Session跟踪 Cookie处理 什么是Cookie Cookie 是存储在客户端计算机上的文本文件,保留了各种跟踪信息.因为HTTP协议是无状态的,即服务器不知 ...
- 深入理解Java虚拟机 学习总结
一.运行时数据区域 Java虚拟机管理的内存包括几个运行时数据内存:方法区.虚拟机栈.本地方法栈.堆.程序计数器,其中方法区和堆是由线程共享的数据区,其他几个是线程隔离的数据区 1.1 程序计数器 程 ...
- flask数据操纵
Flask ORM 在Django框架中内部已经提供ORM这样的框架,来实现对象关系映射,方便我们操作数据库.如果想在Flask中也达到这样效果,需要安装一个第三方来支持. SQLAlchemy是一个 ...
- web性能优化--缓存
什么是缓存? 缓存(Web缓存)是指代理服务器和客户端本地磁盘保存的资源副本.当 web 缓存发现请求的资源已经被存储,它会拦截请求,返回该资源的拷贝,而不会去源服务器重新下载. 缓存大致可以分为私 ...
- PAT甲级——1097 Deduplication on a Linked List (链表)
本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/91157982 1097 Deduplication on a L ...
- angularJS处理table中checkbox的选中状态
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...