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;
本文由用戶 honghu79 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!