servlet+jsp基础知识四
复习:
1、 JSP
jsp引擎
一个程序,把jsp文本文件转换为servlet
jsp的语法
<%......%>
<%=表达式%>---<%out.write(表达式);%>
一个程序,把jsp文本文件转换为servlet
jsp的语法
<%......%>
<%=表达式%>---<%out.write(表达式);%>
JSP内建对象和隐含对象
SUN的标准规定的,由JSP引擎声明好的变量
out
request
response
SUN的标准规定的,由JSP引擎声明好的变量
out
request
response
application
page
config
pageContext
JSP指令
写在jsp文件中,指示jsp引擎在生成servlet的时候一些特性或者注意的问题
<%@ .......%>
<%@page import="java.sql.*,java.util.*"%>
<%@include file="head.jsp" %>
2、cookie技术
理解原理
通过协议的方式来理解原理
理解原理
通过协议的方式来理解原理
第一次发请求的时候
GET /... HTTP/1.1
.........
GET /... HTTP/1.1
.........
响应
HTTP/1.1 200 OK
Set-Cookie:som_key=1000
Set-Cookie:other_key=2000
...
HTTP/1.1 200 OK
Set-Cookie:som_key=1000
Set-Cookie:other_key=2000
...
HTML....
浏览器就会把这些信息保存在客户端
当下一次浏览器又访问时
GET /... HTTP/1.1
.........
Cookie:some_key=1000,other_key=2000
3、了解cookie api
Cookie cookie=new Cookie("name","value");
//cookie.setMaxAge(int s); 0 <0 >0
Response.addCookie(cookie);
将cookie放入到响应http包头
将cookie放入到响应http包头
Cookie [] cookies=request.getCookies();//注意null
4、用cookie的注意事情
a、编码问题(特殊字符与协议的冲突)
URLEncoder 和URLDecoder
b、值得大小和个数
4k,不能超过20个(一个域名20个cookie)
c、cookie的安全问题
cookie可以伪造
d、路径问题
test/a/save_cookie.jsp
a、编码问题(特殊字符与协议的冲突)
URLEncoder 和URLDecoder
b、值得大小和个数
4k,不能超过20个(一个域名20个cookie)
c、cookie的安全问题
cookie可以伪造
d、路径问题
test/a/save_cookie.jsp
<%
Cookie cookie = new Cookie("some_key","1000");
cookie.setPath("/servlet04");//servlet04下面所有应用都带cookie
//可以调用cookie的方法,可以设置路径
//cookie.setPath("/test");//下一次请求,必须是/test下面的
//默认值,如果不指定的话,/test/a
response.addCookie(cookie);
%>
Cookie cookie = new Cookie("some_key","1000");
cookie.setPath("/servlet04");//servlet04下面所有应用都带cookie
//可以调用cookie的方法,可以设置路径
//cookie.setPath("/test");//下一次请求,必须是/test下面的
//默认值,如果不指定的话,/test/a
response.addCookie(cookie);
%>
test/b/get_cookie.jsp
<%
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
out.println("<h1>" + cookie.getName() + ": "
+ cookie.getValue() + "</h1>");
}
}
%>
5、session技术
sesssion技术要利用cookie,cookie记录了session中的session id
session 有一个session id,就是这个session的唯一id
session会对服务器有压力,session如果用不好的话,服务器就完蛋了。
什么时候用session,什么时候用cookie
一个用户登陆一次之后,1年之内不用再登陆。----〉最好是用cookie,服务器不能存储那么多的session数据
一个用户登陆了,半个小时之内不用再登陆。-----〉最好使用session。
一个用户登陆一次之后,1年之内不用再登陆。----〉最好是用cookie,服务器不能存储那么多的session数据
一个用户登陆了,半个小时之内不用再登陆。-----〉最好使用session。
大型的门户系统,最好是用cookie;服务器的sesion肯定有个超时的机制
6、session基本原理,例子及抓包分析
我们来看下session到底是怎么回事//////
基本原理:服务器端先要在内存中做一个对象session,这个session有一个唯一的Id(sessionid),当客户端来访问来
服务器时访,服务器响应的时候会把sessionid放到其cookies里面让客户端带走。当客户端再次访问服务器的时候,
就可以通过sessionid来获得对象。
我们来看下session到底是怎么回事//////
基本原理:服务器端先要在内存中做一个对象session,这个session有一个唯一的Id(sessionid),当客户端来访问来
服务器时访,服务器响应的时候会把sessionid放到其cookies里面让客户端带走。当客户端再次访问服务器的时候,
就可以通过sessionid来获得对象。
通过例子来深入了解session的工作原理
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 如果当前的请求信息中有带有存储Session ID的Cookie,且该Session ID
* 对应的Session对象存在,则返回该对象
*
* 否则,该方法将创建新的Session对象并且将新产生的Session ID 作为Cookie
* 通过响应存到浏览器端
*/
HttpSession session = request.getSession();//通过request.getSession获得一个session对象
System.out.println(session.getId());//获得这个session的编号,SESSIONID
// void setAttribute(String, Object)
session.setAttribute("date", new Date());//存session属性,在这里是存储一个date对象
//设置最大的不活动时间
session.setMaxInactiveInterval(60*30);//默认半小时, 秒
// 让Session失效一般用在login的登出
//session.invalidate();//一调用这个方法,session立马失效
// Object getAttribute(String)
Object obj = session.getAttribute("date");//获得session的属性,在这里是获得一个date对象并返回
System.out.println(obj);
}
session设置的cookie默认为负数
抓包分析Session工作原理
第一次访问
请求信息
GET /servlet/session HTTP/1.1
HOST:localhost:8080
......
Connection:keep-alive
响应
HTTP/1.1 200 OK
Server:apache-coyote/1.1
Set-Cookie:JSESSIONID=BCC703F862DC0CEF7CDEB6088C58E82A;Path=/servlet
content-type:image/x-icon
content-length:21333
Date:...
通过console显示sessionid也为:BCC703F862DC0CEF7CDEB6088C58E82A
刷新页面,实现第二次访问
验证同一session:通过console查看sessionid还是BCC703F862DC0CEF7CDEB6088C58E82A
HTTP/1.1 200 OK
Server:apache-coyote/1.1
Set-Cookie:JSESSIONID=BCC703F862DC0CEF7CDEB6088C58E82A;Path=/servlet
content-type:image/x-icon
content-length:21333
Date:...
通过console显示sessionid也为:BCC703F862DC0CEF7CDEB6088C58E82A
刷新页面,实现第二次访问
验证同一session:通过console查看sessionid还是BCC703F862DC0CEF7CDEB6088C58E82A
第2次请求
GET /servlet/session HTTP/1.1
HOST:localhost:8080
......
Connection:keep-alive
Cookie:JSESSIONID=BCC703F862DC0CEF7CDEB6088C58E82A
Cache-Control:max-age=0
GET /servlet/session HTTP/1.1
HOST:localhost:8080
......
Connection:keep-alive
Cookie:JSESSIONID=BCC703F862DC0CEF7CDEB6088C58E82A
Cache-Control:max-age=0
HTTP/1.1 200 OK
Server:apache-coyote/1.1
content-type:image/x-icon
content-length:21333
Date:...
关闭浏览器:重新访问该页面
Server:apache-coyote/1.1
content-type:image/x-icon
content-length:21333
Date:...
关闭浏览器:重新访问该页面
console上显示:其Cookie:JSESSIONID=F7CC58E8862DC0CEDEB60882ABCC703F
7、session与cookie的联系点
session用cookie存储session id
session可以存储任何对象,而cookie相对来说编码麻烦点
7、session与cookie的联系点
session用cookie存储session id
session可以存储任何对象,而cookie相对来说编码麻烦点
8、session的序列化和反序列化
接着上面的例子,重新做个实验:
1、第一次浏览session
2、第二次浏览同一session
3、第三四浏览器同一session
4、关闭tomcat服务,但不关闭浏览器
5、开启tomcat服务,刷新浏览器页面
6、sessionid没有变化
??为什么呢?这就是序列化和反序列化
接着上面的例子,重新做个实验:
1、第一次浏览session
2、第二次浏览同一session
3、第三四浏览器同一session
4、关闭tomcat服务,但不关闭浏览器
5、开启tomcat服务,刷新浏览器页面
6、sessionid没有变化
??为什么呢?这就是序列化和反序列化
服务器关闭的时候,会把当前内存中session都存储到服务器硬盘的一个文件里面。
当服务器启动起来之后,再把文件里面的内容读取到内存中。这就是序列化和反序列化session
当服务器启动起来之后,再把文件里面的内容读取到内存中。这就是序列化和反序列化session
注意:正常关闭的情况下才能序列化
也就是说往session对象里面放置的对象必须是可序列化的!!!这也是一个重要规则
(从管理维护的角度来看,在用的系统时,如需关机维护时,需先停止服务,使其序列化,然后再关机
等计算机启动起来之后,再启动服务,使其反序列化)
如下例:
public class User implements java.io.Serializable {
//============================
//必须要加上这个才能序列化
//必须实现了序列化接口才能最终序列化
private String id;
private String name;
public String getId() {
return id;
}
return id;
}
public void setId(String id) {
this.id = id;
}
this.id = id;
}
public String getName() {
return name;
}
return name;
}
public void setName(String name) {
this.name = name;
}
this.name = name;
}
9、极品问题
a、
........
response.sendRedirect("1.jsp");//执行完这句还执行下句吗?
System.out.println("hahahhahah");
.....
肯定是要执行的。
response.sendRedirect只是在响应的时候,告诉浏览器响应代码为302,其location为1.jsp而已
整个这个方法还是要执行完的。
a、
........
response.sendRedirect("1.jsp");//执行完这句还执行下句吗?
System.out.println("hahahhahah");
.....
肯定是要执行的。
response.sendRedirect只是在响应的时候,告诉浏览器响应代码为302,其location为1.jsp而已
整个这个方法还是要执行完的。
b、......
response.sendRedirect("1.jsp");//执行完这句还执行下句吗?如果执行的话,会输出到1.jsp中吗?
PrintWriter out=response.getWriter();
out.println("hahahhahaha");
......
肯定会执行,但是在真正响应的时候,只是将其转向到1.jsp,而后面语句的html语句不会带到1.jsp中
会丢弃掉,只发送一个响应302转发而已。
10、文件上传和验证码
response.sendRedirect("1.jsp");//执行完这句还执行下句吗?如果执行的话,会输出到1.jsp中吗?
PrintWriter out=response.getWriter();
out.println("hahahhahaha");
......
肯定会执行,但是在真正响应的时候,只是将其转向到1.jsp,而后面语句的html语句不会带到1.jsp中
会丢弃掉,只发送一个响应302转发而已。
10、文件上传和验证码
验证码程序
1、客户端首先要访问服务器,servlet就产生一个验证码图片(服务器要保存验证码)
2、客户端输入一个识别的验证码,发给服务器
3、服务器要对验证码进行比对,如果一样,则通过
1、客户端首先要访问服务器,servlet就产生一个验证码图片(服务器要保存验证码)
2、客户端输入一个识别的验证码,发给服务器
3、服务器要对验证码进行比对,如果一样,则通过
是不是可以通过session来保存验证码呢?
前面的模式:
a、servlet或者jsp里面包含对数据库的连接和操作,也包含了相关的业务逻辑
b、这种情况下,如果程序比较大的话,后期的维护工作量比较大
怎么来解决这种问题呢?
把对数据库的连接和操作封装起来,比如说弄个工具类
JSP+JavaBean
11、JSP+JavaBean,一般不写servlet;
前面的模式:
a、servlet或者jsp里面包含对数据库的连接和操作,也包含了相关的业务逻辑
b、这种情况下,如果程序比较大的话,后期的维护工作量比较大
怎么来解决这种问题呢?
把对数据库的连接和操作封装起来,比如说弄个工具类
JSP+JavaBean
11、JSP+JavaBean,一般不写servlet;
JSP负责页面,尽量不写servlet;
JavaBean一堆java的类:封装员工数据本身,封装对数据的操作
12、例子:显示员工列表,带分页功能
JavaBean一堆java的类:封装员工数据本身,封装对数据的操作
12、例子:显示员工列表,带分页功能
a、一堆jsp:
显示结果jsp:如emp_list.jsp
表单jsp:login_form.jsp
操作jsp:接收用户输入,可以调用javabean类来访问相关数据
jsp中只会调用javaBean,不能写sql语句
b、java类:封装对数据的访问增删改查
设计从后往前方式:从无到有
1、数据库
table---emp
2、javaBean
a、先考虑好类名,不要考虑其方法和属性如:Emp类
b、类名Dao:封装一些方法,完成对员工数据的增删改查 EmpDao
一般情况下,一个table对应一个类,一个Dao
3、页面
emp_list.jsp
显示结果jsp:如emp_list.jsp
表单jsp:login_form.jsp
操作jsp:接收用户输入,可以调用javabean类来访问相关数据
jsp中只会调用javaBean,不能写sql语句
b、java类:封装对数据的访问增删改查
设计从后往前方式:从无到有
1、数据库
table---emp
2、javaBean
a、先考虑好类名,不要考虑其方法和属性如:Emp类
b、类名Dao:封装一些方法,完成对员工数据的增删改查 EmpDao
一般情况下,一个table对应一个类,一个Dao
3、页面
emp_list.jsp
搭建:
org.e2learning.domain//存放类
org.e2learning.dao//存放操作数据库的类
需求:
员工列表
----------------------- |
|姓名 id salary |
| |
| |
| |
| |
|上一页 2 下一页
----------------------- |
|姓名 id salary |
| |
| |
| |
| |
|上一页 2 下一页
jsp页面
emp_list
emp_list
浏览器 jsp DAO
| ——〉 | 方法 | 获得第一页的数据
| |————〉 |
| <—— | |
| ——〉 | | 再次发请求,必须显示哪一页n的请求
| |————〉 |方法n
| <—— | |
| | |
| | |隐含存在一个返回一个总的页数
| | |
| | |
| ——〉 | 方法 | 获得第一页的数据
| |————〉 |
| <—— | |
| ——〉 | | 再次发请求,必须显示哪一页n的请求
| |————〉 |方法n
| <—— | |
| | |
| | |隐含存在一个返回一个总的页数
| | |
| | |
13、构建一个工具类,通过properties类来将数据库的连接导入
dbo.properties
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.0.20:1521:test1
user=scott
password=tiger
url=jdbc:oracle:thin:@192.168.0.20:1521:test1
user=scott
password=tiger
thin:
连接数据库的这一端不用oracle的任何组件
连接数据库的这一端不用oracle的任何组件
package org.whatisjava.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class ConnectionUtils {
private static String driver;
private static String url;
private static String user;
private static String password;
// Class.forName("");
// Connection con=DriverManager.getConnection("","","");
// //一般情况下,我们会把数据库等的驱动,用户名密码等写到一个配置文件中
// //数据结构比较简单用属性文件,比较复杂的话用xml
private static String driver;
private static String url;
private static String user;
private static String password;
// Class.forName("");
// Connection con=DriverManager.getConnection("","","");
// //一般情况下,我们会把数据库等的驱动,用户名密码等写到一个配置文件中
// //数据结构比较简单用属性文件,比较复杂的话用xml
static {
//静态块初始化这些属性
try {
Properties props = new Properties();
//Properites类
//props.load(new FileInputStream("c:/db.properties"));//难点
//在这里开发,在这里运行。以后开发的时候,这里开发,放到其它服务器上安装
//在这里不要用文件流了。按照下面的方式
//放到src下面的非java文件都会copy到classes目录下
//java虚拟机可以提供一种机制,可以把classes下面的所有文件装载。如下
//像以前学的hibernate
//按照java反射
props.load(ConnectionUtils.class.getClassLoader()
.getResourceAsStream("org/whatisjava/dao/db.properties"));
//静态块初始化这些属性
try {
Properties props = new Properties();
//Properites类
//props.load(new FileInputStream("c:/db.properties"));//难点
//在这里开发,在这里运行。以后开发的时候,这里开发,放到其它服务器上安装
//在这里不要用文件流了。按照下面的方式
//放到src下面的非java文件都会copy到classes目录下
//java虚拟机可以提供一种机制,可以把classes下面的所有文件装载。如下
//像以前学的hibernate
//按照java反射
props.load(ConnectionUtils.class.getClassLoader()
.getResourceAsStream("org/whatisjava/dao/db.properties"));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
}
}
}
public static Connection getConnection() throws SQLException {
Connection con = DriverManager.getConnection(url, user, password);
return con;
}
}
Connection con = DriverManager.getConnection(url, user, password);
return con;
}
}
14、我们接下来看下EmpDao是怎么写的?
package org.whatisjava.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.whatisjava.domain.Emp;
public class EmpDao {
private static final String getEmpList =
"select empno, ename, sal from(select empno,ename,sal, " +
"rownum num from emp where rownum<?) where num>=?";
//SQL里面的分页技术
//select empno,enmae,sal from emp where rownum<=20
//rownum使用<号是没有问题的。使用〉号会出现问题
//rownum是数据先查询出来,再进行的rownum编号
//
//select empno,ename,sal from(select empno,ename,sal,rownum num from emp where rownum<?) where num>=?
//问题:我要对工资进行排序之后再分页
//要搞清楚先order by还是先rownum,
//也可以用hibernate的分页查询
public List<Emp> getEmpList(int page, int rowsPerPage) throws SQLException {
//返回参数
//首先要获得连接,用刚才写得类
Connection con = ConnectionUtils.getConnection();
PreparedStatement stmt = con.prepareStatement(getEmpList);
//计算公式可以按照实际的来进行计算
int start = (page - 1) * rowsPerPage + 1;
int end = start + rowsPerPage;
private static final String getEmpList =
"select empno, ename, sal from(select empno,ename,sal, " +
"rownum num from emp where rownum<?) where num>=?";
//SQL里面的分页技术
//select empno,enmae,sal from emp where rownum<=20
//rownum使用<号是没有问题的。使用〉号会出现问题
//rownum是数据先查询出来,再进行的rownum编号
//
//select empno,ename,sal from(select empno,ename,sal,rownum num from emp where rownum<?) where num>=?
//问题:我要对工资进行排序之后再分页
//要搞清楚先order by还是先rownum,
//也可以用hibernate的分页查询
public List<Emp> getEmpList(int page, int rowsPerPage) throws SQLException {
//返回参数
//首先要获得连接,用刚才写得类
Connection con = ConnectionUtils.getConnection();
PreparedStatement stmt = con.prepareStatement(getEmpList);
//计算公式可以按照实际的来进行计算
int start = (page - 1) * rowsPerPage + 1;
int end = start + rowsPerPage;
//
stmt.setInt(1, end);
stmt.setInt(2, start);
ResultSet rs = stmt.executeQuery();
ArrayList empList = new ArrayList();
while (rs.next()) {
Emp emp = new Emp();
emp.setId(rs.getInt(1));
emp.setName(rs.getString(2));
emp.setSalary(rs.getDouble(3));
empList.add(emp);
}
return empList;
}
while (rs.next()) {
Emp emp = new Emp();
emp.setId(rs.getInt(1));
emp.setName(rs.getString(2));
emp.setSalary(rs.getDouble(3));
empList.add(emp);
}
return empList;
}
public int getTotalPages(int rowsPerPage) {
//每一页有多少行的情况下,返回多少页
return 0;
}
}
15、Oracle中ROWNUM伪列
重点: rownum是在结果集上增加的一列
**********************************************************************************************
ORACLE 中ROWNUM用法总结!(来源于网络)
对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<、<=、!=),
并非说用>,>=,=,between..and 时会提示SQL语法错误,而是经常是查不出一条记录来,还会出现似乎是莫
名其妙的结果来,其实您只要理解好了这个 rownum 伪列的意义就不应该感到惊奇,同样是伪列,rownum
与 rowid 可有些不一样,下面以例子说明
ORACLE 中ROWNUM用法总结!(来源于网络)
对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<、<=、!=),
并非说用>,>=,=,between..and 时会提示SQL语法错误,而是经常是查不出一条记录来,还会出现似乎是莫
名其妙的结果来,其实您只要理解好了这个 rownum 伪列的意义就不应该感到惊奇,同样是伪列,rownum
与 rowid 可有些不一样,下面以例子说明
假设某个表 t1(c1) 有 20 条记录
如果用 select rownum,c1 from t1 where rownum < 10, 只要是用小于号,查出来的结果很容易地与一般
理解在概念上能达成一致,应该不会有任何疑问的。
理解在概念上能达成一致,应该不会有任何疑问的。
可如果用 select rownum,c1 from t1 where rownum > 10 (如果写下这样的查询语句,这时候在您的头脑
中应该是想得到表中后面10条记录),你就会发现,显示出来的结果要让您失望了,也许您还会怀疑是不谁
删了一些记录,然后查看记录数,仍然是 20 条啊?那问题是出在哪呢?
中应该是想得到表中后面10条记录),你就会发现,显示出来的结果要让您失望了,也许您还会怀疑是不谁
删了一些记录,然后查看记录数,仍然是 20 条啊?那问题是出在哪呢?
先好好理解 rownum 的意义吧。因为ROWNUM是对结果集加的一个伪列,即先查到结果集之后再加上去的一
个列 (强调:先要有结果集)。简单的说 rownum 是对符合条件结果的序列号。它总是从1开始排起的。所以
你选出的结果不可能没有1,而有其他大于1的值。所以您没办法期望得到下面的结果集:
个列 (强调:先要有结果集)。简单的说 rownum 是对符合条件结果的序列号。它总是从1开始排起的。所以
你选出的结果不可能没有1,而有其他大于1的值。所以您没办法期望得到下面的结果集:
11 aaaaaaaa
12 bbbbbbb
13 ccccccc
.................
12 bbbbbbb
13 ccccccc
.................
rownum >10 没有记录,因为第一条不满足去掉的话,第二条的ROWNUM又成了1,所以永远没有满足条件的记录。
或者可以这样理解:
或者可以这样理解:
ROWNUM是一个序列,是oracle数据库从数据文件或缓冲区中读取数据的顺序。它取得第一条记录则rownum值为1,
第二条为2,依次类推。如果你用>,>=,=,between...and这些条件,因为从缓冲区或数据文件中得到的第一条记
录的rownum为1,则被删除,接着取下条,可是它的rownum还是1,又被删除,依次类推,便没有了数据。
第二条为2,依次类推。如果你用>,>=,=,between...and这些条件,因为从缓冲区或数据文件中得到的第一条记
录的rownum为1,则被删除,接着取下条,可是它的rownum还是1,又被删除,依次类推,便没有了数据。
有了以上从不同方面建立起来的对 rownum 的概念,那我们可以来认识使用 rownum 的几种现象
select rownum,c1 from t1 where rownum != 10 为何是返回前9条数据呢?它与 select rownum,c1 from
tablename where rownum < 10 返回的结果集是一样的呢?
因为是在查询到结果集后,显示完第 9 条记录后,之后的记录也都是 != 10,或者 >=10,所以只显示前面9条记录。
也可以这样理解,rownum 为9后的记录的 rownum为10,因条件为 !=10,所以去掉,其后记录补上,rownum又是10,
也去掉,如果下去也就只会显示前面9条记录了
tablename where rownum < 10 返回的结果集是一样的呢?
因为是在查询到结果集后,显示完第 9 条记录后,之后的记录也都是 != 10,或者 >=10,所以只显示前面9条记录。
也可以这样理解,rownum 为9后的记录的 rownum为10,因条件为 !=10,所以去掉,其后记录补上,rownum又是10,
也去掉,如果下去也就只会显示前面9条记录了
为什么 rownum >1 时查不到一条记录,而 rownum >0 或 rownum >=1 却总显示所以的记录
因为 rownum 是在查询到的结果集后加上去的,它总是从1开始
因为 rownum 是在查询到的结果集后加上去的,它总是从1开始
为什么 between 1 and 10 或者 between 0 and 10 能查到结果,而用 between 2 and 10 却得不到结果
原因同上一样,因为 rownum 总是从 1 开始
原因同上一样,因为 rownum 总是从 1 开始
从上可以看出,任何时候想把 rownum = 1 这条记录抛弃是不对的,它在结果集中是不可或缺的,少了rownum=1
就像空中楼阁一般不能存在,所以你的 rownum 条件要包含到 1
就像空中楼阁一般不能存在,所以你的 rownum 条件要包含到 1
但如果就是想要用 rownum > 10 这种条件的话话就要用嵌套语句,把 rownum 先生成,然后对他进行查询。
select *
from (selet rownum as rn,t1.* from a where ...)
where rn >10
select *
from (selet rownum as rn,t1.* from a where ...)
where rn >10
一般代码中对结果集进行分页就是这么干的。
另外:rowid 与 rownum 虽都被称为伪列,但它们的存在方式是不一样的,rowid 可以说是物理存在的,表示记录在
表空间中的唯一位置ID,在DB中唯一。只要记录没被搬动过,rowid是不变的。rowid 相对于表来说又像表中的一般列,
所以以 rowid 为条件就不会有 rownum那些情况发生。
另外还要注意:rownum不能以任何基表的名称作为前缀。
表空间中的唯一位置ID,在DB中唯一。只要记录没被搬动过,rowid是不变的。rowid 相对于表来说又像表中的一般列,
所以以 rowid 为条件就不会有 rownum那些情况发生。
另外还要注意:rownum不能以任何基表的名称作为前缀。
根据以上理解:
select empno,ename,sal from emp where rownum<=20 and rownum>11;//此语句有问题
select empno,ename,sal from(select empno,ename,sal,rownum num from emp where rownnum<20)
where num>11;
where num>11;