事務視圖約束存儲過程

數據庫相關知識

事務

1. 什麼是事務?

爲了完成某個業務而對數據庫進行一系列操作,這些操作要麼全部成功,要麼全部失敗。

2. 事務的四個特性(ACID)?

  • 原子性(Atomicity)
    • 事務所涉及的各個操作要麼全部成功,要麼全部失敗
  • 一致性(Consistency)
    • 事務結束之後,不能夠有非法的數據寫入到數據庫
  • 隔離性(lsolation)
    • 多個非事務可以同時進行,能一定程度上保證互不影響
  • 持久性(Durability)
    • 事務完成之後,數據一定會存放在數據庫裏面

3. 隔離級別?

  • 讀未提交

    • 一個事務可以讀取另外一個事務尚未提交的數據,可能會產生髒讀不可重複讀取幻影讀取問題

在這裏插入圖片描述

  • 讀已提交

    • 一個事務只能讀取另外一個事務已經提交的數據。該隔離級別解決了髒讀問題,但是有可能會產生不可重複讀取幻影讀取問題

    在這裏插入圖片描述

  • 可重複讀取

    • 在同一個事務當中,多次讀取同一份數據,結果是一致的。該隔離級別解決了髒讀不可重複讀取,但是仍然有可能產生幻影讀取問題

在這裏插入圖片描述

  • 序列化(串行化)

    • 讓事務一個一個串行執行,解決了髒讀不可重複讀取幻影讀取問題

    從上往下,隔離級別越來越高;

    隔離級別越高,性能越低

視圖

1. 什麼是視圖?

在已有表或者視圖上創建的虛擬表(存在內存中的)

2. 創建視圖

create view 視圖名(字段列表) as select 語句;

# 如
create view v_emp as select * from t_emp;
create view v_emp2(ename,salary) as select * from t_emp;
--視圖也可以是基於多張表
create view v_teacher_course(cname,tname,level) as select
c.name,t.name,t.level
from t_course c join t_teacher t on c.teacher_id = t.id;

3. 刪除視圖

drop view 視圖名;

4. 視圖的優點

  • 簡化:

    可以將一些複雜的SQL(比如多張表的join查詢)的查詢結果作爲一個視圖,調用者不用關心這個複雜的查詢怎麼寫。

  • 安全:

    調用者只能查詢或者修改他們所見到的數據

  • 邏輯獨立性:

    可以屏蔽真實表結構變化帶來的影響

約束

1. 什麼是約束

約束是一種限制,它通過對錶的行或者列的數據做出限制,確保數據的完整性和一致性

2. 約束的種類

  • 主鍵約束

    • 要求主鍵值必須唯一且非空
    • 一張表最多隻有一個主鍵約束
  • 唯一性約束(unique)

    • 唯一性約束不允許重複值,但是允許有多個null

    • 一個表中可以有多個unique字段

    • create table t_dept(
          id int primary key,
          dept_name varchar(50) unique,
          loc varchar(100)
      );
      
      create table t_dept(
          id int primary key,
          dept_name varchar(50),
          loc varchar(100),
          unique(dept_name)
      );
      
  • 外鍵約束

    • 示例:外鍵約束

      create table t_dept(
          id int primary key,
          dept_name varchar(50),
          loc varchar(100)
      );
      
      create table t_staff(
          id int primary key auto_increment,
          sname varchar(50),
          age int,
          dept_id int,
          foreign key(dept_id) references t_dept(id)
      );
      
      # 添加數據時,先添加主表中的數據
      insert into t_dept values(100,'HR','location01');
      insert into t_staff values(null,'張三',22,100);
      # 刪除數據時,要先刪除從表中的數據
      delete from t_staff where id = 1;
      delete from t_dept where id = 100
      
  • 非空約束(not null)

存儲過程

1. 什麼是數據庫的存儲過程?

存放在數據庫端的一系列SQL語句,用於完成某個業務功能。

2. 如何創建存儲過程

 create procedure 存儲過程名(in/out/inout 參數 參數類型)

參數有三種類型:

  • in:(默認的)輸入參數,該參數值在調用時需要指定,在存儲過程當中該參數值不能返回
  • out:輸出參數,該參數值可以被返回。
  • inout:輸入輸出參數。

3. 調用存儲過程

call 存儲過程名;

示例:

# 執行存儲過程
delimiter //
create procedure getEmp()
begin
	select * from t_emp;
end
//

# 創建完存儲過程要將分號改回來
delimiter ;

# 調用存儲過程
call getEmp;

--------------------------
# 執行存儲過程(帶參數in)
delimiter //
create procedure getEmp2(in sid int)
begin
	select * from t_emp where id = sid;
end
//

# 創建完存儲過程要將分號改回來
delimiter ;

# 調用存儲過程
call getEmp2(1);

--------------------------
# 執行存儲過程(帶參數out)是可以拿到返回值的
delimiter //
create procedure getEmp3(out max_value decimal(8,2))
begin
	select max(salary) into max_value from t_emp;
end
//

# 創建完存儲過程要將分號改回來
delimiter ;

# 調用存儲過程
call getEmp3(@mv);
select @mv;

因爲在控制檯,“;”表示結束,這樣存儲過程就不完整了,所以用"delimiter //“將結束符號改爲”//"

delimiter; 表示創建完存儲過程要將分號改回來,跟以前一樣SQL命令以";"結尾

java操作存儲過程

package util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {
	public static Connection getConnection() throws Exception{
		Connection conn = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			conn = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/test","root","123456");
		}catch(Exception e) {
			e.printStackTrace();
			throw e;
		}
		return conn;
	}
	
	/**
	 * 關閉連接
	 * @param conn
	 */
	public static void close(Connection conn) {
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) throws Exception {
		// 測試連接是否成功
		System.out.println(getConnection());
	}
}

package util;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Types;

/**
 * 如何調用存儲過程
 */
public class ProcedureTest {
	public static void main(String[] args) throws Exception {
		test1();
	}
	
	/**
	 * 調用不帶參的存儲過程
	 * @throws Exception 
	 */
	public static void test1() throws Exception{
		Connection conn = null;
		try {
			conn = DBUtil.getConnection();
			CallableStatement cs = conn.prepareCall("{call getEmp}");
			ResultSet rs = cs.executeQuery();
			while(rs.next()) {
				int id = rs.getInt("id");
				String ename = rs.getString("ename");
				System.out.println("id:" + id + " ename:" + ename);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}finally {
			DBUtil.close(conn);
		}
		
	}
	
	/**
	 * 調用帶參的存儲過程
	 * @throws Exception 
	 */
	public static void test2() throws Exception{
		Connection conn = null;
		try {
			conn = DBUtil.getConnection();
			// 一個參數一個問號
			CallableStatement cs = conn.prepareCall("{call getEmp2(?)}");
			cs.setInt(1, 1);
			ResultSet rs = cs.executeQuery();
			while(rs.next()) {
				int id = rs.getInt("id");
				String ename = rs.getString("ename");
				System.out.println("id:" + id + " ename:" + ename);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}finally {
			DBUtil.close(conn);
		}
	}
	
	/**
	 * 調用帶參(out參數的)的存儲過程(能獲取返回值的)
	 * @throws Exception 
	 */
	public static void test3() throws Exception{
		Connection conn = null;
		try {
			conn = DBUtil.getConnection();
			// 一個參數一個問號
			CallableStatement cs = conn.prepareCall("{call getEmp3(?)}");
			cs.registerOutParameter(1, Types.DECIMAL);
			cs.execute();
			System.out.println(cs.getBigDecimal(1));
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}finally {
			DBUtil.close(conn);
		}
		
	}
}

4. 存儲過程的優點:

  • 減少應用程序和數據庫之間交互的次數,提升性能
  • 將多個應用程序相同的邏輯集中寫在存儲過程裏面,可以共享一部分業務邏輯

在這裏插入圖片描述

5. 存儲過程的缺點
  • 存儲過程依賴於特定的數據庫(不同數據庫存儲過程語法不同,不能移植)
  • 存儲過程對於特別複雜的業務也不好寫。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章