to cqzhangq(阿干) : 谢谢你的关心,真的很感谢;你这里是有问题的,你的重定向是怎么做的? 类似于response.sendRedirect("nextPath"); return;//(有不有这一句?)这样吗?
to cqzhangq(阿干) : 能把你的这个servlet的完整代码写出来看一下吗?
to cqzhangq(阿干) ls()两位高手: 我用一个bean进行数据库的连接,bean的scope是session,然后将结果集存入另一个bean中。现在出现问题了,就是每次查询一次与oracle建一个session后,就不断开了。每查一个建立一个会话。但我如果将连接数据库的代码直接写在jsp中,就没有这些问题了!
to redstarstar(红星星): 叫我高手?哈哈,别抬举我行不行,否则摔下来很痛的。你刚才说的具体实现我不太清楚,但我觉得你首先应该明白一点,数据库操作分三步:Connection,Statement,ResultSet。你的session保存的对象是指哪一个?你说的‘与oracle建立一个session后,就不断开了’又是指哪一个呢。
to cqzhangq(阿干): 你是怎样看待Connection、Statement、ResultSet之间的关系? 还有这里的session只是压的一个指针,你觉得呢? 还有你知道那些session中的结果集的数据都放在服务器端,但到底是web应用服务器端还是数据库服务器端啦?(都怪我心情不好!)
是这样的: 在servlet中取得数据,然后放到session中(通过定义一个bean(这里只是一个数据的结构),和一个Vector(相当于一个数组)),然后在jsp里仅仅对session进行操作,从session中取得数据显示,已经不需要用到ResultSet了 在servlet中可以这样: rs = stmt.executeQuery("..."); memberdata md = new memberdata(); Vector list; while(rs.next()){ md.setXm(rs.getString("xm")); ... list.addElement(md);//将对象加到数组 } synchronized (session) { session.setAttribute("memberlist",list);//将数组加到session中 } ... (当然了,代码中该try的地方还是要try的)在jsp里可以这样: ... Vector list; synchronized (session) { list = (Vector) session.getAttribute("memberlist"); } ... memberdata d = new memberdata(); for (int index=0; index < list.size();index++) { d = (memberdata)list.elementAt(index); String xm = d.getXm(); out.print("..."+xm+"...");//在适当的地方显示 ...//可以显示数据 }类memberdata相当于数据结构,里面的属性就是数据,然后有get和set的方法: class memberdata{ private String xm; ... public memberdata(){ xm=""; ... }
public String getXm(){ return xm; } public Void setXm(String newxm){ xm=newxm; } } 肯定不能这样:ResultSet rst1 = (ResultSet)session.getAttribute("this_rst"); 这里的结构模式是: servlet是用来处理数据的取出,然后结构化的将数据保存入session,然后在jsp中结构化地取出数据来显示,不在jsp中提及有关连接和会话的东西。 这里相当于对象被串行化了。如果只有一条数据,就没有必要用Vector了
cookie仅仅是一个文本文件,当用户访问站点时,它就被存储在用户使用的计算机上,其中,保存了一些信息,当用户日后再次访问这个站点时,web可以将这些信息提取出来。
session主要用于服务器端编程,而cookie是写到客户端的
你可以利用session.getId()方法来获得此号。你所说的数据,一般都是系统的一些数据。
当然我们通常还需要自己的数据,
session有很多方法,可以存放数据,最常用的是session.putValue("test",var),session.getValue("test")等等
将你用来存储的bean的scope设为session,每个需要读取与存储数据的页面,都需要声明这个bean。
说的对就给分吧。
用javabean把scope设置为session其实也是把数据存放在服务器端的内存中。
所以如果你真正做过项目,就该知道这里边其实有个很大的问题。比如一个数据库查询操作,其结果集需要在客户端做翻页显示,你是怎样做呢?可能大多数人都会做一个javabean,该bean的功能是根据查询条件得到结果集。然后在jsp中调用这个bean,把scope设置为session。这表面上看去很完美,操作起来也很快(因为牺牲了服务器的内存)。仔细想想就会发现,这结果集何时才能被释放呢。这当然是看客户端最后一次请求到现在的时间差是否超过你给session设置的过期时间。如果这个时候有很多不同session的客户端在请求,那么就服务器就会贡献出很多内存为这些不同session_id的客户端保存不同的数据。但服务器的内存总是有限,如果内存被耗完会是什么样啦?比如象sina这样的门户网站,其访问量大就不用说了,如果在查询框里输入‘计算机’会得到多少结果,近百万条结果呀,要是所有客户端的查询结果都放在服务器端的内存里,会是什么结果?(慢慢想吧)
所以,这里讨论一下session是很有意义的,因为当我知道其原理后,就会重新去思考我们的某些做法是否是真的实际可行。
一、 前言
说起来,Cookie应该是一种应用较久的技术了。早在HTML刚刚出现的时候,在每个独立的页面之间没有办法记录和标识不同的用户。后来人们就发明了Cookie技术,当用户访问网页时,它能够在访问者的机器上创立一个文件,我们把它叫作Cookie,写一段内容进去,来标识不同的用户。如果下次用户再访问这个网页的时候,它又能够读出这个文件里面的内容,这样网页就知道上次这个用户已经访问过该网页了。 虽然现在网页的制作技术比起几年以前已经发展了许多。不过有些时候,Cookie还是能够帮我们很多忙的。接下来,我们就来看看,如何在写JSP文件的时候,用JSP操作Cookie。
二、 写入Cookie 其实用JSP操作Cookie是非常简单的,我们来看下面一段JSP程序:<html>
<head>........(中间略)
</head>
<body>
<%
String cookieName="Sender";
Cookie cookie=new Cookie(cookieName, "Test_Content");
cookie.setMaxAge(10);
response.addCookie(cookie);
%>
........(其他内容)
</body>
</html> 这样我们就设置了一个Cookie,很简单吧? 我们来仔细研究一下这段代码: Cookie cookie=new Cookie(cookieName, "Test_Content"); 这一行建立了一个Cookie对象,初始化有两个参数,第一个参数cookieName定义了Cookie的名字,后一个参数,也是一个字符串,定义了Cookie的内容。也就是我们希望网页在用户的机器上标识的文件内容。 接下来一行:cookie.setMaxAge(10),调用了Cookie中的setMaxAge方法,设定Cookie在用户机器硬盘上的存活期为10秒。一个Cookie在用户的硬盘里面存在的时间并不是无限期的,在建立Cookie对象的时候,我们必须制定Cookie的存活期,超过了这个存活期后,Cookie文件就不再起作用,会被用户的浏览器自行删除。如果我们希望用户在下次访问这个页面的时候,Cookie文件仍然有效而且可以被网页读出来的话,我们可以将Cookie的存活期设得稍微长一些。比如cookie.setMaxAge(365*24*60*60)可以让Cookie文件在一年内有效。
三、 读出Cookie Cookie文件创建好后,自然还需要我们把它读出来,否则我们不是白费力气吗?接下来我们看看如何读出在用户硬盘上的Cookie。<html>
<head>........(中间略)
</head>
<body>
<table border=1>
<tr><td>Name</td><td>value</td></tr>
<%
Cookie cookies[]=request.getCookies();
Cookie sCookie=null;
String svalue=null;
String sname=null;
for(int i=0;i<cookies.length;i++)
{
sCookie=cookies[i];
svalue=sCookie.getValue();
sname=sCookie.getName();
%>
<tr><td><%=name%></td><td><%=svalue%></td></tr>
<%
}
%>
</table>
........(其他内容)
</body>
</html> 这一小段JSP文件可以读出用户硬盘上的所有有效的Cookie,也就是仍然在存活期内的Cookie文件。并用表格的形式列出每个Cookie的名字和内容。 我们来逐行分析一下这段代码: Cookie cookies[]=request.getCookies() 我们用request.getCookies()读出用户硬盘上的Cookie,并将所有的Cookie放到一个cookie对象数组里面。 接下来我们用一个循环语句遍历刚才建立的Cookie对象数组,我们用sCookie=cookies[i]取出数组中的一个Cookie对象,然后我们用sCookie.getValue()和sCookie.getName()两个方法来取得这个Cookie的名字和内容。 通过将取出来的Cookie的名字和内容放在字符串变量中,我们就能对其进行各种操作了。在上面的例子里,可通过循环语句的遍历,将所有Cookie放在一张表格中进行显示。
四、 需要注意的一些问题
通过上面两个简单的例子,可以看到,用JSP进行Cookie的操作,是非常简单的。不过我们在实际操作中还要注意一些问题: 1. Cookie的兼容性问题 Cookie的格式有2个不同的版本,第一个版本,我们称为Cookie Version 0,是最初由Netscape公司制定的,也被几乎所有的浏览器支持。而较新的版本,Cookie Version 1,则是根据RFC 2109文档制定的。为了确保兼容性,JAVA规定,前面所提到的涉及Cookie的操作都是针对旧版本的Cookie进行的。而新版本的Cookie目前还不被Javax.servlet.http.Cookie包所支持。 2. Cookie的内容 同样的Cookie的内容的字符限制针对不同的Cookie版本也有不同。在Cookie Version 0中,某些特殊的字符,例如:空格,方括号,圆括号,等于号(=),逗号,双引号,斜杠,问号,@符号,冒号,分号都不能作为Cookie的内容。这也就是为什么我们在例子中设定Cookie的内容为“Test_Content”的原因。 虽然在Cookie Version 1规定中放宽了限制,可以使用这些字符,但是考虑到新版本的Cookie规范目前仍然没有为所有的浏览器所支持,因而为保险起见,我们应该在Cookie的内容中尽量避免使用这些字符。到下面这个地方:
http://www.csdn.net/develop/article/9/9903.shtm
说明:
1.session数据存储在服务器端的共享内存中,不是存储在客户端,客户端存的是session的id号
2.不管你存不存到session中,都要从数据库中取数据
3.数据量很大时,采用session长期保存数据,势必会牺牲服务器内存,其实也就相当于把所有抽屉里的东西拿到桌面上备用,这样有好处也有坏处,很容易权衡吧。
4.取数据有几种方式:
直接取数据显示
取数据放到一个数据结构中,然后将其用session来保存,用一个专门显示数据的页面程序来显示
我个人认为,
如果基于规范性、代码可维护性考虑,可以选用后者,将程序分为专门取数据的,和专门做显示用的,比如javaBean和Servlet+bean+jsp;
或者是基于组件的开发的EJB等,当然也要用后者了;
反之,无所谓,可以采用前者,节约代码了。
以上是个人观点,如有不妥,请指正
说明:
1.session数据存储在服务器端的共享内存中,不是存储在客户端,客户端存的是session的id号
2.不管你存不存到session中,都要从数据库中取数据
3.数据量很大时,采用session长期保存数据,势必会牺牲服务器内存,其实也就相当于把所有抽屉里的东西拿到桌面上备用,这样有好处也有坏处,很容易权衡吧。
4.取数据有几种方式:
直接取数据显示
取数据放到一个数据结构中,然后将其用session来保存,用一个专门显示数据的页面程序来显示
我个人认为,
如果基于规范性、代码可维护性考虑,可以选用后者,将程序分为专门取数据的,和专门做显示用的,比如javaBean和Servlet+bean+jsp;
或者是基于组件的开发的EJB等,当然也要用后者了;
反之,无所谓,可以采用前者,节约代码了。
以上是个人观点,如有不妥,请指正
如果不明白的话,把贴子的所有回复从头到尾读一遍!
如果你还不明白的话,
我就有点怀疑你了呵呵!
这时候可以再来问!
同意你的一些看法,但是:
用session一样可以很好解决分页的问题,不是session的局限,而是方法适应的问题。
可以通过限制结果集的数量,每次从数据库中取一页所需的n条,放到session中,需要看下一页时再取下n条,这只是算法的问题。所以说,session中可以不用存上百万的纪录,而只有20条或30条。
不好意思,我并没有恶意。
至于用session和用cookie,我想应该是数据的安全性考虑的范畴了
阿干兄,我是做jsp才不久,很多问题,看的不是很清。我的目的是想帮助别人,如果您是对的,我不仅尊重您,更感谢您!在另一方面,我也想和大家讨论讨论,向你们多学点东西。也许我有很多对问题的看法不对,还有说话的方式不对,请您原谅!sorry!向您道歉!从数据库中取出数据并分页显示,通常采用的两种处理方法:
1。一次将取出所有结果放到记录集中, 存放在内存中,然后再分页显示。
2。一次仅取出规定数目的记录数,并显示
当数据记录非常多的情况下,通常采用第二种方式。当数据量不大时,采用第一种方式较好。
论坛就是提供一个大家讨论的空间,我的知识也浅薄,只是想通过讨论来提高自己,当然能帮助别人也很荣幸,大家用jsp都不长,因为jsp出来就不久,共同进步吧
既然大家都明白了session的实现是靠牺牲服务器的内存来实现的,其解决方案大家心里都有了底(比如楼上很多兄弟都提到了,数据记录少时可以存放在内存中;多时,那么每次取出一定数量的记录来显示)。那我们就来继续把话题深入下去。
我们用session的目的是什么啦?可能有很多,比如安全性、不同page之间的数据传送等;但我们这里的目的是想快速得到数据。就是说从session中去取数据我们可以只进行一次数据库操作就能得到数据(因为它把数据存在了服务器内存中);而如果不用session的话,每次想得到数据都得进行一次数据库操作。而数据库操作在我们的印象中总是很耗时间的。session的原理我们在前面已经讨论得差不多了;下面就讨论一下数据库操作(耗时问题),这里主要指数据库查询。
我认为这样一次数据库操作应该分三步,首先建立一个Connection,然后是创建一个Statement,最后就是得到ResultSet处理。这里很明显第一步是最耗时的,所以实际项目中几乎没有人会在每一个线程(就是jsp页面中或servlet中的doGet()或servlet中的doPoset()或servlet中的service())中去创建一个Connection,然后再创建一个Statement,然后再得到ResultSet,然后再去反过来把它们都关掉。
那我们应该怎么做啦?为了把问题清晰化,我们在servlet中来进行说明(都知道jsp实际也可以在某中意义上说是servlet)。先看下面代码:
package 包名;//(注意该代码只是示意,不能进行调试运行)
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
public class Test extends HttpServlet { protected Connection con; public void init(ServletConfig config) throws ServletException {
super.init(config);
try
{
Class.forName("driver");
con = (Connection)DriverManager.getConnection("path", "user", "password");
con.setAutoCommit(true);//是否自动提交。
}
catch(Exception err)
{
//;
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("text/html");
response.setHeader("test", "no-cache");
response.setDateHeader("Expires", 0L);
PrintWriter out = response.getWriter();
try{
Statement stmt = con.createStatement(/*参数*/);
ResultSet rst = stmt.executeQuery("sql语句");
//对rst进行处理,1.直接显示rst;2.把rst压如session在转向到jsp中进行显示(特别是需要分页显示时)
}catch(SQLException e){
out.println(e.toString());
}
}
public void destroy()
{
super.destroy();
try
{
con.close();
}
catch(SQLException sqlexception) {
//;
}
finally
{
try
{
if(!con.isClosed())
con.close();
}
catch(SQLException sqlexception1) {
//;
}
}
}
}
(注意这里我没有用连接池)注意在上面的代码中我把Connection的创建放在了init()方法中,这样一旦这个进程起来后,那么这个Connection就被创建了,而后的所有线程都在共享这个Connection;这意味着什么呢,1.所有的线程都共享一个Connection;2.除第一个线程(起动这个进程)外,其余所有线程都不用去创建Connection。第一条会给我们带来麻烦,因为如果访问量很大时一个Connection是会崩溃的。现在比较多的解决办法是用连接池。而第二条却给我们带来好处,因为我们不用再去创建Connection,这样可以节省大量的时间。现在我们假设不用连接池,还是就象上面的代码那样。这里看起来好象很正常,没有什么明显的不当之处。但如果仔细分析一下,我们会发现在service(线程)方法中还有一个Statement对象。我们为了得到ResultSet不得不创建它,但随之一个问题产生了(需要把结果集通过session传递到jsp时, 特别是在要翻页显示的时候),我们为了使用ResultSet却又不能把刚创建的Statement
关掉。是不是很痛苦?没办法。可能有的人会觉得无所谓,但你试一试就知道,你不停的去请求,很快就会报出一个57011的错误(它的大概意思是资源耗尽,至于为什么,不知你注意没有,原来每一个Connection能创建的Statement是有限的,可以想办法得到这个上限数)。
总归得解决吧,对这个问题我先提出两种解决方案,一是把Statement的创建放在init()中;
二是在线程中想办法把创建的Statement对象关闭。(当然这里边又会扯出进一步的话题,先让俺歇一会儿吧)
继续刚才的话题前,做一个具体的假设(也就是实际中的某种应用),假设我们现在是要根据一些查询条件得到一个结果集,然后通过session把结果集传递到一个jsp文件中,在jsp文件中进行显示,并且需翻页。有不有发现,我们在做了这个具体假设后突然发现前面的两个解决方案都不可行了。why?
一.我们为了把Statement的创建放在init()中,就不得不把Statement的变量定义为全局的,也就是说,所有线程共享一个Statement对象,这样似乎速度上又可以提高不少,因为每个线程连Statement对象也不用创建了;但如果测试一下就会发现出问题了:输入查询条件,确定后得到查询结果,假设有5页;再另开一个IE(最好和刚才那个PAGE没有session关系,后面再具体说),也输入一些查询条件,确定后得到查询结果,假设有3页。好象很正常;错了,这个时候你去把刚才那个查询结果刷新一下,看到什么了,是不是结果变了,居然变成别人的查询结果了。哈哈,明白怎么回事了,因为Statement是全局变量呀!
(待叙)
private DBConnectionManager connMgr; //Initialize global variables
public void init(ServletConfig config) throws ServletException {
...
} //Process the HTTP Get request
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Statement stmt=null;
Connection con = ...;//这里创建连接
stmt=con.createStatement();
ResultSet rs1=stmt.executeQuery("SQL语句");
...
if(stmt!=null)stmt.close();
//断开连接
}
} public void destroy() {
// 断开连接
} public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
} //Get Servlet information
public String getServletInfo() {
return "Test1.listbookdl Information";
}
}(代码不完整,没有异常处理,发生异常时也要断开连接)
在这里用连接池来创建连接,这样每次连接都不会很慢了。
:)
我上面的意思不是主要讨论Connection的问题,用连接池当然是对。但你有不有发现你的Statement有问题吗?如果结果集需要用session传递到jsp进行分页显示,你的Statement能关闭吗?
up!
help me!
up!
up!
我的statement可以关闭呀,上面的程序是我从以前的项目中提出来的(网站已经正常运行1年多了),还没有遇到什么问题。
当地址重定向到jsp显示页面时,那个servlet的生命周期已经结束了,当然statement要被关闭了,并且connection也断开了,当然,如果不断开的话会出问题的(资源很快会被耗尽),要重启java的服务器(虽然java是自动回收,这里我也还没有明白)。
另外:同情老兄的遭遇,也许你们之间有误会,随着时间会消除的吧,或许可以用你的真诚去打动一下了,祝好运
谢谢你的关心,真的很感谢;你这里是有问题的,你的重定向是怎么做的?
类似于response.sendRedirect("nextPath");
return;//(有不有这一句?)这样吗?
能把你的这个servlet的完整代码写出来看一下吗?
我用一个bean进行数据库的连接,bean的scope是session,然后将结果集存入另一个bean中。现在出现问题了,就是每次查询一次与oracle建一个session后,就不断开了。每查一个建立一个会话。但我如果将连接数据库的代码直接写在jsp中,就没有这些问题了!
叫我高手?哈哈,别抬举我行不行,否则摔下来很痛的。你刚才说的具体实现我不太清楚,但我觉得你首先应该明白一点,数据库操作分三步:Connection,Statement,ResultSet。你的session保存的对象是指哪一个?你说的‘与oracle建立一个session后,就不断开了’又是指哪一个呢。
我摔得也会痛:)
你在bean中有关闭Connection,Statement之类的方法吗,在jsp执行的最后要执行此方法来关闭它。ls():源代码就是上面的了,我只是把取结果集和放入session的部分去掉了,
重定向有两种方式:
1.正如你所说,一般使用
2.用RequestDispatcher接口,利用请求分配器,可以寻找路径
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher(url);
rd.forward(req, res);
此方法,我现在发现的效果区别就是定向到的页面还是在本页显示的,直接的说就是地址栏里显示的是servlet的url,也就是说相当于将那个页面打包到这个servlet中了,这种方法还是很有用的。
对了我那里有什么问题呢?我在重定向后关闭了statement和connection了
如果你在重定向后用了return;的话,那么后后面的操作根本就没执行(就是那些关闭操作)
不会吧!关闭了Statement后你的ResultSet实例还能用吗?
...
Connection con = //得到一个连接;
Statement stmt = con.createStatement(1004,1007);
ResultSet rst = stmt.executeQuery("sql语句");
session.setAttribute("this_rst",rst);
stmt.close();
...
//下面是到jsp里去处理
ResultSet rst1 = (ResultSet)session.getAttribute("this_rst");
你觉得这里的rst1还能用吗?
你是怎样看待Connection、Statement、ResultSet之间的关系?
还有这里的session只是压的一个指针,你觉得呢?
还有你知道那些session中的结果集的数据都放在服务器端,但到底是web应用服务器端还是数据库服务器端啦?(都怪我心情不好!)
是这样的:
在servlet中取得数据,然后放到session中(通过定义一个bean(这里只是一个数据的结构),和一个Vector(相当于一个数组)),然后在jsp里仅仅对session进行操作,从session中取得数据显示,已经不需要用到ResultSet了
在servlet中可以这样:
rs = stmt.executeQuery("...");
memberdata md = new memberdata();
Vector list;
while(rs.next()){
md.setXm(rs.getString("xm"));
...
list.addElement(md);//将对象加到数组
}
synchronized (session) {
session.setAttribute("memberlist",list);//将数组加到session中
}
...
(当然了,代码中该try的地方还是要try的)在jsp里可以这样:
...
Vector list;
synchronized (session) {
list = (Vector) session.getAttribute("memberlist");
}
...
memberdata d = new memberdata();
for (int index=0; index < list.size();index++)
{
d = (memberdata)list.elementAt(index);
String xm = d.getXm();
out.print("..."+xm+"...");//在适当的地方显示
...//可以显示数据
}类memberdata相当于数据结构,里面的属性就是数据,然后有get和set的方法:
class memberdata{
private String xm;
...
public memberdata(){
xm="";
...
}
public String getXm(){
return xm;
}
public Void setXm(String newxm){
xm=newxm;
}
}
肯定不能这样:ResultSet rst1 = (ResultSet)session.getAttribute("this_rst");
这里的结构模式是:
servlet是用来处理数据的取出,然后结构化的将数据保存入session,然后在jsp中结构化地取出数据来显示,不在jsp中提及有关连接和会话的东西。
这里相当于对象被串行化了。如果只有一条数据,就没有必要用Vector了
如果是做做练习,在SESSION中存放数据是要快一些。
如果是开发企业级的应用,我觉得还是少用SESSION的好,客户多时,增加的服务器端的开销大大多于再次连接数据库所需的开销,而且,利用CONNECTION POOL,可以大大减少连接DB的开销,对于分页查询来说,同一条SQL文再解析的时间也会大大减少。所以在一般的开发中,我们只在SESSION中存放一些简单的用户信息而已。