【迷你微信】基於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&amp;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的二級緩存也都是這樣];

注:本篇來自於數據庫調試員:王飛先生
歡迎閱讀我的開源項目《迷你微信》服務器《迷你微信》客戶端


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM