<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 78, comments - 34, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

         摘要: (轉自:http://hi.baidu.com/%C9%AE_%CC%C6/blog/item/9e2a8b0887008a8ad0581b3d.html) 這是轉載自一個兄弟的,寫的比較細致,受益頗多!我只是針對圖片進行了修改,使它看起來邏輯清晰一些。 十分感謝這位兄弟!        Java平臺提供了一個全新的集合框架。...  閱讀全文

    posted @ 2009-12-06 21:48 長城 閱讀(425) | 評論 (0)編輯 收藏

             今日學習的是在Oracle中使用簡單的查詢語句,與“2009-11-29傳智播客 數(shù)據(jù)庫——數(shù)據(jù)庫入門[mysql]”學習的內容差不多,不知寫些什么好了?,F(xiàn)在學習的都是單表查詢,后天應該就開始學習多表操作了。

     

             Oracle中有個虛擬表“DUAL”,說是虛擬,只是這個表不需要用戶創(chuàng)建。在數(shù)據(jù)庫里默認就有的,它有什么用途?用一句話概括一下:只是不是針對某表記錄的操作,就需要這個表來完成!比如,打印當前系統(tǒng)時間就需要:“select sysdate from dual”,但在MySQL等數(shù)據(jù)庫中確不需要這樣,在MySQL中直接使用“select now();”即可。

     

             今日老馮講解的Oracle函數(shù)比較簡單,但也讓我感覺到Oracle的強大。比如說有一個“decode”函數(shù),說是函數(shù)更像是“switch catch”語句。老馮有個例子,要按照職位給員工漲工資:

    SELECT   last_name,salary,

          decode(job_id,

              '總經(jīng)理',1.15*salary,

              '副總經(jīng)理',1.10*salary,

              salary)  工資

    FROM employees;

     

             可見它的強大了吧!下面列一下日期時間與文本互轉的格式和數(shù)字與文本互轉的格式:

    期日格式:

    格式控制符

    描述

    YYYY  YYY YY

    以數(shù)字表示全年(分別代表4位、三位、兩位)的數(shù)字年

    YEAR

    年的拼寫

    MM

    兩位數(shù)字月

    MONTH

    月的全拼

    MON

    月名稱的縮寫

    DD

    數(shù)字日

    DAY

    星期的全拼

    D

    星期中的第幾天 

    DY

    表示三位縮寫的星期

     

             注意:調用TO_DATE函數(shù)時,比如TO_DATE(“2009-12-05”,”yyyy-mm-dd”),其中第二個日期格式字符串必須與第一個參數(shù)的時間格式相同。

     

    數(shù)字格式控制符:

    數(shù)字格式控制符

    描述

    9

    代表一位數(shù)字,如果當前位有數(shù)字,顯示數(shù)字,否則不顯示(小數(shù)部分仍然會強制顯示)

    0

    強制顯示該位,如果當前位有數(shù)字,顯示數(shù)字,否則顯示0

    $

    增加美元符號顯示

    L

    增加本地貨幣符號顯示(RMB)

    .

    小數(shù)點符號

    ,

    千分位符號  3,000,000,000.00

     

             其他操作函數(shù),就去下載了個Oracle函數(shù)大全吧!操作數(shù)據(jù)庫這些語句,更多的就是練習了,練習的讓自己很容易記下來。

     

             來傳智播客學習的這段時間,讓我感覺很好,充實了很多。真是物有所值,也搞不懂那些教一些基礎知識加點高級內容的培訓機構卻要1萬多。而且還是遠程視頻授課!真是越垃圾的學校越貴,廣告做的真好!課間時,大家有與老馮談論起大連的軟件產(chǎn)業(yè)。只要做這行的都知道,大連的軟件產(chǎn)業(yè)外包是重點,而且這個城市是出了名的收入低消費高。這些到也罷。要命的是,給日本人干活,那真叫苦力!似乎一點動腦子的東西都不愿意讓你來做,做這種工作的人應該都不叫程序員吧。應該叫“打字”員,專門按照日本人寫的文檔來打代碼。如果這種工作在中國過多,還到那里去發(fā)展什么自己的核心競爭力啊!不過沒辦法,人家愿意出錢。也有聽說,日本人出的一個人月是2-3萬人民幣,但到程員手中卻只有3000-5000元。呵呵!

     

             無論如何,學習結束后我還是想回到大連。我喜歡那里!

    posted @ 2009-12-05 21:20 長城 閱讀(354) | 評論 (0)編輯 收藏

         摘要:          從今日起連結四天Oracle,由馮威老師授課。由于以前沒有接觸過Oracle數(shù)據(jù)庫,所以上午講解的Oraclae數(shù)據(jù)庫的一些專業(yè)名詞,讓我有點措手不及。不過沒關系,回家看一下就可以了。上午的內容比較枯燥,下午還好。下午講解在Oracle數(shù)據(jù)庫中使用SQL語句,這相對輕松些。SQL語句與前兩天學習的在M...  閱讀全文

    posted @ 2009-12-04 22:46 長城 閱讀(317) | 評論 (0)編輯 收藏

             我對IO流的理解上并沒什么問題,但前一片段上課時有經(jīng)常使用到IO流。發(fā)現(xiàn)自己對JAVAIO流沒有系統(tǒng)的概念,JAVAIO流的要類是InputStreamOutputStream,這兩個類的子類較多,而且還有一部分的包裝類。SO,我要對JAVAIO流有一個系統(tǒng)的學習。

    JAVA IO 全視圖:

    JAVAIO 

    InputStream部分:

             InputStream,它是一個抽象類,所示所有輸入流的的超類。它包含了輸入流的基本操作。

             AudioIntpuStream,音頻輸入流對應的輸出。結合AudioSystem可以實現(xiàn):

    1.        從外部音頻文件、流或 URL 獲得音頻輸入流

    2.        從音頻輸入流寫入外部文件

    3.        將音頻輸入流轉換為不同的音頻格式

    ByteArrayInputStream,字節(jié)數(shù)據(jù)輸入流。字面的翻譯。它包含了一個緩沖區(qū),該緩沖區(qū)從輸入游戲中讀取字節(jié)。因為數(shù)據(jù)已經(jīng)讀入到緩沖區(qū)中,所以關閉流對它無效,仍然可以調用它的方法而不會拋出異常。

    FileInputStream,文件輸入流。從文件中獲取輸入字節(jié),包含對文件流的特殊方法。如果要讀取字符流,可以使用FileReader。

    PipedInputStream,管道輸入流。用于線程間的通訊,但不要在同一個線程中使用管道輸入流和輸出流,這樣可能造成線程死鎖。

    SequenceInputStream,輸入流的邏輯串聯(lián)。它將多個輸入流串聯(lián)到一起讀取。比如它串聯(lián)了輸入流AB,當讀取到A的結尾時,便從B流中接著讀取。

    StringBufferInputStream,與ByteArrayInputSteam類同,ByteArrayInputStream用于處理字節(jié),而StringBufferInputStream用于處理字符。

    ObjectInputStream,Java對象輸入流。實現(xiàn)將對象從輸入流中讀取。比如將ObjectOutputStreamFileOutputStream結合使用,將JAVA對象序列化后保存到文件。然后再使用FileInputStreamObjectInputStream將文件中被序列化的JAVA對象反序列化回來到程序中。也可以在遠程通訊中使用對象流傳輸JAVA對象,這個比較高級。

    FilterInputStreamJDK幫助文檔中說它只是簡單的重寫將所有對輸入流的操作傳遞給它所包含的InputStream輸入流。嗯,其實它是一個Decorate模式的超類。從它繼承了一些子類,用于提供一些額外的功能,向下看。

             BufferedInputStream,對InputStream增加了緩存功能。以更好的支持markreset方法。

    CheckedInputStream,校驗輸入流??捎糜隍炞C輸入數(shù)據(jù)的完整性。與Checksum配合使用。

    CipherInputStream,解密輸入流。與Cipher配合使用。CipherOutputStream是加密輸出流。對數(shù)據(jù)進行加解密使用。

    DigestInputStream,摘要輸入流。這個比較少見,棱一看JDK手冊,不太了解。不過數(shù)據(jù)摘要是用于安全通訊或數(shù)據(jù)完整證驗證的。哦,它與MessageDigest配合使用,可見JAVA IO設計者的用心!

    LineNumberInputStream,行號輸入流。此類已過時。它假定輸入流是字符流,它調用InputStream的方法并將\n\r統(tǒng)一轉換成一個\n。每讀到一個換行時,便將行號加1,初始行號為0。此類不深入研究了!

    ProgressMonitor,進度監(jiān)視輸入流。用于監(jiān)視用戶讀取的進度,如果這個流很大。它會自動彈出進度提示窗口,用戶可以點擊“Cancel”按鈕,取消讀取。這個也實JAVAIO給實現(xiàn)了,比較人性化!

    PushBackInputStream,推回輸入流。就是可以將從輸入流中讀取的數(shù)據(jù),調用unread方法將數(shù)據(jù)推回到輸入流中,也可以將其他數(shù)據(jù)推進去。JDK手冊中舉了一個例子說,將標識符字符讀取后,可以推回到輸入然,然后重復讀取,在哪里需要這樣的應用呢?

    DataInputStream,數(shù)據(jù)輸入流??梢砸耘c機器無關方式從底層輸入流中讀取基本JAVA數(shù)據(jù)類型。

    InflaterInputStream 解壓縮輸入流。解壓縮以“deflate”壓縮格式的流過濾器。它與Inflater配合使用,Inflater使用流行的ZLIB壓縮庫。

             GZipInputStream,GZip解壓縮輸入流。解壓縮以“GZip”壓縮格式的流過濾器。

             ZipInputStreamZip解壓縮輸入流。解壓縮以“Zip”壓縮格式的流過濾器。

             JarInputStreamJar解壓縮輸入流。可以讀取Jar文件中的內容。其實Jar的壓縮格式就是Zip格式。但它比Zip多了一個Manifest條目。Manifest 可用于存儲有關 JAR 文件及其條目的元信息。關于Manifest,可以查看JDK手冊。

             OK,OutputStream在此就不一一列出了。因為OutpuStream中子類與InputStream中的子類相對應。但OutpuStream不完全具有與InputStream中的子類對應的類。因為沒必要,比如AudioInputStream,沒有與之對應的AudioOutputStream,我們需要讀取指定格式的音頻即可。如果想寫出音頻數(shù)據(jù)直接用FileOutputStream即可!        

             Java中還有WriterReader兩個超類,主要用于處理字符流,這個比較簡單就不在此做介紹了。OK!

    posted @ 2009-12-03 22:48 長城 閱讀(398) | 評論 (0)編輯 收藏

    JAVAIO

    posted @ 2009-12-03 16:22 長城 閱讀(275) | 評論 (0)編輯 收藏

    Today is JDBC高級部分,課程的主要內容有連接池與事務。這都是在應用開發(fā)中比較常用,比較重要的。

    一、使用配置文件優(yōu)化JDBCUtil,使用工廠模式隔離DAO層:

    昨天有說過將對數(shù)據(jù)庫獲取連接和釋放的操作單封裝到一個類中,如:

    import java.sql.*;
    import cn.itcast.cc.exception.JDBCUtilException;
    
    /**
     * JDBC工具類
     * 
     * @author Administrator
     * 
     */
    public class JDBCUtil {
    	// 連接數(shù)據(jù)庫時所需要的參數(shù)
    	private static String url = "jdbc:mysql://localhost:3306/jdbc";
    	private static String username = "root";
    	private static String password = "root";
    	// 類被加載時就加載驅動
    	static {
    		try {
    			Class.forName("com.mysql.jdbc.Driver");
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		}
    	}
    
    	// 獲取連接
    	public static Connection getConnection() throws JDBCUtilException {
    		try {
    			return DriverManager.getConnection(url, username, password);
    		} catch (SQLException e) {
    			throw new JDBCUtilException(e);
    		}
    	}
    
    	// 釋放連接等資源,下面是一種健康的釋放方式
    	public static void release(ResultSet rs, Statement sta, Connection conn)
    			throws JDBCUtilException {
    		if (rs != null) {
    			try {
    				rs.close();
    			} catch (SQLException e) {
    				throw new JDBCUtilException(e);
    			}
    			rs = null;
    		}
    
    		if (sta != null) {
    			try {
    				sta.close();
    			} catch (SQLException e) {
    				throw new JDBCUtilException(e);
    			}
    			sta = null;
    		}
    
    		if (conn != null) {
    			try {
    				conn.close();
    			} catch (SQLException e) {
    				throw new JDBCUtilException(e);
    			}
    			conn = null;
    		}
    	}
    }

    從上面我們看到其中裝載數(shù)據(jù)庫驅動和獲取數(shù)據(jù)庫連接的代碼:

    Class.forName("com.mysql.jdbc.Driver");

    DriverManager.getConnection(url, username, password);

    我們使用了固定的url,它是一個成員。在以后的開發(fā)中,如果要使用其他的數(shù)據(jù)庫或者數(shù)據(jù)庫的用戶名密碼被改變了,我們還需要手動的修改上邊的代碼,重新編譯。這是一種不良的設計方法,為了使我們的代碼與數(shù)據(jù)庫分離,我們可以將這些參數(shù)配置到配置文件中。這樣在需要使用時去讀取配置文件中的對應值即可。以后換數(shù)據(jù)庫或更改了用戶名,直接修改一下配置文件即可。

    昨天有提到過DAO層,DAO層專門用于處理對數(shù)據(jù)庫的CURD操作等,比如,添加用戶、查找用戶、修改用戶、刪除用戶,我們可以把這些操作封裝到一個類中(UserDao.java),它所處位置就是DAO層。比如,用于處理用戶注冊的Servlet,在這個Servlet中直接實例化一個UserDao對象。然后調用userDaoObj.add(userbean);方法即可實現(xiàn)用戶的注冊。

    如果我想換一種數(shù)據(jù)存儲方式,比如配置文件,我只將用戶信息保存在配置文件中。這樣我就需要修改UserDao.java,但有時又需要UserDao.java這個功能類怎么辦?我只能重新創(chuàng)建一個專門處理配置文件數(shù)據(jù)的類(UserDaoPro.java)。這樣我又需要修改Servlet中的代碼,將實例化UserDao的代碼修改為實例化UserDaoPro對象。那UserDaoPro與UserDao的接口是不是相同的呢?如果不相同麻煩就大了,JAVA是提倡使用接口編程的,就是為了實現(xiàn)接口的統(tǒng)一化。

    可見,上面的這種實現(xiàn)方式是存在問題的。即使接口統(tǒng)一,我們還需要修改Servlet中的代碼。此時工廠模式派上了用場,還記得工廠模式吧!是這樣的:

    1.定義一個UserDao接口,統(tǒng)一對用戶操作的接口。

    2.定義一個UserDaoFactory的工廠類,專門生產(chǎn)UserDao對象。

    3. UserDaoFactory工廠從配置文件中讀取實現(xiàn)了UserDao接口的類名稱。使用此類生產(chǎn)產(chǎn)品——UserDao對象。

    4.在Servlet中使用UserDaoFactory工廠來創(chuàng)建需要的UserDao對象。

    這樣就實現(xiàn)了DAO層與Servlet的完全分離!完美!

    二、數(shù)據(jù)庫連接池:

    每當有一個新的連接發(fā)生時,數(shù)據(jù)庫就需要創(chuàng)建一個Connection對象來處理連接。訪問結束后,Connection對象被釋放。數(shù)據(jù)庫創(chuàng)建一個Connection對象,是十分耗時且消耗較大的服務器資源。試想,如果有500個用戶同時訪問數(shù)據(jù)庫,數(shù)據(jù)庫同時創(chuàng)建500個Connection將會是什么樣子!因此,連接池這一技術誕生了。

    連接池,在服務器加載WEB應用后。WEB應用會自動創(chuàng)建一個連接池,池中包含多個Connection對象。每當有新的連接請求時,便從這個池中拿出一個Connection對象用于處理連接,使用完成后,便還回給這個池子。下面代碼為連接池的實現(xiàn)原理:

    import java.io.*;
    import java.lang.reflect.*;
    import java.sql.*;
    import java.util.*;
    import javax.sql.DataSource;
    
    /**
     * 自己編寫的簡單連接池類,單例模式實現(xiàn)。
     * 
     * @author Administrator
     * 
     */
    public class JDBCUtil implements DataSource {
    	private static LinkedList<Connection> conns = new LinkedList<Connection>();
    	private static JDBCUtil myjdbcutil = new JDBCUtil();
    
    	private JDBCUtil() {
    		// 取配置文件
    		InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream(
    				"cn/itcast/cc/db/myjdbc.properties");
    		// 裝載配置文件
    		Properties pro = new Properties();
    		try {
    			pro.load(in);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		// 取出配置項
    		String driver = pro.getProperty("driverClassName");
    		String url = pro.getProperty("url");
    		String username = pro.getProperty("username");
    		String password = pro.getProperty("password");
    		int initialSize = Integer.parseInt(pro.getProperty("initialSize"));
    		// 加載驅動,填充連接池
    		try {
    			// 常用的數(shù)據(jù)庫,驅動類被加載時,都會自已加載驅動。
    			Class.forName(driver);
    			for (int i = 0; i < initialSize; i++) {
    				conns.add(DriverManager.getConnection(url, username, password));
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	// 返回單例的實例
    	public static JDBCUtil getInstance() {
    		return myjdbcutil;
    	}
    
    	public Connection getConnection() throws SQLException {
    		if (conns.size() > 0) {
    			final Connection conn = conns.pop();
    			// 此處需要使用動態(tài)代理技術,因為返回的Connection對象在關閉時需要被收回到LinkedList中。
    			// 動態(tài)代理,增強Connection.colse()方法,將它回收到LinkedList中。但不銷毀!
    			return (Connection) Proxy.newProxyInstance(JDBCUtil.class
    					.getClassLoader(), conn.getClass().getInterfaces(),
    					new InvocationHandler() {
    
    						public Object invoke(Object proxy, Method method,
    								Object[] args) throws Throwable {
    							// 如果是close方法,則將conn回收到List中。
    							if (method.getName().equals("close")) {
    								conns.push(conn);
    								return null;
    							}
    							return method.invoke(conn, args);
    						}
    					});
    		}
    		throw new RuntimeException("服務器忙,請稍后連接!");
    	}
    }

    有很多服務器為用戶提供了DataSource(數(shù)據(jù)源)的實現(xiàn)。DataSource中包含了連接池的實現(xiàn)。也有一些第三方組織單獨提供了連接池的實現(xiàn):DBCP、C3P0。所以,在以后的開發(fā)中,我們可以直接使用這些資源。

    著名的DBCP比較常用,使用DBCP必須引入Commons-dbcp.jar和Commons-pool.jar。Tomcat中的連接池也是使用DBCP實現(xiàn)的。DBCP的使用非常簡單:

    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    import javax.sql.DataSource;
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    
    public class DBCPUtil {
    	private static DataSource ds = null;
    	static {
    		try {
    			// 取配置文件
    			InputStream in = JDBCUtil.class.getClassLoader()
    					.getResourceAsStream(
    							"cn/itcast/cc/db/dbcpconfig.properties");
    			// 裝載配置文件
    			Properties pro = new Properties();
    			pro.load(in);
    			// 創(chuàng)建數(shù)據(jù)源
    			ds = BasicDataSourceFactory.createDataSource(pro);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	// 獲取連接
    	public static Connection getConnection() throws SQLException {
    		return ds.getConnection();
    	}
    }

     

    其中的配置文件“dbcpconfig.properties”:

    #連接設置

    #驅動器

    driverClassName=com.mysql.jdbc.Driver

    #數(shù)據(jù)庫連接URL

    url=jdbc:mysql://localhost:3306/jdbc

    #數(shù)據(jù)庫用戶名

    username=root

    #數(shù)據(jù)庫密碼

    password=root

    #初始連接池數(shù)量

    initialSize=10

    #最大連接數(shù)量

    maxActive=50

    #最大空閑連接

    maxIdle=20

    #最小空閑連接

    minIdle=5

    #超時等待時間以毫秒為單位 6000毫秒/1000等于60秒

    maxWait=60000

    #JDBC驅動建立連接時附帶的連接屬性屬性的格式必須為這樣:[屬性名=property;]

    #注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這里不需要包含他們。

    connectionProperties=useUnicode=true;characterEncoding=UTF8

    #指定由連接池所創(chuàng)建的連接的自動提交(auto-commit)狀態(tài)。

    defaultAutoCommit=true

    #driver default 指定由連接池所創(chuàng)建的連接的只讀(read-only)狀態(tài)。

    #如果沒有設置該值,則“setReadOnly”方法將不被調用。(某些驅動并不支持只讀模式,如:Informix)

    defaultReadOnly=

    #driver default 指定由連接池所創(chuàng)建的連接的事務級別(TransactionIsolation)。

    #可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

    defaultTransactionIsolation=READ_UNCOMMITTED

    上面是直接使用Apache提供的DBCP實現(xiàn)的連接池,接下來看一下使用JNDI技術在Tomcat中配置連接池,在Tomcat服務的conf\context.xml文件中添加:

    <Context>

    <Resource name="jdbc/datasource" auth="Container"

    type="javax.sql.DataSource" username="root" password="root"

    driverClassName="com.mysql.jdbc.Driver"

    url="jdbc:mysql://localhost:3306/jdbc"

    maxActive="8" maxIdle="4"/>

    </Context>

    Name: 對象在JNDI容器中的名稱。

    Auth:所使用的容器。

    Type:對象類型。

    Username:數(shù)據(jù)庫用戶名。

    Password:數(shù)據(jù)庫密碼。

    driverClassName:數(shù)據(jù)庫驅動類。

    url:連接數(shù)據(jù)庫的URL。

    maxActive:最大連接數(shù)。

    maxIdle:最大空閑連接數(shù)。

    注意其中的數(shù)據(jù)庫驅動,對應的jar包必須放置到Tomcat目錄下的lib目錄中。這樣服務器才能找得到。

    在WEB應用中獲取數(shù)據(jù)庫連接的代碼:

    // 初始化JNDI環(huán)境

    Context initCtx = new InitialContext();

    // 獲取JNDI容器

    Context envCtx = (Context) initCtx.lookup("java:comp/env");

    // 獲取數(shù)據(jù)源

    DataSource dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

    // 獲取數(shù)據(jù)庫連接

    dataSource.getConnection();

    JNDI是一個對象容器,服務器根據(jù)配置文件提供的信息。創(chuàng)建這些對象,并按照指定的名稱保存在容器中。WEB應用,無論在何處都可以根據(jù)名稱獲取在JNDI容器中的對象。

    三、數(shù)據(jù)庫事務管理:

    什么是事務?老方有這樣的面試題。事務指邏輯上的一組操作,這組操作要不全部生效,要不全部失效。在控制臺中操作事務的命令:

    start transaction 開啟事務

    Rollback 回滾事務

    Commit 提交事務

    set transction isolation level 設置事務隔離級別

    select @@tx_isolation 查詢當前事務隔離級別

    事務的特性(ACID),這在面試中是比較常見的。老方一再強調,一定要記下來!OK,讓我們看一看。

    事務的原子性(Automicity),它更像是事務的定義。就是邏輯上的一組操作,不可分割,要么全部生效,要么全部失效。

    事務的一致性(Consistency),老方的PPT有中說:事務必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另外一個一致性狀態(tài)。比如,銀行轉賬,A-B。A賬戶中減少100元,B帳戶中增加一百元。這看起來比較好理解,但讓我有點疑問的是,如果從數(shù)據(jù)庫中刪除一個用戶呢?難道不用事務處理嗎?所以我對這個一致性的理解除了老方說的,還有只要事務處理符合正確的邏輯,就是一致性。

    隔離性(Isolation),如果多個用戶同時訪問數(shù)據(jù)庫,同時訪問一張表。這樣會造成一些訪問錯誤,所以有了隔離性這一定義。將多個并發(fā)事務之間要相互隔離。

    持久性(Durability),事務一旦被提交,它對數(shù)據(jù)庫中數(shù)據(jù)的改變是永久性的,無論其他操作或數(shù)據(jù)庫故障不會對它有任何影響。

    在JDBC中使用事務的語句:

    // 開啟事務

    conn.setAutoCommit(false);

    // 回滾事務

    conn.rollback();

    // 提交事務

    conn.commit();

    // ...

    // 設置保存點

    sp = conn.setSavepoint();

    // 回滾到指定保存點

    conn.rollback(sp);

    方老師使用了一個經(jīng)典的案例,來講解事務處理——銀行轉賬系統(tǒng)!

    例,用戶A轉賬10000元給用戶B。應該是A賬戶中減少10000元,B賬戶中增加10000元。那么在A提交了10000元后,數(shù)據(jù)庫發(fā)生問題(比如斷電),那B帳戶增加10000元的語句還沒有執(zhí)行。使用事務可以很好解決這一問題:

    1. 開啟事務

    2. A帳戶減少10000元

    3. 中間發(fā)生錯誤,回滾事務

    4. B帳戶增加10000元

    5. 提交事務

    OK,在上同這一過程中,如果沒有執(zhí)行到第5步。數(shù)據(jù)庫的內容就不會發(fā)生改變。在此有必要解釋一下回滾事務,回滾事務在提交事務后執(zhí)行沒有什么效果,回滾事務在提交事務之前執(zhí)行,會擦除在開啟事務之后執(zhí)行的SQL語句。

    上面是針對單一事務進行的處理,在并發(fā)事務中會遇到一些問題。設置事務的隔離級別可以很好的解決這一問題。

    首先我們來看一下并發(fā)事務容易產(chǎn)生的問題:

    臟讀:

    例,用戶A賬戶減少10000元,用戶B賬戶增加了10000元,但A還沒有提交事務。此時,B去查詢它的賬戶發(fā)現(xiàn)A已經(jīng)給自己轉賬了10000元。然后,A回滾了事務。B被A給騙了,這就是臟讀,B讀到的是未提交的數(shù)據(jù)。我雖對數(shù)據(jù)庫事務的實現(xiàn)原理不了解(事務是通過日志處理的),我打個比方就更好理解這一原因了。數(shù)據(jù)庫對所有用戶維護了一個虛表,在開啟事務中,提交事務前對數(shù)據(jù)的修改,都是修改的虛表,用戶查詢的也是虛表的內容,當執(zhí)行了提交事務操作后,將虛表中被修改的內容保存到數(shù)據(jù)庫。實際技術細節(jié)就不深入了!

    不可重復讀:

    例,用戶A原賬戶內容為100萬元,此時銀行將數(shù)據(jù)顯示到電腦屏幕和保存到文件中。銀行工作人員在電腦屏幕上看到的是100萬元,但此時,用戶A向賬戶里又存了100萬元。結果保存到文件的是200萬元。到是100萬元還是200萬元?工作人員有些迷惑。與臟讀相反的是,臟讀是讀取了前一事務未提交的數(shù)據(jù),不可重復讀讀取的是前一事務提交了的事務。注意,不可重復讀針對的是某一記錄!

    虛讀:

    例,銀行要統(tǒng)計A的報表。A的賬戶中有200萬元,屏幕上報表顯示的總額是200萬元,此時,用戶A向賬戶中又存入了100萬元。報表打印出來的總額就是300萬元。工作人員一對比,到底哪個是正確的?注意,虛讀針對的是整個表。

    不可重復讀和虛讀,有點難理解。這看起來不是什么問題,如果發(fā)生這一問題,工作人員就刷新一下表唄!如果工作人員處理的是1萬個用戶的報表,同時不幸運的是這1萬個用戶都發(fā)生了虛讀的問題。那工作人員能受了嗎?你可能還會說那就以打印的報表為準唄!問題是,可能屏幕上的那個才是正確的,這樣就要重新打印報表。所以為了使問題得以簡單的解決,事務的隔離性發(fā)揮了它的作用!

    處理上邊的三種并發(fā)事務產(chǎn)生的問題,數(shù)據(jù)庫定義了四種隔離級別:

    Serializable:可避免臟讀、不可重復讀、虛讀情況的發(fā)生。

    Repeatable read:可避免臟讀、不可重復讀情況的發(fā)生。

    Read committed:可避免臟讀情況發(fā)生。

    Read uncommitted:最低級別,以上情況均無法保證。

    Serializable,最高安全級別。設置了此級別,當一個事務訪問了某一表時,此表就會被封死。其他事務對此表的訪問就會被掛起,直到上一事務提交后才執(zhí)行一個事務。OK,這看起來十分容易理解。

    Repeatable read,讓我再小深入一下,當每個事務線程訪問同一表時,數(shù)據(jù)庫針對每個線程維護了一張?zhí)摂M表。此時各線程看到的都是原始的數(shù)據(jù)內容,對表數(shù)據(jù)的修改相互不發(fā)生影響,即使事務被提交了。數(shù)據(jù)庫可能為每個線程維護了一張?zhí)摂M表嗎?當然不可以,我想這只是為了便于理解。技術細節(jié)不深入研究!

    Read committed,數(shù)據(jù)庫對每個用戶的查詢顯示的都是原始內容(真實內容)。如果某些用戶對此表的事務沒有提交就不會影響原始內容。所以其他用戶查看到的都是原始內容或提交了的數(shù)據(jù)內容。

    Read uncommitted,這個就不多說了。

    今天的內容也就事務的隔離性有些難度吧!一般也不會去用那最高安全級別,這一級別在銀行中比較常用。

    正如老方所說,是不是感覺越學越簡單了!確實如此,我想大家應該也對此有感覺。不知不覺明天又休息了!

    加油!

    posted @ 2009-12-02 23:20 長城 閱讀(757) | 評論 (1)編輯 收藏

    僅列出標題
    共8頁: 上一頁 1 2 3 4 5 6 7 8 
    主站蜘蛛池模板: 久久亚洲AV成人无码电影| 欧美三级在线电影免费| 精品国产免费观看久久久 | 久久久久久久亚洲精品| 亚洲AV日韩AV无码污污网站| 四虎国产精品免费久久| 国产精品亚洲自在线播放页码| 222www免费视频| 亚洲国产激情在线一区| 亚洲不卡无码av中文字幕| 丰满妇女做a级毛片免费观看| 亚洲精品WWW久久久久久| 日韩少妇内射免费播放| 国产亚洲精品a在线观看| 国产成人精品免费午夜app| 香蕉大伊亚洲人在线观看| 色播在线永久免费视频| 国内精品99亚洲免费高清| 亚洲AV乱码久久精品蜜桃| 69精品免费视频| 亚洲AV无码一区二区三区牛牛| 国产亚洲精品AA片在线观看不加载| 麻豆一区二区免费播放网站| 亚洲人成色4444在线观看| 日韩成人免费视频播放| 一级全免费视频播放| 精品亚洲AV无码一区二区| 免费大学生国产在线观看p| 国产免费人成视频在线播放播| 亚洲AV无码久久精品狠狠爱浪潮| 在线日本高清免费不卡| 特级一级毛片免费看| 国产亚洲精久久久久久无码| 91在线老王精品免费播放| 国产福利电影一区二区三区,免费久久久久久久精 | 亚欧乱色国产精品免费视频| 亚洲AV无码一区二区三区牛牛| 99亚洲精品高清一二区| 在线观看国产区亚洲一区成人 | 人人爽人人爽人人片A免费| 亚洲无线码在线一区观看|