什么是JDBC? Java語(yǔ)言訪問(wèn)數(shù)據(jù)庫(kù)的一種規(guī)范,是一套API JDBC (Java Database Connectivity) API,即Java數(shù)據(jù)庫(kù)編程接口,是一組標(biāo)準(zhǔn)的Java語(yǔ)言中的接口和類(lèi),使用這些接口和類(lèi),Java客戶(hù)端程序可以訪問(wèn)各種不同類(lèi)型的數(shù)據(jù)庫(kù)。比如建立數(shù)據(jù)庫(kù)連接、執(zhí)行SQL語(yǔ)句進(jìn)行數(shù)據(jù)的存取操作。
JDBC規(guī)范采用接口和實(shí)現(xiàn)分離的思想設(shè)計(jì)了Java數(shù)據(jù)庫(kù)編程的框架。接口包含在java.sql及javax.sql包中,其中java.sql屬于JavaSE,javax.sql屬于JavaEE。這些接口的實(shí)現(xiàn)類(lèi)叫做數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序,由數(shù)據(jù)庫(kù)的廠商或其它的廠商或個(gè)人提供。
為了使客戶(hù)端程序獨(dú)立于特定的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序,JDBC規(guī)范建議開(kāi)發(fā)者使用基于接口的編程方式,即盡量使應(yīng)用僅依賴(lài)java.sql及javax.sql中的接口和類(lèi)。
JDBC驅(qū)動(dòng)程序: 什么是JDBC驅(qū)動(dòng)程序? 這些是各個(gè)數(shù)據(jù)庫(kù)廠家根據(jù)JDBC的規(guī)范制作的JDBC實(shí)現(xiàn)類(lèi) JDBC驅(qū)動(dòng)程序的四種類(lèi)型: 1. 第一種類(lèi)型的驅(qū)動(dòng)程序的實(shí)現(xiàn)是通過(guò)將JDBC的調(diào)用全部委托給其它編程接口來(lái)實(shí)現(xiàn)的,比如ODBC。這種類(lèi)型的驅(qū)動(dòng)程序需要安裝本地代碼庫(kù),即依賴(lài)于本地的程序,所以便攜性較差。比如JDBC-ODBC橋驅(qū)動(dòng)程序 2. 第二種類(lèi)型的驅(qū)動(dòng)程序的實(shí)現(xiàn)是部分基于Java語(yǔ)言的。即該驅(qū)動(dòng)程序一部分是用Java語(yǔ)言編寫(xiě),其它部分委托本地的數(shù)據(jù)庫(kù)的客戶(hù)端代碼來(lái)實(shí)現(xiàn)。同類(lèi)型1的驅(qū)動(dòng)一樣,該類(lèi)型的驅(qū)動(dòng)程序也依賴(lài)本地的程序,所以便攜性較差 3. 第三種類(lèi)型的驅(qū)動(dòng)程序的實(shí)現(xiàn)是全部基于JAVA語(yǔ)言的。該類(lèi)型的驅(qū)動(dòng)程序通常由某個(gè)中間件服務(wù)器提供,這樣客戶(hù)端程序可以使用數(shù)據(jù)庫(kù)無(wú)關(guān)的協(xié)議和中間件服務(wù)器進(jìn)行通信,中間件服務(wù)器再將客戶(hù)端的JDBC調(diào)用轉(zhuǎn)發(fā)給數(shù)據(jù)庫(kù)進(jìn)行處理 4. 第四種類(lèi)型的驅(qū)動(dòng)程序的實(shí)現(xiàn)是全部基于JAVA語(yǔ)言的。該類(lèi)型的驅(qū)動(dòng)程序中包含了特定數(shù)據(jù)庫(kù)的訪問(wèn)協(xié)議,使得客戶(hù)端可以直接和數(shù)據(jù)庫(kù)進(jìn)行通信
JDBC類(lèi)結(jié)構(gòu): DriverManager
Driver Driver
Connection Connection
Statement Statement
Resultset Resultset
DriverManager:這個(gè)是一個(gè)實(shí)現(xiàn)類(lèi),它是一個(gè)工廠類(lèi),用來(lái)生產(chǎn)Driver對(duì)象的 這個(gè)類(lèi)的結(jié)構(gòu)設(shè)計(jì)模式為工廠方法 Driver:這是驅(qū)動(dòng)程序?qū)ο蟮慕涌?/span>,它指向一個(gè)實(shí)實(shí)在在的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序?qū)ο?/span>,那么這個(gè)數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序?qū)ο笫菑哪睦飦?lái)的呢? DriverManager工廠中有個(gè)方法:getDriver(String URL),通過(guò)這個(gè)方法可以得到驅(qū)動(dòng)程序?qū)ο?/span>,這個(gè)方法是在各個(gè)數(shù)據(jù)庫(kù)廠商按JDBC規(guī)范設(shè)計(jì)的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序包里的類(lèi)中靜態(tài)實(shí)現(xiàn)的,也就是在靜態(tài)塊中 Connection:這個(gè)接口可以制向一個(gè)數(shù)據(jù)庫(kù)連接對(duì)象,那么如何得到這個(gè)連接對(duì)象呢? 是通過(guò)DriverManager工廠中的getConnection(String URL)方法得到的 Statement:用于執(zhí)行靜態(tài)的SQL語(yǔ)句的接口,通過(guò)Connection中的createStatement方法得到的 Resultset:用于指向結(jié)果集對(duì)象的接口,結(jié)果集對(duì)象是通過(guò)Statement中的execute等方法得到的
JAVA使用JDBC訪問(wèn)數(shù)據(jù)庫(kù)的步驟: 1. 得到數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序 2. 創(chuàng)建數(shù)據(jù)庫(kù)連接 3. 執(zhí)行SQL語(yǔ)句 4. 得到結(jié)果集 5. 對(duì)結(jié)果集做相應(yīng)的處理(增,刪,改,查) 6. 關(guān)閉資源:這里釋放的是DB中的資源
設(shè)置classpath: 1. 在java文件中起的包名一定要是工程基目錄下的子目錄,classpath:基目錄 2. .jar包,需要將這個(gè).jar包的路徑包括這個(gè)文件的全名添加到classpath中來(lái) Oracle連接字符串的書(shū)寫(xiě)格式: “oracle:jdbc:thin:@ip:1521: 數(shù)據(jù)庫(kù)名”,”數(shù)據(jù)庫(kù)用戶(hù)名”,”數(shù)據(jù)庫(kù)密碼”
簡(jiǎn)單的例子: package moudule1.first;
import java.sql.*;
public class FirstJdbc { public static void main(String[] args) { String sql="select * from yuchen_user"; Connection con=null; Statement st=null; ResultSet rs=null;
try { Class.forName("oracle.jdbc.driver.OracleDriver"); con=DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:name", "scott","tiger"); st=con.createStatement(); rs=st.executeQuery(sql); while(rs.next()) { System.out.println(rs.getInt("id")); System.out.println(rs.getString("name")); } }catch(Exception e) { e.printStackTrace(); }finally { try { con.close(); }catch(Exception e) {}
try { st.close(); }catch(Exception e) { }
try { rs.close(); }catch(Exception e) { }
}
}
}
常用數(shù)據(jù)庫(kù)的驅(qū)動(dòng)程序及JDBC URL: Oracle數(shù)據(jù)庫(kù): 驅(qū)動(dòng)程序包名:ojdbc14.jar 驅(qū)動(dòng)類(lèi)的名字:oracle.jdbc.driver.OracleDriver JDBC URL:jdbc:oracle:thin:@dbip:port:databasename 說(shuō)明:驅(qū)動(dòng)程序包名有可能會(huì)變 JDBC URL中黑色字體部分必須原封不動(dòng)的保留,為該驅(qū)動(dòng)識(shí)別的URL格式。紅色字體部分需要根據(jù)數(shù)據(jù)庫(kù)的安裝情況填寫(xiě)。其中各個(gè)部分含義如下: dbip –為數(shù)據(jù)庫(kù)服務(wù)器的IP地址,如果是本地可寫(xiě):localhost或127.0.0.1。 port –為數(shù)據(jù)庫(kù)的監(jiān)聽(tīng)端口,需要看安裝時(shí)的配置,缺省為1521。 databasename –為數(shù)據(jù)庫(kù)的SID,通常為全局?jǐn)?shù)據(jù)庫(kù)的名字。 舉例如果要訪問(wèn)本地的數(shù)據(jù)庫(kù)allandb,端口1521,那么URL寫(xiě)法如下: jdbc:oracle:thin:@localhost:1521:allandb 下載地址如下: http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html
SQL Server數(shù)據(jù)庫(kù) 驅(qū)動(dòng)程序包名:msbase.jar mssqlserver.jar msutil.jar 驅(qū)動(dòng)類(lèi)的名字:com.microsoft.jdbc.sqlserver.SQLServerDriver JDBC URL:jdbc:microsoft:sqlserver://dbip:port;DatabaseName=databasename 說(shuō)明:驅(qū)動(dòng)程序包名有可能會(huì)變 JDBC URL中黑色字體部分必須原封不動(dòng)的保留,為該驅(qū)動(dòng)識(shí)別的URL格式。紅色字體部需要根據(jù)數(shù)據(jù)庫(kù)的安裝情況填寫(xiě)。其中各個(gè)部分含義如下: dbip –為數(shù)據(jù)庫(kù)服務(wù)器的IP地址,如果是本地可寫(xiě):localhost或127.0.0.1。 port –為數(shù)據(jù)庫(kù)的監(jiān)聽(tīng)端口,需要看安裝時(shí)的配置,缺省為1433。 databasename –數(shù)據(jù)庫(kù)的名字。 舉例如果要訪問(wèn)本地的數(shù)據(jù)庫(kù)allandb,端口1433,那么URL寫(xiě)法如下: jdbc: microsoft: sqlserver:@localhost:1433; DatabaseName =allandb 下載地址:http://www.microsoft.com/downloads/details.aspx
MySQL數(shù)據(jù)庫(kù) 驅(qū)動(dòng)程序包名:mysql-connector-java-3.1.11-bin.jar 驅(qū)動(dòng)類(lèi)的名字:com.mysql.jdbc.Driver JDBC URL:jdbc:mysql://dbip:port/databasename 說(shuō)明:驅(qū)動(dòng)程序包名有可能會(huì)變 JDBC URL中黑色字體部分必須原封不動(dòng)的保留,為該驅(qū)動(dòng)識(shí)別的URL格式。紅色字體部需要根據(jù)數(shù)據(jù)庫(kù)的安裝情況填寫(xiě)。其中各個(gè)部分含義如下: dbip –為數(shù)據(jù)庫(kù)服務(wù)器的IP地址,如果是本地可寫(xiě):localhost或127.0.0.1。 port –為數(shù)據(jù)庫(kù)的監(jiān)聽(tīng)端口,需要看安裝時(shí)的配置,缺省為3306。 databasename –數(shù)據(jù)庫(kù)的名字。 舉例如果要訪問(wèn)本地的數(shù)據(jù)庫(kù)allandb,端口1433,那么URL寫(xiě)法如下: jdbc:mysql://localhost:3306/allandb 下載地址:http://dev./downloads/connector/j/
Access數(shù)據(jù)庫(kù) 驅(qū)動(dòng)程序包名:該驅(qū)動(dòng)程序包含在JavaSE中,不需要額外安裝。 驅(qū)動(dòng)類(lèi)的名字:sun.jdbc.odbc.JdbcOdbcDriver JDBC URL:jdbc:odbc:datasourcename 說(shuō)明:該驅(qū)動(dòng)只能工作在Windows系統(tǒng)中,首先需要在操作系統(tǒng)中建立一個(gè)可以訪問(wèn)Access數(shù)據(jù)庫(kù)的本地?cái)?shù)據(jù)源(ODBC),如果名字為allandb,那么URL寫(xiě)法如下: jdbc:odbc:allandb
PreparedStatement接口: 預(yù)編譯的sql語(yǔ)句對(duì)象 作用: 解決了書(shū)寫(xiě)sql語(yǔ)句時(shí)一些特殊的字符與sql保留字符沖突的問(wèn)題,非常方便 /** *知識(shí)點(diǎn): *PreparedStatement接口及方法的使用 *程序目標(biāo): *java文件: *PreparedInsert.java:連接數(shù)據(jù)庫(kù),插入一條數(shù)據(jù) *JdbcUtil.java:實(shí)現(xiàn)一個(gè)工具類(lèi),功能:1.連接數(shù)據(jù)庫(kù) 2.關(guān)閉資源 */
package moudule1.preparedstatement;
import java.sql.*; import moudule1.com.*;
public class PreparedInsert { public static void main(String[] args) { String sql="insert into yuchen_user (id,name) values (?,?)"; System.out.println(sql);
Connection con=null; PreparedStatement ps=null;
try{ con=JdbcUtil.getConnection(); ps=con.prepareStatement(sql);
ps.setInt(1,2); ps.setString(2,"zhangsan"); ps.executeUpdate();
ps.setInt(1,3); ps.setString(2,"lisi"); ps.executeUpdate();
}catch(Exception e){ e.printStackTrace(); }finally{ JdbcUtil.close(con,ps); } } }
package moudule1.com;
import java.sql.*;
public class JdbcUtil{
public static Connection getConnection() throws Exception{ Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:name", "scott","tiger"); }
public static void close(Connection con,Statement st){
close(con); close(st);
}
public static void close(Connection con,Statement st,ResultSet rs){
close(con,st); close(rs);
}
public static void close(Connection con){ try{
con.close();
}catch(Exception e){
}
}
public static void close(Statement st){
try{
st.close();
}catch(Exception e){
} }
public static void close(ResultSet rs){
try{
rs.close();
}catch(Exception e){
}
}
}
數(shù)據(jù)庫(kù)的增刪改查的例子: /** *知識(shí)點(diǎn): *JDBC+SQL+ORACLE *程序目標(biāo): *UserDao.java:實(shí)現(xiàn)了數(shù)據(jù)庫(kù)的增刪改查 *JdbcUtil.java:工具類(lèi),有連庫(kù)和關(guān)閉資源的方法 */
package moudule1.idus;
import java.sql.*; import moudule1.com.*;
public class UserDao{
private String sql; private Connection con; private Statement st; private ResultSet rs;
public UserDao(){ sql=null; con=null; st=null; rs=null; }
public void insert(){
sql="insert into yuchen_user (id,name) values("; sql+="4,‘zhouwu‘)"; System.out.println(sql);
try{
con=JdbcUtil.getConnection(); st=con.createStatement(); st.executeUpdate(sql);
}catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.close(con,st);
}
}
public void delete(){
sql="delete from yuchen_user where id=2"; System.out.println(sql);
try{
con=JdbcUtil.getConnection(); st=con.createStatement(); st.executeUpdate(sql);
}catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.close(con,st);
} }
public void update(){
sql="update yuchen_user set name=‘liumang‘ where id=1"; System.out.println(sql);
try{
con=JdbcUtil.getConnection(); st=con.createStatement(); st.executeUpdate(sql);
}catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.close(con,st);
} }
public void select(){
sql="select * from yuchen_user"; System.out.println(sql);
try{
con=JdbcUtil.getConnection(); st=con.createStatement(); rs=st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getInt(1)); System.out.println(rs.getString(2));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.close(con,st,rs);
}
}
public static void main(String[] args){
UserDao ud=new UserDao(); ud.select(); ud.insert(); ud.select(); ud.update(); ud.select(); ud.delete(); ud.select(); } }
一些常用的方法: /** *知識(shí)點(diǎn): *execute方法,getResultSet(),getUpdateCount() *程序目標(biāo): *JdbcUtil.java:工具類(lèi),連接數(shù)據(jù)庫(kù),關(guān)閉資源 *sqlExecutor.java:命令行參數(shù)輸入sql語(yǔ)句,并執(zhí)行該語(yǔ)句 */ package moudule1.fangfa;
import java.sql.*; import moudule1.com.*;
public class sqlExecutor{
public static void main(String[] args){
Connection con=null; Statement st=null;
try{
con=JdbcUtil.getConnection(); st=con.createStatement(); boolean str=st.execute(args[0]);
if(str){
ResultSet rs=st.getResultSet();
while(rs.next()){ System.out.println(rs.getInt("id")+":"+rs.getString("name")); }
rs.close();
}else{ int row=st.getUpdateCount(); System.out.println(row); }
}catch(Exception e){
e.printStackTrace();
}finally{
JdbcUtil.close(con,st);
} } } 2. 補(bǔ)充 加載及注冊(cè)JDBC驅(qū)動(dòng)程序 Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver").newInstance(); JDBC URL 定義驅(qū)動(dòng)程序與數(shù)據(jù)源之間的連接 標(biāo)準(zhǔn)語(yǔ)法: <protocol(主要通訊協(xié)議)>:<subprotocol(次要通訊協(xié)議,即驅(qū)動(dòng)程序名稱(chēng))>:<data source identifier(數(shù)據(jù)源)> MySQL的JDBC URL格式: jdbc:mysql//[hostname][:port]/[dbname][?param1=value1][¶m2=value2]….
示例:jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password
常見(jiàn)參數(shù): user 用戶(hù)名 password 密碼 autoReconnect 聯(lián)機(jī)失敗,是否重新聯(lián)機(jī)(true/false) maxReconnect 嘗試重新聯(lián)機(jī)次數(shù) initialTimeout 嘗試重新聯(lián)機(jī)間隔 maxRows 傳回最大行數(shù) useUnicode 是否使用Unicode字體編碼(true/false) characterEncoding 何種編碼(GB2312/UTF-8/…) relaxAutocommit 是否自動(dòng)提交(true/false) capitalizeTypeNames 數(shù)據(jù)定義的名稱(chēng)以大寫(xiě)表示 建立連接對(duì)象 String url="jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password"; Connection con = DriverManager.getConnection(url); 建立SQL陳述式對(duì)象(Statement Object) Statement stmt = con.createStatement(); 執(zhí)行SQL語(yǔ)句 executeQuery() String query = "select * from test"; ResultSet rs=stmt.executeQuery(query); 結(jié)果集ResultSet while(rs.next()) {rs.getString(1);rs.getInt(2);} executeUpdate() String upd="insert into test (id,name) values(1001,xuzhaori)"; int con=stmt.executeUpdate(upd); execute() 示例: try{ catch(SQLException sqle) { } finally { }
Java類(lèi)型和SQL類(lèi)型 技術(shù)手冊(cè)P421 PreparedStatement(預(yù)編語(yǔ)句) PreparedStatement stmt = conn.prepareStatement("insert into test(id,name)values(?,?)"); stmt.setInt(1,id); stmt.setString(2,name); 注:一旦設(shè)定語(yǔ)句的參數(shù)值后,就可以多次執(zhí)行改語(yǔ)句,直到調(diào)用clearParameters()方法將他清除為止 CallableStatement(預(yù)儲(chǔ)程序)技術(shù)手冊(cè)P430 JDBC2.0使用 ResultSet對(duì)象中的光標(biāo)上下自由移動(dòng) Statement stmt = con.createStatement (ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet rs=stmt.executeQuery("select * from test");
public Statement createStatement(int resultSetType,int resultSetConcuttency) throws SQLException
resultSetType TYPE_FORWARD_ONLY 只能使用next()方法。 TYPE_SCROLL_SENSITIVE 可以上下移動(dòng),可以取得改變后的值。 TYPE_SCROLL_INSENSITIVE 可以上下移動(dòng)。 resultSetConcuttency CONCUR_READ_ONLY 只讀 CONCUR_UPDATABLE ResultSet對(duì)象可以執(zhí)行數(shù)據(jù)庫(kù)的新增、修改、和移除
直接使用ResultSet對(duì)象執(zhí)行更新數(shù)據(jù) 新增數(shù)據(jù) Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE); ResultSet uprs=stmt.executeQuery("select * from test"); uprs.moveToInsertRow(); uprs.updateInt(1,1001); uprs.updateString(2,"許召日"); uprs.insertRow; 更新數(shù)據(jù) Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE); ResultSet uprs=stmt.executeQuery("select * from test"); uprs.last(); uprs.updateString("name","xuzhaori"); uprs.updateRow; 刪除數(shù)據(jù) Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_PUDATABLE); ResultSet uprs=stmt.executeQuery("select * from test"); uprs.absolute(4); uprs.deleteRow();
批處理 con.setAutoCommit(false); 關(guān)閉自動(dòng)認(rèn)可模式 Statement stmt=con.createStatement(); int[] rows; stmt.addBatch("insert into test values(1001,xuzhaori)"); stmt.addBatch("insert into test values(1002,xuyalin)"); rows=stmt.executeBatch(); con.commit(); 沒(méi)有任何錯(cuò)誤,執(zhí)行批處理stmt.executeBatch();
JNDI-數(shù)據(jù)源(Data Source)與連接池(Connection Pool) Tomcat的JDBC數(shù)據(jù)源設(shè)置 技術(shù)手冊(cè)P439 連接池工具-Proxool Var 0.8.3 技術(shù)手冊(cè)P446 設(shè)置web.xml <?xml version="1.0" encoding="ISO-8859-1"?> <!--<?xml version="1.0" encoding="GB2312"?>-->
<web-app xmlns="http://java./xml/ns/j2ee" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://java./xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> …. <servlet> <servlet-name>ServletConfigurator</servlet-name> <servlet-class>org.logicalcobwebs.proxool.configuration.ServletConfigurator</servlet-class>
<init-param> <param-name>propertyFile</param-name> <param-value>WEB-INF/classes/Proxool.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> 后端統(tǒng)計(jì)端口添加下列 <servlet> <servlet-name>Admin</servlet-name> <servlet-class>org.logicalcobwebs.proxool.admin.servlet.AdminServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>Admin</servlet-name> <url-pattern>/Admin</url-pattern> </servlet-mapping>
….
</web-app>
配置Proxool.properties jdbc-0.proxool.alias=JSPBook jdbc-0.proxool.driver-class=com.mysql.jdbc.Driver jdbc-0.proxool.driver-url=jdbc:mysql://localhost:3306/sample_db?user=root&password=browser&useUnicode=true&characterEncoding=UTF-8 jdbc-0.proxool.maximum-connection-count=10 jdbc-0.proxool.prototype-count=4 jdbc-0.proxool.house-keeping-test-sql=select CURRENT_DATE jdbc-0.proxool.verbose=true jdbc-0.proxool.statistics=10s,1m,1d 后端統(tǒng)計(jì)接口添加此行 jdbc-0.proxool.statistics-log-level=DEBUG 使用Proxool連接池 Connection con = DriverManager.getConnection("proxool.JSPBook"); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); String query = "SELECT * FROM employee"; ResultSet rs = stmt.executeQuery(query); |
|
來(lái)自: 鳳舞天煌 > 《數(shù)據(jù)庫(kù)技術(shù)》