使用過濾器(Filter)Hibernate Session 延時加載 (一對多關係)

轉自:http://www.blogjava.net/DoubleJ/archive/2008/03/04/183781.html 

 

Hibernate 3.x 提供的session的檢索策略默認爲延時加載.他有以下優點:
    減少數據庫併發性
    減少數據的IO次數
下面的例子是關於session的延時加載的例子.

建立數據庫example1

 

 1# SQL Manager 2005 Lite for MySQL 3.6.5.8
 2---------------------------------------
 3# Host     : localhost
 4# Port     : 3306
 5Database : example1
 6
 7
 8/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
 9/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
10/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
11/*!40101 SET NAMES gb2312 */;
12
13SET FOREIGN_KEY_CHECKS=0;
14
15DROP DATABASE IF EXISTS `example1`;
16
17CREATE DATABASE `example1`
18    CHARACTER SET 'gbk'
19    COLLATE 'gbk_chinese_ci';
20
21USE `example1`;
22
23#
24# Structure for the `department` table : 
25#
26
27DROP TABLE IF EXISTS `department`;
28
29CREATE TABLE `department` (
30  `d_id` int(11NOT NULL auto_increment,
31  `d_name` varchar(20NOT NULL,
32  PRIMARY KEY  (`d_id`),
33  UNIQUE KEY `d_name` (`d_name`)
34) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
35
36#
37# Data for the `department` table  (LIMIT 0,500)
38#
39
40INSERT INTO `department` (`d_id`, `d_name`) VALUES 
41  (1,'Office');
42
43COMMIT;
44
45#
46# Structure for the `emplyee` table : 
47#
48
49DROP TABLE IF EXISTS `emplyee`;
50
51CREATE TABLE `emplyee` (
52  `e_id` int(11NOT NULL auto_increment,
53  `e_name` varchar(20NOT NULL,
54  `e_login_name` varchar(20NOT NULL,
55  `e_password` varchar(20NOT NULL,
56  `e_reg_date` date default NULL,
57  `d_id` int(11default NULL,
58  PRIMARY KEY  (`e_id`),
59  UNIQUE KEY `e_login_name` (`e_login_name`),
60  KEY `d_id` (`d_id`),
61  CONSTRAINT `emplyee_fk` FOREIGN KEY (`d_id`) REFERENCES `department` (`d_id`)
62) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
63
64#
65# Data for the `emplyee` table  (LIMIT 0,500)
66#
67
68INSERT INTO `emplyee` (`e_id`, `e_name`, `e_login_name`, `e_password`, `e_reg_date`, `d_id`) VALUES 
69  (1,'YiJun','DoubleJ','windows','2008-03-01',1),
70  (2,'ZhangSan','Zs','windows','2008-03-04',1);
71
72COMMIT;
73
74
75
76/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
77/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
78/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

 

新建一javaWeb工程,取名爲 DJ_HIBERNATE
在MyEclipse裏的database Explorer建立數據源,連接上example1數據庫,並將hibernate 3.0導入到工程中!
創建以下類:
org.dj.pojo.DepartmentPojo.java

package org.dj.pojo;

import java.util.HashSet;
import java.util.Set;

public class DepartmentPojo {
    
private Integer did;

    
private String dname;

    
private Set<EmplyeePojo> emps = new HashSet<EmplyeePojo>(0);

    
public DepartmentPojo() {
        
// TODO Auto-generated constructor stub
    }


    
public DepartmentPojo(String dname) {
        
super();
        
this.dname = dname;
    }


    
public DepartmentPojo(Integer did, String dname) {
        
super();
        
this.did = did;
        
this.dname = dname;
    }


    
public Integer getDid() {
        
return did;
    }


    
public void setDid(Integer did) {
        
this.did = did;
    }


    
public String getDname() {
        
return dname;
    }


    
public void setDname(String dname) {
        
this.dname = dname;
    }


    
public Set<EmplyeePojo> getEmps() {
        
return emps;
    }


    
public void setEmps(Set<EmplyeePojo> emps) {
        
this.emps = emps;
    }


}


並在org.dj.pojo包下創建DepartmentPojo.hbm.xml關係配置文件
 1<?xml version="1.0"?>
 2<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4<hibernate-mapping>
 5    <class name="org.dj.pojo.DepartmentPojo" table="department">
 6        <id name="did" column="d_id" type="java.lang.Integer">
 7            <generator class="native"></generator>
 8        </id>
 9        <property name="dname" column="d_name"
10            type="java.lang.String">
11        </property>
12        <set name="emps">
13            <key column="d_id"></key>
14            <one-to-many class="org.dj.pojo.EmplyeePojo" />
15        </set>
16    </class>
17</hibernate-mapping>

再創建org.dj.pojo.EmplyeePojo類,
 1package org.dj.pojo;
 2
 3import java.sql.Date;
 4
 5public class EmplyeePojo {
 6    private Integer eid;
 7
 8    private String ename;
 9
10    private String eloginName;
11
12    private String epassword;
13
14    private java.sql.Date eregDate;
15
16    private DepartmentPojo department;
17
18    public DepartmentPojo getDepartment() {
19        return department;
20    }

21
22    public void setDepartment(DepartmentPojo department) {
23        this.department = department;
24    }

25
26    public EmplyeePojo() {
27        // TODO Auto-generated constructor stub
28    }

29
30    public EmplyeePojo(String ename, String eloginName, String epassword,
31            Date eregDate) {
32        super();
33        this.ename = ename;
34        this.eloginName = eloginName;
35        this.epassword = epassword;
36        this.eregDate = eregDate;
37    }

38
39    public EmplyeePojo(Integer eid, String ename, String eloginName,
40            String epassword, Date eregDate) {
41        super();
42        this.eid = eid;
43        this.ename = ename;
44        this.eloginName = eloginName;
45        this.epassword = epassword;
46        this.eregDate = eregDate;
47    }

48
49    public Integer getEid() {
50        return eid;
51    }

52
53    public void setEid(Integer eid) {
54        this.eid = eid;
55    }

56
57    public String getEloginName() {
58        return eloginName;
59    }

60
61    public void setEloginName(String eloginName) {
62        this.eloginName = eloginName;
63    }

64
65    public String getEname() {
66        return ename;
67    }

68
69    public void setEname(String ename) {
70        this.ename = ename;
71    }

72
73    public String getEpassword() {
74        return epassword;
75    }

76
77    public void setEpassword(String epassword) {
78        this.epassword = epassword;
79    }

80
81    public java.sql.Date getEregDate() {
82        return eregDate;
83    }

84
85    public void setEregDate(java.sql.Date eregDate) {
86        this.eregDate = eregDate;
87    }

88
89}

90


再在org.dj.pojo包下創建與其對應的配置文件EmplyeePojo.hbm.xml

 1<?xml version="1.0"?>
 2<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 3"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 4<hibernate-mapping>
 5    <class name="org.dj.pojo.EmplyeePojo" table="emplyee">
 6        <id name="eid" column="e_id" type="java.lang.Integer">
 7            <generator class="native"></generator>
 8        </id>
 9        <property name="ename" column="e_name"
10            type="java.lang.String">
11        </property>
12        <property name="eloginName" column="e_login_name"
13            type="java.lang.String">
14        </property>
15        <property name="epassword" column="e_password"
16            type="java.lang.String">
17        </property>
18        <property name="eregDate" column="e_reg_date"
19            type="java.sql.Date">
20        </property>
21        <many-to-one name="department"
22            class="org.dj.pojo.DepartmentPojo" column="d_id">
23        </many-to-one>
24    </class>
25</hibernate-mapping>


再創建一個dao對象用來得到一個員工記錄,些類爲:
org.dj.dao.EmplyeeDao
 1package org.dj.dao;
 2
 3import java.io.Serializable;
 4
 5import org.dj.pojo.EmplyeePojo;
 6import org.dj.util.HibernateSessionFactory;
 7import org.hibernate.HibernateException;
 8import org.hibernate.Session;
 9import org.hibernate.Transaction;
10
11public class EmplyeeDao {
12    /**
13     * 根據id得到用戶
14     * 
15     * @param eid
16     * @return
17     */

18    public EmplyeePojo getEmplyee(Serializable eid) {
19        EmplyeePojo emp = null;
20        Session session = HibernateSessionFactory.getSession();
21        // Transaction trans = session.beginTransaction();
22        try {
23            emp = (EmplyeePojo) session.load(EmplyeePojo.class, eid);
24            // trans.commit();
25        }
 catch (HibernateException e) {
26            e.printStackTrace();
27            // trans.rollback();
28        }
 finally {
29            // HibernateSessionFactory.closeSession();
30        }

31        return emp;
32    }

33}

34

一開始.請去掉我的代碼註釋;

下面,我們去寫個Emplyee的Service類,寫一個業務處理的方法, 通得員工ID計算已註冊的天數
org.dj.service.EmplyeeManegerService
 1package org.dj.service;
 2
 3import java.io.Serializable;
 4import java.util.Calendar;
 5
 6import org.dj.dao.EmplyeeDao;
 7import org.dj.pojo.EmplyeePojo;
 8import org.dj.vo.EmplyeeVo;
 9
10public class EmplyeeManegerService {
11    private EmplyeeDao empDao = new EmplyeeDao();
12    /**
13     * 得到用戶註冊的天數(本網站的網齡)
14     * @param eid 用戶的id
15     * @return 網齬
16     */

17    public Long loadEmplyeeOnlineTime(Serializable eid){
18        EmplyeePojo emp = empDao.getEmplyee(eid);
19        java.sql.Date regDate = emp.getEregDate();
20        Long time = System.currentTimeMillis() - regDate.getTime();
21        long day = time/(24*60*60*1000);
22        return day;
23    }

24    
25    public static void main(String[] args) {
26        Long day = new EmplyeeManegerService().loadEmplyeeOnlineTime(1);
27        System.out.println(day);
28    }

29}

30

裏面有個main寫的測試. 你去run的時候. 發現他會發生一個異常:
session was close;

解決這個方法,你可以這樣做.
先修改HibernateSessionFactory類.
  1package org.dj.util;
  2
  3import org.hibernate.HibernateException;
  4import org.hibernate.Session;
  5import org.hibernate.Transaction;
  6import org.hibernate.cfg.Configuration;
  7
  8
  9public class HibernateSessionFactory {
 10
 11    
 12    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
 13
 14    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
 15
 16    private static final ThreadLocal<Transaction> trThreadLocal = new ThreadLocal<Transaction>();
 17
 18    private static Configuration configuration = new Configuration();
 19
 20    private static org.hibernate.SessionFactory sessionFactory;
 21
 22    private static String configFile = CONFIG_FILE_LOCATION;
 23
 24    static {
 25        try {
 26            configuration.configure(configFile);
 27            sessionFactory = configuration.buildSessionFactory();
 28        }
 catch (Exception e) {
 29            System.err.println("%%%% Error Creating SessionFactory %%%%");
 30            e.printStackTrace();
 31        }

 32    }

 33
 34    private HibernateSessionFactory() {
 35    }

 36
 37    /**
 38     * Returns the ThreadLocal Session instance. Lazy initialize the
 39     * <code>SessionFactory</code> if needed.
 40     * 
 41     * @return Session
 42     * @throws HibernateException
 43     */

 44    public static Session getSession() throws HibernateException {
 45        Session session = (Session) threadLocal.get();
 46
 47        if (session == null || !session.isOpen()) {
 48            if (sessionFactory == null{
 49                rebuildSessionFactory();
 50            }

 51            session = (sessionFactory != null? sessionFactory.openSession()
 52                    : null;
 53            threadLocal.set(session);
 54        }

 55
 56        return session;
 57    }

 58
 59    /**
 60     * Rebuild hibernate session factory
 61     * 
 62     */

 63    public static void rebuildSessionFactory() {
 64        try {
 65            configuration.configure(configFile);
 66            sessionFactory = configuration.buildSessionFactory();
 67        }
 catch (Exception e) {
 68            System.err.println("%%%% Error Creating SessionFactory %%%%");
 69            e.printStackTrace();
 70        }

 71    }

 72
 73    /**
 74     * Close the single hibernate session instance.
 75     * 
 76     * @throws HibernateException
 77     */

 78    public static void closeSession() throws HibernateException {
 79        Session session = (Session) threadLocal.get();
 80        threadLocal.set(null);
 81
 82        if (session != null{
 83            session.close();
 84        }

 85    }

 86
 87    /**
 88     * return session factory
 89     * 
 90     */

 91    public static org.hibernate.SessionFactory getSessionFactory() {
 92        return sessionFactory;
 93    }

 94
 95    /**
 96     * return session factory
 97     * 
 98     * session factory will be rebuilded in the next call
 99     */

100    public static void setConfigFile(String configFile) {
101        HibernateSessionFactory.configFile = configFile;
102        sessionFactory = null;
103    }

104
105    /**
106     * return hibernate configuration
107     * 
108     */

109    public static Configuration getConfiguration() {
110        return configuration;
111    }

112
113    public static void openTransaction() {
114        Transaction tr = trThreadLocal.get();
115        if (tr == null{
116            tr = getSession().beginTransaction();
117            System.out.println("BeginTransaction");
118            trThreadLocal.set(tr);
119        }

120    }

121
122    public static void commitTransaction() {
123        Transaction tr = trThreadLocal.get();
124        if (tr != null && !tr.wasCommitted() && !tr.wasRolledBack()) {
125            System.out.println("Commit !");
126            tr.commit();
127            trThreadLocal.set(null);
128        }

129    }

130
131    public static void RollbackTransaction() {
132        Transaction tr = trThreadLocal.get();
133        if (tr != null && !tr.wasCommitted() && !tr.wasRolledBack()) {
134            tr.rollback();
135            System.out.println("Rollback!");
136            trThreadLocal.set(null);
137        }

138    }

139
140}


注意最後面的三個方法和trThreadLocal的屬性;

再寫一個過濾器, 代碼如下 :
org.dj.filter.HibernateSessionFilter
 1package org.dj.filter;
 2
 3import java.io.IOException;
 4
 5import javax.servlet.Filter;
 6import javax.servlet.FilterChain;
 7import javax.servlet.FilterConfig;
 8import javax.servlet.ServletException;
 9import javax.servlet.ServletRequest;
10import javax.servlet.ServletResponse;
11
12import org.dj.util.HibernateSessionFactory;
13
14public class HibernateSessionFilter implements Filter {
15
16    public void destroy() {
17        // TODO Auto-generated method stub
18
19    }

20
21    public void doFilter(ServletRequest request, ServletResponse response,
22            FilterChain chain) throws IOException, ServletException {
23
24        HibernateSessionFactory.getSession();
25        HibernateSessionFactory.openTransaction();
26        try {
27            chain.doFilter(request, response);
28            HibernateSessionFactory.commitTransaction();
29        }
 catch (Exception e) {
30            HibernateSessionFactory.RollbackTransaction();
31            e.printStackTrace();
32        }
 finally {
33            HibernateSessionFactory.closeSession();
34        }

35    }

36
37    public void init(FilterConfig filterConfig) throws ServletException {
38        // TODO Auto-generated method stub
39
40    }

41
42}

43

並在web.xml裏面配置這個過濾器,代碼如下 :
1<filter>
2      <filter-name>sessionFilter</filter-name>
3      <filter-class>org.dj.filter.HibernateSessionFilter</filter-class>
4  </filter>
5  <filter-mapping>
6      <filter-name>sessionFilter</filter-name>
7      <url-pattern>/*</url-pattern>
8  </filter-mapping>

這樣,我們就寫好了. 再回過頭把我在EmplyeeDao對象裏面註釋重新註釋上.並寫個兩個jsp和一個Serlvet進行測試.代碼如下:

index.jsp:
 1<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2<%
 3    String path = request.getContextPath();
 4    String basePath = request.getScheme() + "://"
 5            + request.getServerName() + ":" + request.getServerPort()
 6            + path + "/";
 7
%>
 8
 9<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
10<html>
11    <head>
12        <base href="<%=basePath%>">
13
14        <title>My JSP 'index.jsp' starting page</title>
15        <meta http-equiv="pragma" content="no-cache">
16        <meta http-equiv="cache-control" content="no-cache">
17        <meta http-equiv="expires" content="0">
18        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
19        <meta http-equiv="description" content="This is my page">
20        <!--
21    <link rel="stylesheet" type="text/css" href="styles.css">
22    -->
23    </head>
24
25    <body>
26        <form action="/DJ_HIBERNATE/servlet/GetOnlineDays">
27            員工編號:
28            <input name="eid">
29            <input type="submit">
30        </form>
31
32
33    </body>
34</html>
35


disp.jsp:
 1<%@ page language="java" import="java.util.*" pageEncoding="GB18030"%>
 2<%
 3String path = request.getContextPath();
 4String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 5
%>
 6
 7<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 8<html>
 9  <head>
10    <base href="<%=basePath%>">
11    
12    <title>My JSP 'disp.jsp' starting page</title>
13    
14    <meta http-equiv="pragma" content="no-cache">
15    <meta http-equiv="cache-control" content="no-cache">
16    <meta http-equiv="expires" content="0">    
17    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
18    <meta http-equiv="description" content="This is my page">
19    <!--
20    <link rel="stylesheet" type="text/css" href="styles.css">
21    -->
22
23  </head>
24  
25  <body>
26    ${day }
27  </body>
28</html>
29

org.dj.servlet.GetOnlineDays的serlvet的代碼如果:
package org.dj.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dj.service.EmplyeeManegerService;

public class GetOnlineDays extends HttpServlet {
    
private EmplyeeManegerService service = new EmplyeeManegerService();

    
public void doGet(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, IOException {
        Integer eid 
= Integer.parseInt(request.getParameter("eid"));
        Long day 
= service.loadEmplyeeOnlineTime(eid);
        request.setAttribute(
"day", day);
        request.getRequestDispatcher(
"/disp.jsp").forward(request, response);
    }


}


好了. 讓我們發佈後測試一下吧.
你會發現session was close的異常沒有了.
基本的工作原理如下 圖.
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章