JavaWeb筆記007 jdbc基本使用以及事物基礎知識

首先你要有一個Java項目,然後依賴了mysql驅動,過程略,這裏介紹一下jdbc的基本使用,實際開發是用不到的,都是Spring結合Mybatis或者Hibernate。

基本使用

public void f2() throws Exception{
	//註冊驅動
	//Class.forName("com.mysql.jdbc.Driver");  // 除了Driver是jdbc的類,其餘都是Java的類
	DriverManager.registerDriver(new Driver());
	
	//獲取連接 		ctrl+o 整理包
	Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234"); // 高版本的有一個警告,用SSL:jdbc:mysql://localhost:3306/test?useSSL=true
	
	//編寫sql
	String  sql="select * from category";
	
	//創建語句執行者
	PreparedStatement st=conn.prepareStatement(sql);
	
	//設置參數
	
	//執行sql
	ResultSet rs=st.executeQuery();
	
	//處理結果
	while(rs.next()){
		System.out.println(rs.getString("cid")+"::"+rs.getString("cname"));
	}
	
	//釋放資源.
	rs.close();
	st.close();
	conn.close();
}
//插入一條數據  注:JdbcUtils是自己封裝的類
public void f3(){
	Connection conn=null;
	ResultSet rs=null;
	PreparedStatement st=null;
	
	try {
		//獲取連接
		conn=JdbcUtils.getConnection();
		
		//編寫sql
		String sql="insert into  category values(?,?)";
		
		//獲取語句執行者
		st=conn.prepareStatement(sql);
		
		//設置參數
		st.setString(1, "c006");
		st.setString(2, "戶外");
		
		//執行sql 
		int i=st.executeUpdate();
		
		//處理結果
		if(i==1){
			System.out.println("success");
		}else{
			System.out.println("fail");
		}
		
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		//釋放資源
		JdbcUtils.closeResource(conn, st, rs);
	}
	
}


public class JdbcUtils {
	// 獲取連接
	public static Connection getConnection() throws ClassNotFoundException, SQLException {
		// 註冊驅動   ctrl+shift+f格式化代碼
		Class.forName("com.mysql.jdbc.Driver");

		// 獲取連接 ctrl+o 整理包
		Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day07", "root", "1234");
		return conn;
	}

	/**
	 * 釋放資源
	 * @param conn 連接
	 * @param st 語句執行者
	 * @param rs 結果集
	 */
	public static void closeResource(Connection conn, Statement st, ResultSet rs) {
		closeResultSet(rs);
		closeStatement(st);
		closeConn(conn);
	}
	
	/**
	 * 釋放連接
	 * @param conn 連接
	 */
	public static void closeConn(Connection conn){
		if(conn!=null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn=null;
		}
		
	}
	
	/**
	 * 釋放語句執行者
	 * @param st 語句執行者
	 */
	public static void closeStatement(Statement st){
		if(st!=null){
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			st=null;
		}
		
	}
	
	/**
	 * 釋放結果集
	 * @param rs 結果集
	 */
	public static void closeResultSet(ResultSet rs){
		if(rs!=null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			rs=null;
		}
		
	}
}

jdbc-api詳解

所有的包 都是 java.sql 或者 javax.sql

DriverManager:管理了一組jdbc的操作 類
	常用方法:
		瞭解:註冊驅動	
			static void registerDriver(Driver driver) :
				通過查看 com.mysql.jdbc.Driver的源碼 有如下代碼
					 static {
						try {
							java.sql.DriverManager.registerDriver(new Driver());//這段代碼我們已經寫過
						} catch (SQLException E) {
							throw new RuntimeException("Can't register driver!");
						}
					}
				驅動註冊了兩次.我們只需要將靜態代碼塊執行一次,類被加載到內存中會執行靜態代碼塊,並且只執行一次.
				現在只需要將類加載到內存中即可:
					方式1:
						★Class.forName("全限定名");//包名+類名   com.mysql.jdbc.Driver
					方式2:
						類名.class;
					方式3:
						對象.getClass();

		掌握:獲取連接
			static Connection getConnection(String url, String user, String password) 
				參數1:告訴我們連接什麼類型的數據庫及連接那個數據庫
							協議:數據庫類型:子協議 參數
					mysql:	jdbc:mysql://localhost:3306/數據庫名稱
					oracle:	jdbc:oracle:thin@localhost:1521@實例
					
				參數2:賬戶名 root
				參數3:密碼
				
				
Connection:連接 接口
	常用方法:
		獲取語句執行者:
			(瞭解)Statement createStatement() :獲取普通的語句執行者  會出現sql注入問題
			★PreparedStatement prepareStatement(String sql) :獲取預編譯語句執行者
			(瞭解)CallableStatement prepareCall(String sql):獲取調用存儲過程的語句執行者

		瞭解:
			setAutoCommit(false) :手動開啓事務
			commit():提交事務
			rollback():事務回滾

Statement:語句執行者 接口
PreparedStatement:預編譯語句執行者 接口
	常用方法:
		設置參數:
			setXxx(int 第幾個問號,Object 實際參數);
				常見的方法:
					 setInt
					 setString
					 setObject
		
		執行sql:
			 ResultSet executeQuery() :執行 r 語句 返回值:結果集
			 int executeUpdate() :執行cud 語句 返回值:影響的行數


ResultSet:結果集 接口
	執行查詢語句之後返回的結果
		常用方法:
			boolean next():判斷是否有下一條記錄,若有返回true且將光標移到下一行,若沒有呢則返回false
				光標一開始處於第一條記錄的上面
			
			獲取具體內容
				getXxx(int|string)
					若參數爲int :第幾列
					若參數爲string:列名(字段名)
				例如:
					獲取cname的內容可以通過
						getString(2)
						getString("cname")
				常用方法:
					getInt
					getString 也可以獲取int值
					getObject 可以獲取任意

事務

事務總結:
	事務的特性:★★★
		ACID
		原子性:事務裏面的操作單元不可切割,要麼全部成功,要麼全部失敗
		一致性:事務執行前後,業務狀態和其他業務狀態保持一致.
		隔離性:一個事務執行的時候最好不要受到其他事務的影響
		持久性:一旦事務提交或者回滾.這個狀態都要持久化到數據庫中
	不考慮隔離性會出現的讀問題(都是對於兩個事務來說的)★★
		髒讀:在一個事務中讀取到另一個事務沒有提交的數據
		不可重複讀:在一個事務中,兩次查詢的結果不一致(針對的update操作)
		虛讀(幻讀):在一個事務中,兩次查詢的結果不一致(針對的insert操作)
	通過設置數據庫的隔離級別來避免上面的問題(理解)
		read uncommitted  	讀未提交	上面的三個問題都會出現
		read committed  	讀已提交	可以避免髒讀的發生
		repeatable read		可重複讀	可以避免髒讀和不可重複讀的發生
		serializable		串行化		可以避免所有的問題
	
	
	瞭解
		演示髒讀的發生:
			將數據庫的隔離級別設置成 讀未提交
				set session transaction isolation level read uncommitted;
			查看數據庫的隔離級別
				select @@tx_isolation;
		避免髒讀的發生,將隔離級別設置成  讀已提交
			set session transaction isolation level read committed;
			不可避免不可重複讀的發生.
		
		避免不可重複讀的發生 經隔離級別設置成 可重複讀
			set session transaction isolation level  repeatable read;
			
		演示串行化 可以避免所有的問題
			set session transaction isolation level  serializable;
			鎖表的操作.
		
	四種隔離級別的效率
		read uncommitted>read committed>repeatable read>serializable
	四種隔離級別的安全性
		read uncommitted<read committed<repeatable read<serializable
		
	開發中絕對不允許髒讀發生.
		mysql中默認級別:repeatable read
		oracle中默認級別:read committed

	java中控制隔離級別:(瞭解)
		Connection的api
			void setTransactionIsolation(int level) 
				level是常量
package com.itheima.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

// 數據庫工具另一種封裝,使用了第三方連接池
public class DataSourceUtils {
	private static ComboPooledDataSource ds=new ComboPooledDataSource();
	private static ThreadLocal<Connection> tl=new ThreadLocal<>();
	
	/**
	 * 獲取數據源
	 * @return 連接池
	 */
	public static DataSource getDataSource(){
		return ds;
	}
	
	/**
	 * 從當前線程上獲取連接
	 * @return 連接
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException{
		Connection conn = tl.get();
		if(conn==null){
			//第一次獲取 創建一個連接 和當前的線程綁定
			 conn=ds.getConnection();
			 
			 //綁定
			 tl.set(conn);
		}
		return conn;
	}
	
	
	
	/**
	 * 釋放資源
	 * 
	 * @param conn
	 *            連接
	 * @param st
	 *            語句執行者
	 * @param rs
	 *            結果集
	 */
	public static void closeResource(Connection conn, Statement st, ResultSet rs) {
		closeResource(st, rs);
		closeConn(conn);
	}
	
	 
	public static void closeResource(Statement st, ResultSet rs) {
			closeResultSet(rs);
			closeStatement(st);
	}

	/**
	 * 釋放連接
	 * 
	 * @param conn
	 *            連接
	 */
	public static void closeConn(Connection conn) {
		if (conn != null) {
			try {
				conn.close();
				//和當前的線程解綁
				tl.remove();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}

	}

	/**
	 * 釋放語句執行者
	 * 
	 * @param st
	 *            語句執行者
	 */
	public static void closeStatement(Statement st) {
		if (st != null) {
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			st = null;
		}

	}

	/**
	 * 釋放結果集
	 * 
	 * @param rs
	 *            結果集
	 */
	public static void closeResultSet(ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			rs = null;
		}

	}
	
	/**
	 * 開啓事務
	 * @throws SQLException
	 */
	public static void startTransaction() throws SQLException{
		//獲取連接//開啓事務
		getConnection().setAutoCommit(false);;
	}
	
	/**
	 * 事務提交
	 */
	public static void commitAndClose(){
		try {
			//獲取連接
			Connection conn = getConnection();
			//提交事務
			conn.commit();
			//釋放資源
			conn.close();
			//解除綁定
			tl.remove();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 事務回滾
	 */
	public static void rollbackAndClose(){
		try {
			//獲取連接
			Connection conn = getConnection();
			//事務回滾
			conn.rollback();
			//釋放資源
			conn.close();
			//解除綁定
			tl.remove();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}

public class AccountDao4DB {

	public void accountOut(String fromUser, String money) throws SQLException {
		//創建queryrunner
		QueryRunner qr = new QueryRunner();
		
		//編寫sql
		String sql="update account set money =money - ? where name =?";
		
		//執行sql
		qr.update(DataSourceUtils.getConnection(), sql, money,fromUser);
	}

	public void accountIn(String toUser, String money) throws SQLException {
		// TODO Auto-generated method stub
		QueryRunner qr=new QueryRunner();
		String sql="update account set money =money + ? where name =?";
		qr.update(DataSourceUtils.getConnection(), sql, money,toUser);
	}

}


public class AccountService4DB {

	/**
	 * 轉賬
	 * @param fromUser 轉出方
	 * @param toUser 轉入方
	 * @param money 金額
	 * @throws Exception 
	 */
	public void account(String fromUser, String toUser, String money) throws Exception {
		AccountDao4DB dao = new AccountDao4DB();
		
		try {
			//0.開啓事務
			DataSourceUtils.startTransaction();
			
			//1.轉出
			dao.accountOut(fromUser,money);
			
			int i=1/0;
			
			//2.轉入
			dao.accountIn(toUser,money);
			
			//3.事務提交
			DataSourceUtils.commitAndClose();
		} catch (Exception e) {
			e.printStackTrace();
			DataSourceUtils.rollbackAndClose();
			throw e;
		}
		
	}

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