java web複習 day16(數據庫事務,鏈接池)

        day16的內容有點無聊,但是還是硬着頭皮聽了,希望能早點過度到ssm的學習。

一、事務的概念

        事務指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。

二、如何在jdbc中控制事務

         在Jdbc中主要由以下三個語句控制事務:

            (1)Connection.setAutoCommit(false);   開始事務

            (2)Connection.rollback();    回滾事務

            (3)Connection.commit();    提交事務

        其中回滾事務的操作爲:

            (1)設置回滾點:Savepoint sp = conn.setSavepoint();

            (2)提交回滾請求:Conn.rollback(sp);

            (3)提交事務:Conn.commit();   (回滾後必須提交事務)

三、事務的四大特性(ACID)

        原子性(Atomicity)原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。 

        一致性(Consistency)事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。

        隔離性(Isolation)事務的隔離性是多個用戶併發訪問數據庫時,數據庫爲每一個用戶開啓的事務,不能被其他事務的操作數據所幹擾,多個併發事務之間要相互隔離。

        持久性(Durability)持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。

四、事務的四大隔離級別

           事務的隔離級別如果不引起重視,就會引發一系列問題,比如說髒讀,幻讀,不可重複讀:

            (1)髒讀:指一個事務讀取了另外一個事務未提交的數據。

            (2)不可重複讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同。

            (3)虛讀(幻讀):是指在一個事務內讀取到了別的事務插入的數據,導致前後讀取不一致。   

        數據庫共定義了四種隔離級別:
            (1)Serializable:可避免髒讀、不可重複讀、虛讀情況的發生。(串行化)
            (2)Repeatable read:可避免髒讀、不可重複讀情況的發生。(可重複讀)
            (3)Read committed:可避免髒讀情況發生(讀已提交)。

            (4)Read uncommitted:最低級別,以上情況均無法保證。(讀未提交)

        在mysql中有以下兩種語句來操作隔離級別:

            (1)set   transaction isolation level 設置事務隔離級別

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

五、從鏈接池中獲取鏈接

            傳統方法獲取鏈接的缺點:用戶每次請求都需要向數據庫獲得鏈接,而數據庫創建連接通常需要消耗相對較大的資源,創建時間也較長,並且極易造成數據庫服務器內存溢出、宕機。

            我們獲取鏈接的方式有以下三種:

 1.使用動態代理技術構建鏈接池中的connection。

public class JdbcPool implements DataSource {
	private static LinkedList<Connection> list = new LinkedList<Connection>();
	
	static{
		try{
			InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
			Properties prop = new Properties();
			prop.load(in);
			
			String driver = prop.getProperty("driver");
			String url = prop.getProperty("url");
			String username = prop.getProperty("username");
			String password = prop.getProperty("password");
			
			Class.forName(driver);
			//爲了演示,循環輸出鏈接
			for(int i=0;i<10;i++){
				Connection conn = DriverManager.getConnection(url, username, password);
				System.out.println("獲取到了鏈接" + conn);
				list.add(conn);
			}
			
		}catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
public Connection getConnection() throws SQLException {
		
		//proxyConnection.commit()  proxyConnection.rollback
		if(list.size()>0){
			final Connection conn = list.removeFirst();   //myconnection.commit
			System.out.println("池大小是" + list.size());
			return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){

				public Object invoke(Object proxy, Method method, Object[] args)
						throws Throwable {//調用重寫的close方法
					if(!method.getName().equals("close")){
						return method.invoke(conn, args);
					}else{
						list.add(conn);
						System.out.println(conn + "被還給池了!!");
						System.out.println("池大小爲" + list.size());
						return null;
					}	
				}	
			});	
		}else{
			throw new RuntimeException("對不起,數據庫忙");
		}
		
	}
/*
用包裝設計模式對某個對象進行增強
1.寫一個類,實現與被增強對象(mysql的connection)相同的接口
2、定義一個變量,指向被增強對象
3、定義一個構造方法,接收被增強對象
4、覆蓋想增強的方法
5、對於不想增強的方法,直接調用被增強對象的方法
 */

class MyConnection implements Connection{
	private Connection conn;
	private List pool;
	public MyConnection(Connection conn,List pool){
		this.conn = conn;
		this.pool = pool;
	}
	
	public void close() throws SQLException {
		pool.add(conn);
	}}  //其他沒有重寫的方法在這裏省略

        也有一些開源組織提供了數據源的獨立實現:
        DBCP 數據庫連接池 
        C3P0 數據庫連接池

2.DHCP技術獲取鏈接

        DBCP 是 Apache 軟件基金組織下的開源連接池實現,使用DBCP數據源,應用程序應在系統中增加如下兩個 jar 文件:
            (1)Commons-dbcp.jar:連接池的實現
            (2)Commons-pool.jar:連接池實現的依賴庫
        Tomcat 的連接池正是採用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。

         首先配置資源文件:

driverClassName=com.mysql.cj.jdbc.Driver

url=jdbc:mysql://localhost:3306/day16?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true

username=root

password=root

initialSize=10 #初始值

maxActive=50#最大鏈接激活數

maxIdle=20#最大等待連接中的數量

minIdle=5#最小等待連接中的數量

maxWait=60000#最大等待毫秒數

connectionProperties=useUnicode=true;characterEncoding=UTF8

defaultAutoCommit=true #配置事務是否自動提交

defaultTransactionIsolation=READ_UNCOMMITTED   #配置事務隔離級別     

   配置JdbcUtils_DHCP

package cn.itcast.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;


public class JdbcUtils_DBCP {
	
	private static DataSource ds = null;
	static{
		try{
			InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
			Properties prop = new Properties();
			prop.load(in);
			
			BasicDataSourceFactory factory = new BasicDataSourceFactory();
			
			ds = factory.createDataSource(prop);
			System.out.println(ds);
		}catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection() throws SQLException{
		
		return ds.getConnection();
	}
	
	public static void release(Connection conn,Statement st,ResultSet rs){
		if(rs!=null){
			try{
				rs.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;

		}
		if(st!=null){
			try{
				st.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		
		if(conn!=null){
			try{
				conn.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			
		}
	}
}

3.C3P0獲取鏈接池

C3P0的配置文件不是放在資源文件中的,而是放在xml中的,該xml放在src目錄下。

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT&amp;allowPublicKeyRetrieval=true</property>
		<property name="user">root</property>
		<property name="password">root</property>
	
		<property name="acquireIncrement">5</property>
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">5</property>
		<property name="maxPoolSize">20</property>
	</default-config>
	<!--默認配置-->
	<named-config name="mysql">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
		<property name="user">root</property>
		<property name="password">root</property>
	
		<property name="acquireIncrement">5</property>
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">5</property>
		<property name="maxPoolSize">20</property>
	</named-config>
	<!--找mysql-->
	<named-config name="oracle">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16</property>
		<property name="user">root</property>
		<property name="password">root</property>
	
		<property name="acquireIncrement">5</property>
		<property name="initialPoolSize">10</property>
		<property name="minPoolSize">5</property>
		<property name="maxPoolSize">20</property>
	</named-config>
</c3p0-config> <!--找oracle-->

注意:在寫url的時候需要轉義字符。

獲取鏈接的工具類:

package cn.itcast.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcUtils_C3P0 {
	
	private static ComboPooledDataSource ds = null;
	static{
		try{
			
			ds = new ComboPooledDataSource();
			
		}catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection() throws SQLException{
		
		return ds.getConnection();
	}
	
	public static void release(Connection conn,Statement st,ResultSet rs){
		
		
		if(rs!=null){
			try{
				rs.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;

		}
		if(st!=null){
			try{
				st.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		
		if(conn!=null){
			try{
				conn.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
			
		}
	}

綜上C3P0最好用。(下班了!!!!)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章