JDBC-用Java語句操作數據庫


JDBC

1. Jdbc概述

問題:實際開發中,不可能用工具或者命令行操作數據庫,數據庫表中的數據最終要使用Java程序來操作,那么Java中如何操作數據庫中的數據呢?

Java語言中,有一個專門連接數據庫的規范(JDBC),專門負責連接數據庫進行數據操作的規范

 

JDBC只是SUN編寫的一堆接口(規范的體現),SUN公司自己並沒有實現

 

問題 為什么SUN只定義一個JDBC規范,而不實現呢?

因為市面上的數據庫很多,每個數據庫內部接口不會向外暴露,而且即便是暴露讓SUN去實現,市面上很多數據庫全部要SUN來實現不現實

 

實際中哪個數據庫需要支持JAVA語言,就需要自己實現JavaJDBC規范,因為實現了JDBC很多接口,那么就會有很多實現類,而很多實現類在java中會使用一個專門的包封裝起來,叫做jar(在JDBC中叫做驅動包),各大數據庫產商實現JDBC規范以后都會把他們jar包放在官網上以供開發者下載使用

 

1.1. JDBC

JDBC(Java DataBase Connectivity):

是一種用於執行SQL語句的Java API,可以為多種關系數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基

JDBC規范對應的api

2.java連接數據庫

以連接mysql為例

2.1. 創建普通java項目

2.2. 在項目下面新建一個lib目錄

 

 

2.3. MySQL驅動包拷貝到項目中並添加依賴

 

2.5 獲取數據庫連接對象

准備:

1.拷貝MySQL的驅動包到項目中去:mysql-connector-java-5.1.x-bin.jar

2.build path,告速項目去哪里去找字節碼文件.

--------------------------------------------------------------------------------

操作JDBC的第一步,獲取JDBC的連接對象.:Connection.

 

步驟:

  1.加載注冊驅動.

    就是把驅動中的Driver字節碼加載到JVM.

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

   為什么這句話就可以加載注冊驅動?

   第一步:com.mysql.jdbc.Driver.class這份字節碼加載到JVM.

   第二步:當一份字節碼被加載進JVM,馬上就會執行該字節碼中的靜態代碼塊.

    第三步:該靜態代碼中,就在完成,先創建驅動對象,再注冊.

  2.通過DriverManager獲取連接對象.

    public static Connection getConnection(String url,String user,String password)

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbName","root","admin");

 

jdbc:mysql://localhost:3306/dbName

jdbc:mysql:// :連接MySQL數據庫的協議,不同數據庫協議不一樣

localhost:3306 :數據庫軟件的主機和端口

dbName  具體要連接數據庫

    若數據庫安裝在本機,並且端口是默認的3306,則可以簡寫:

    Connection conn = DriverManager.getConnection("jdbc:mysql:///dbName","root","admin");

 

驗證已經獲取連接:可以在MySQL控制台,使用命令:show processlist; 查看MySQL運行進程.

 

 

 1 public class GetConnectionDemo {
 2     public static void main(String[] args) throws Exception {
 3         
 4         //1.加載注冊驅動 : 把當前類對應的字節碼加載到JVM中
 5         Class.forName("com.mysql.jdbc.Driver");
 6         //2.獲取數據庫連接
 7         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 8         System.out.println(conn);
 9         
10     }
11 }

 

3. 創建表-DDL操作

在其他操作之間先要把數據庫表要創建出來

/賈璉欲執事

創建一張t_student表:

id:

name:

age:

 

 

 1 //DML : 對表數據的增刪改操作
 2 public class DMLDemo {
 3 
 4     /*
 5      * 向 t_student表中插入一條數據 
 6      * sql : insert into t_student(name,age) values ('喬峰',30)
 7      */
 8     @Test
 9     public void testInsert() throws Exception {
10         String sql = "insert into t_student(name,age) values ('喬峰',30)";
11         
12         // 1.加載注冊驅動
13         Class.forName("com.mysql.jdbc.Driver");
14 
15         // 2.獲取數據庫連接對象
16         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
17         // 3.創建語句對象
18         Statement st = conn.createStatement();
19         
20         // 4.執行SQL語句
21         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
22         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
23         int rows = st.executeUpdate(sql);
24         System.out.println(rows);
25         //5.釋放資源(先開后關)
26         st.close();
27         conn.close();
28 
29     }
30     /*
31      * 刪除操作: 刪除t_student表中的某一條數據
32      * SQL :delete from t_student where id = 2
33      */
34     @Test
35     public void testDelete() throws Exception {
36         String sql = "delete from t_student where id = 2";
37         
38         // 1.加載注冊驅動
39         Class.forName("com.mysql.jdbc.Driver");
40 
41         // 2.獲取數據庫連接對象
42         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
43         // 3.創建語句對象
44         Statement st = conn.createStatement();
45         
46         // 4.執行SQL語句
47         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
48         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
49         int rows = st.executeUpdate(sql);
50         System.out.println(rows);
51         //5.釋放資源(先開后關)
52         st.close();
53         conn.close();
54     }
55     /*
56      * 修改操作 : 修改t_student表中的某一條數據
57      * SQL : update t_student set name = '虛竹',age = 50 where id = 3
58      */
59     @Test
60     public void testUpdate() throws Exception {
61         String sql = "update t_student set name = '虛竹',age = 50 where id = 3";
62         
63         // 1.加載注冊驅動
64         Class.forName("com.mysql.jdbc.Driver");
65 
66         // 2.獲取數據庫連接對象
67         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
68         // 3.創建語句對象
69         Statement st = conn.createStatement();
70         
71         // 4.執行SQL語句
72         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
73         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
74         int rows = st.executeUpdate(sql);
75         System.out.println(rows);
76         //5.釋放資源(先開后關)
77         st.close();
78         conn.close();
79     }
80 }

 

4.DML操作-表數據的增刪改

 

 1 //DML : 對表數據的增刪改操作
 2 public class DMLDemo {
 3 
 4     /*
 5      * 向 t_student表中插入一條數據 
 6      * sql : insert into t_student(name,age) values ('喬峰',30)
 7      */
 8     @Test
 9     public void testInsert() throws Exception {
10         String sql = "insert into t_student(name,age) values ('喬峰',30)";
11         
12         // 1.加載注冊驅動
13         Class.forName("com.mysql.jdbc.Driver");
14 
15         // 2.獲取數據庫連接對象
16         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
17         // 3.創建語句對象
18         Statement st = conn.createStatement();
19         
20         // 4.執行SQL語句
21         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
22         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
23         int rows = st.executeUpdate(sql);
24         System.out.println(rows);
25         //5.釋放資源(先開后關)
26         st.close();
27         conn.close();
28 
29     }
30     /*
31      * 刪除操作: 刪除t_student表中的某一條數據
32      * SQL :delete from t_student where id = 2
33      */
34     @Test
35     public void testDelete() throws Exception {
36         String sql = "delete from t_student where id = 2";
37         
38         // 1.加載注冊驅動
39         Class.forName("com.mysql.jdbc.Driver");
40 
41         // 2.獲取數據庫連接對象
42         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
43         // 3.創建語句對象
44         Statement st = conn.createStatement();
45         
46         // 4.執行SQL語句
47         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
48         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
49         int rows = st.executeUpdate(sql);
50         System.out.println(rows);
51         //5.釋放資源(先開后關)
52         st.close();
53         conn.close();
54     }
55     /*
56      * 修改操作 : 修改t_student表中的某一條數據
57      * SQL : update t_student set name = '虛竹',age = 50 where id = 3
58      */
59     @Test
60     public void testUpdate() throws Exception {
61         String sql = "update t_student set name = '虛竹',age = 50 where id = 3";
62         
63         // 1.加載注冊驅動
64         Class.forName("com.mysql.jdbc.Driver");
65 
66         // 2.獲取數據庫連接對象
67         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
68         // 3.創建語句對象
69         Statement st = conn.createStatement();
70         
71         // 4.執行SQL語句
72         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
73         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
74         int rows = st.executeUpdate(sql);
75         System.out.println(rows);
76         //5.釋放資源(先開后關)
77         st.close();
78         conn.close();
79     }
80 }

5. DQL操作-查詢操作

 

5.1. 查詢操作的分析

 

 

5.2 查詢具體操作

 

結果集的列的位置

 

 

1.使用 rs.next() 偏移光標,循環指定具體的某一行

獲取數據的具體方法

 Object

getObject(int columnIndex) 
 columnIndex : 通過結果集的位置(1開始)獲取對應的數據

 Object

getObject(String columnLabel) 
columnLabel : 通過結果集的 列名獲取對應的數據

 

 

 

  1 package cn.sxt.jdbc._01connection;
  2 
  3 
  4 import java.sql.Connection;
  5 import java.sql.DriverManager;
  6 import java.sql.ResultSet;
  7 import java.sql.Statement;
  8 import java.util.ArrayList;
  9 import java.util.List;
 10 
 11 import org.junit.Test;
 12 
 13 //DQL :查詢操作
 14 public class D_DQLDemo {
 15     
 16     /*
 17      * 多行查詢 :查詢t_student表中的所有數據
 18      * SQL : select * from t_student
 19      */
 20     @Test
 21     public void testList() throws Exception {
 22         String sql = "select * from t_student";
 23         
 24         // 1.加載注冊驅動
 25         Class.forName("com.mysql.jdbc.Driver");
 26 
 27         // 2.獲取數據庫連接對象
 28         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 29         // 3.創建語句對象
 30         Statement st = conn.createStatement();
 31         
 32         // 4.執行SQL語句
 33         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
 34         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
 35         ResultSet rs = st.executeQuery(sql);
 36         
 37         
 38         //創建list集合用於封裝Student對象
 39         List<Student> stus = new ArrayList<>();
 40         
 41         while(rs.next()) {
 42             //1.通過結果集的位置獲取對應的數
 43             /*Object id = rs.getObject(1);
 44             Object name = rs.getObject(2);
 45             Object age = rs.getObject(3);*/
 46             
 47             //2.通過結果集的 列名獲取對應的數據
 48             /*Object id = rs.getObject("id");
 49             Object name = rs.getObject("name");
 50             Object age = rs.getObject("age");*/
 51             //3.通過數據庫數據和Java對應的數據類型獲取對應的只
 52             int id = rs.getInt("id");
 53             String name = rs.getString("name");
 54             int age = rs.getInt("age");
 55             //System.out.println(id+","+name+","+age);
 56             
 57             //將獲取的數據封裝成對應的Student對象
 58             Student stu = new  Student(id, name, age);
 59             
 60             //將一個個Student對象添加到list集合中
 61             stus.add(stu);
 62         }
 63         
 64         for (Student student : stus) {
 65             System.out.println(student);
 66         }
 67         //5.釋放資源(先開后關)
 68         rs.close();
 69         st.close();
 70         conn.close();
 71     }
 72     
 73     
 74     /*
 75      * 單行查詢: 查詢出t_student 指定id的信息
 76      * SQL : select * from t_student where id = 1;
 77      */
 78     @Test
 79     public void testGetOne() throws Exception {
 80         String sql = "select * from t_student where id = 2";
 81         
 82         // 1.加載注冊驅動
 83         Class.forName("com.mysql.jdbc.Driver");
 84 
 85         // 2.獲取數據庫連接對象
 86         Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 87         // 3.創建語句對象
 88         Statement st = conn.createStatement();
 89         
 90         // 4.執行SQL語句
 91         // int rows = st.executeUpdate(String sql);執行DDL和DML語句,放回的是受影響的行數
 92         // ResultSet res = st.executeQuery(String sql);執行DQL查詢語句,返回的結果集對象
 93         ResultSet rs = st.executeQuery(sql);
 94         
 95         if(rs.next()) {
 96             //1.通過結果集的位置獲取對應的數
 97             /*Object id = rs.getObject(1);
 98             Object name = rs.getObject(2);
 99             Object age = rs.getObject(3);*/
100             
101             //2.通過結果集的 列名獲取對應的數據
102             /*Object id = rs.getObject("id");
103             Object name = rs.getObject("name");
104             Object age = rs.getObject("age");*/
105             //3.通過數據庫數據和Java對應的數據類型獲取對應的只
106             int id = rs.getInt("id");
107             String name = rs.getString("name");
108             int age = rs.getInt("age");
109             //System.out.println(id+","+name+","+age);
110             
111             //將獲取的數據封裝成對應的Student對象
112             Student stu = new  Student(id, name, age);
113             System.out.println(stu);
114         }
115         //5.釋放資源(先開后關)
116         rs.close();
117         st.close();
118         conn.close();    
119     }
120 }

 

6. 預編譯語句對象PreparedStatment

問題 我們有了Statment對象可以執行SQL,為什么還要使用PreparedStatment

 

優勢

  1. SQL語句結構清晰,參數的設置和SQL語句分離
  2. 性能更高
  3. 防止SQL注入

 

Statement: 表示靜態SQL語句對象.

PreparedStatement:Statement的子接口,表示預編譯SQL語句對象. 通過占位符(?)來拼SQL.  

6.1 創建PreparedStatement

創建語句對象 Statment

 Statement

createStatement() 
創建一個 Statement 對象來將 SQL 語句發送到數據庫。

 

創建預編譯語句對象PreparedStatement

 

 PreparedStatement

prepareStatement(String sql) 
創建預編譯語句對象,SQL是帶有占位符的SQL模板.

 

 

6.2. 執行SQL語句的方法

6.2.1. Statment

在執行SQL語句的時候回帶上SQL語句

 ResultSet

executeQuery(String sql) 
          執行給定的 SQL 語句,該語句返回單個 ResultSet 對象。

 int

executeUpdate(String sql) 
          執行給定 SQL 語句,該語句可能為 INSERT、UPDATE 或 DELETE 語句,或者不返回任何內容的 SQL 語句(如 SQL DDL 語句)。

 

6.2.2. PreparedStatement 

在執行SQL語句的方法中不需要設置SQL語句

 ResultSet

executeQuery() 
          在此 PreparedStatement 對象中執行 SQL 查詢,並返回該查詢生成的 ResultSet 對象。

 int

executeUpdate() 
          在此 PreparedStatement 對象中執行 SQL 語句,該語句必須是一個 SQL 數據操作語言(Data Manipulation Language,DML)語句,比如 INSERT、UPDATE 或 DELETE 語句;或者是無返回內容的 SQL 語句,比如 DDL 語句。

 

 

6.3. 設置站位參數的值

void  setXxx(int parameterIndex,Xxx value):用於設置占位符參數,

       parameterIndex:第幾個問號. 注意:1開始.

       value:設置的真實值.

Xxx:表示數據類型.String/int/long/Double/Date

 

6.4. 代碼

package cn.sxt.jdbc._01connection;

 

import static org.junit.Assert.*;

 

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

 

import org.junit.Test;

 

//DML : 對表數據的增刪改操作,使用預編譯語句對象

public class E_DMLByPreparedStatmentDemo {

 

/*

 * 向 t_student表中插入一條數據

 * sql : insert into t_student(name,age) values ('喬峰',30)

 */

@Test

public void testInsert() throws Exception {

String sql = "insert into t_student(name,age) values (?,?)";

 

// 1.加載注冊驅動

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

 

// 2.獲取數據庫連接對象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.創建預編譯語句對象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1設置占位符參數

ps.setString(1, "東方姑娘");

ps.setInt(2, 18);

 

// 4.執行SQL語句:注意不要帶SQL參數

ps.executeUpdate();

//5.釋放資源(先開后關)

ps.close();

conn.close();

 

}

/*

 * 刪除操作: 刪除t_student表中的某一條數據

 * SQL :delete from t_student where id = 2

 */

@Test

public void testDelete() throws Exception {

String sql = "delete from t_student where id = ?";

 

// 1.加載注冊驅動

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

 

// 2.獲取數據庫連接對象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.創建預編譯語句對象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1設置占位符對應的參數值

ps.setInt(1, 1);

 

// 4.執行SQL語句

int rows = ps.executeUpdate();

System.out.println(rows);

//5.釋放資源(先開后關)

ps.close();

conn.close();

}

/*

 * 修改操作 : 修改t_student表中的某一條數據

 * SQL : update t_student set name = '虛竹',age = 50 where id = 3

 */

@Test

public void testUpdate() throws Exception {

String sql = "update t_student set name = ?,age = ? where id = ?";

 

// 1.加載注冊驅動

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

 

// 2.獲取數據庫連接對象

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");

// 3.創建預編譯語句對象

PreparedStatement ps = conn.prepareStatement(sql);

//3.1設置占位符參數對應的值

ps.setString(1, "西方失敗");

ps.setInt(2, 40);

ps.setInt(3, 4);

// 4.執行SQL語句

int rows = ps.executeUpdate();

System.out.println(rows);

//5.釋放資源(先開后關)

ps.close();

conn.close();

}

}

 

 

7. JavaWeb開發的分層設計-三層架構

7.1. DAO層設計

實際開發中,JavaWeb開發代碼一般分為三層,分層結構是JavaWeb開發中的一種設計思想,這樣會讓我們開發層次分明,每一層只要完成對應的功能即可,使得項目便於開發和維護

 

1 . Web/表現層 : 主要接受前台瀏覽器用戶的參數,給瀏覽器響應數據等等

  1. Service/業務成/服務層:主要處理業務功能,日志,權限,事物,等等
  2. DAO/持久層 :專門負責和數據庫交互,數據處理相關代碼

 

DAO Data Access Object 數據訪問對象

 

實際開發中 用戶請求到-Web--->Service-->DAO

 

7.2. DAO思想

 

 

7.3. 使用DAO以后代碼的以及包的設計結構

開發中如果使用的分層,編寫的包和類名接口名等等都是有固定規則,不能隨便瞎寫

7.3.1. DAO層接口包命名

 

公司域名倒寫+項目名稱/模塊名稱+dao

如 : cn.sxt.crm.dao

7.3.2. DAO層實現類包命名

 

公司域名倒寫+項目名稱/模塊名稱+dao+impl

如 : cn.sxt.crm.dao.impl

 

7.3.3. DAO層操作對應表的接口命名

 

對應表的名稱 + Dao/DAO

 

如 : StudentDao/DAO , TeacherDao/DAO

 

7.3.4. DAO層操作對應表的實現類命名

 

對應表的名稱 + Dao/DAOImpl

 

如 : StudentDaoImpl/DAOImpl , TeacherDaoImpl/DAOImpl

7.3.5. 數據表對應的Javadomain/pojo包命名

POJOPlain Ordinary Java Object)簡單的Java對象
domian : 域對象

    

 

公司域名倒寫+項目名稱/模塊名稱+domain/pojo

如 : cn.sxt.crm.domain

 

7.3.6. 對應的測試包命名

公司域名倒寫+項目名稱/模塊名稱+test

如 : cn.sxt.crm.test

7.3.7. 項目的工具類包命名

公司域名倒寫+項目名稱/模塊名稱+util/utils

如 : cn.sxt.crm.util/utils

 

 

7.3.8. DAO代碼設計結構

 

 

7.3.9. Dao的實現類代碼

  1 package cn.sxt.jdbc.dao.impl;
  2 
  3 import java.sql.Connection;
  4 import java.sql.DriverManager;
  5 import java.sql.PreparedStatement;
  6 import java.sql.ResultSet;
  7 import java.sql.SQLException;
  8 import java.util.ArrayList;
  9 import java.util.List;
 10 
 11 import cn.sxt.jdbc.dao.StudentDao;
 12 import cn.sxt.jdbc.domain.Student;
 13 
 14 public class StudentDaoImpl implements StudentDao {
 15 
 16     @Override
 17     public int saveStudent(Student stu) {
 18         String sql = "insert into t_student(name,age) values (?,?)";
 19         
 20         Connection conn = null;
 21         PreparedStatement ps = null;
 22         try {
 23             
 24             // 1.加載注冊驅動
 25             Class.forName("com.mysql.jdbc.Driver");
 26 
 27             // 2.獲取數據庫連接對象
 28             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 29             // 3.創建預編譯語句對象
 30             ps = conn.prepareStatement(sql);
 31             //3.1設置占位符參數
 32             ps.setString(1, stu.getName());
 33             ps.setInt(2, stu.getAge());
 34             
 35             // 4.執行SQL語句:注意不要帶SQL參數
 36             return ps.executeUpdate();
 37             
 38             
 39         } catch (Exception e) {
 40             e.printStackTrace();
 41         }finally {
 42             //5.釋放資源(先開后關)
 43             try {
 44                 if(ps !=null) {
 45                     ps.close();
 46                 }
 47             } catch (SQLException e) {
 48                 e.printStackTrace();
 49             }finally {
 50                 try {
 51                     if(conn !=null) {
 52                         conn.close();
 53                     }
 54                 } catch (SQLException e) {
 55                     // TODO Auto-generated catch block
 56                     e.printStackTrace();
 57                 }
 58             }
 59         }
 60         return 0;
 61     }
 62 
 63     @Override
 64     public int deleteById(int id) {
 65         
 66         String sql = "delete from t_student where id = ?";
 67         
 68         Connection conn = null;
 69         PreparedStatement ps = null;
 70         try {
 71             
 72             // 1.加載注冊驅動
 73             Class.forName("com.mysql.jdbc.Driver");
 74 
 75             // 2.獲取數據庫連接對象
 76             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
 77             // 3.創建預編譯語句對象
 78             ps = conn.prepareStatement(sql);
 79             //3.1設置占位符參數
 80             ps.setInt(1, id);
 81             
 82             // 4.執行SQL語句:注意不要帶SQL參數
 83             return ps.executeUpdate();
 84             
 85             
 86         } catch (Exception e) {
 87             e.printStackTrace();
 88         }finally {
 89             //5.釋放資源(先開后關)
 90             try {
 91                 if(ps !=null) {
 92                     ps.close();
 93                 }
 94             } catch (SQLException e) {
 95                 e.printStackTrace();
 96             }finally {
 97                 try {
 98                     if(conn !=null) {
 99                         conn.close();
100                     }
101                 } catch (SQLException e) {
102                     // TODO Auto-generated catch block
103                     e.printStackTrace();
104                 }
105             }
106         }
107         return 0;
108     }
109 
110     @Override
111     public int updateStudentById(Student stu) {
112         
113         String sql = "update t_student set name = ?,age = ? where id = ?";
114         
115         Connection conn = null;
116         PreparedStatement ps = null;
117         try {
118             
119             // 1.加載注冊驅動
120             Class.forName("com.mysql.jdbc.Driver");
121 
122             // 2.獲取數據庫連接對象
123             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
124             // 3.創建預編譯語句對象
125             ps = conn.prepareStatement(sql);
126             //3.1設置占位符參數
127             ps.setString(1, stu.getName());
128             ps.setInt(2, stu.getAge());
129             ps.setInt(3, stu.getId());
130             // 4.執行SQL語句:注意不要帶SQL參數
131             return ps.executeUpdate();
132             
133             
134         } catch (Exception e) {
135             e.printStackTrace();
136         }finally {
137             //5.釋放資源(先開后關)
138             try {
139                 if(ps !=null) {
140                     ps.close();
141                 }
142             } catch (SQLException e) {
143                 e.printStackTrace();
144             }finally {
145                 try {
146                     if(conn !=null) {
147                         conn.close();
148                     }
149                 } catch (SQLException e) {
150                     // TODO Auto-generated catch block
151                     e.printStackTrace();
152                 }
153             }
154         }
155         return 0;
156     }
157 
158     @Override
159     public Student selectById(int id) {
160         String sql = "select * from t_student where id = ?";
161         
162         Connection conn = null;
163         PreparedStatement ps = null;
164         ResultSet rs = null;
165         
166         try {
167             // 1.加載注冊驅動
168             Class.forName("com.mysql.jdbc.Driver");
169 
170             // 2.獲取數據庫連接對象
171             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
172             // 3.創建語句對象
173             ps = conn.prepareStatement(sql);
174             //3.1設置占位符參數對應的值
175             ps.setInt(1, id);
176             
177             // 4.執行SQL語句
178             rs = ps.executeQuery();
179             if(rs.next()) {
180                 //通過數據庫數據和Java對應的數據類型獲取對應的只
181                 String name = rs.getString("name");
182                 int age = rs.getInt("age");
183                 //System.out.println(id+","+name+","+age);
184                 
185                 //將獲取的數據封裝成對應的Student對象
186                 Student stu = new  Student(id, name, age);
187                 
188                 return stu;
189             }
190             
191         } catch (Exception e) {
192             // TODO: handle exception
193         }finally {
194             try {
195                 if(rs !=null) {
196                     rs.close();
197                 }
198             } catch (SQLException e) {
199                 e.printStackTrace();
200             }finally {
201                 try {
202                     if(ps !=null) {
203                         ps.close();
204                     }
205                 } catch (SQLException e) {
206                     e.printStackTrace();
207                 }finally {
208                     try {
209                         if(conn !=null) {
210                             conn.close();
211                         }
212                     } catch (SQLException e) {
213                         e.printStackTrace();
214                     }
215                 }
216             }
217         }
218         
219         return null;
220     }
221 
222     @Override
223     public List<Student> selectList() {
224         String sql = "select * from t_student";
225         //創建list集合用於封裝Student對象
226         List<Student> stus = new ArrayList<>();
227         
228         Connection conn = null;
229         PreparedStatement ps = null;
230         ResultSet rs = null;
231         
232         try {
233             
234             // 1.加載注冊驅動
235             Class.forName("com.mysql.jdbc.Driver");
236 
237             // 2.獲取數據庫連接對象
238             conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "root");
239             // 3.創建語句對象
240             ps = conn.prepareStatement(sql);
241             
242             // 4.執行SQL語句
243             rs = ps.executeQuery();
244             while(rs.next()) {
245                 //通過數據庫數據和Java對應的數據類型獲取對應的只
246                 int id = rs.getInt("id");
247                 String name = rs.getString("name");
248                 int age = rs.getInt("age");
249                 //System.out.println(id+","+name+","+age);
250                 
251                 //將獲取的數據封裝成對應的Student對象
252                 Student stu = new  Student(id, name, age);
253                 //將一個個Student對象添加到list集合中
254                 stus.add(stu);
255             }
256             
257         } catch (Exception e) {
258             // TODO: handle exception
259         }finally {
260             try {
261                 if(rs !=null) {
262                     rs.close();
263                 }
264             } catch (SQLException e) {
265                 e.printStackTrace();
266             }finally {
267                 try {
268                     if(ps !=null) {
269                         ps.close();
270                     }
271                 } catch (SQLException e) {
272                     e.printStackTrace();
273                 }finally {
274                     try {
275                         if(conn !=null) {
276                             conn.close();
277                         }
278                     } catch (SQLException e) {
279                         e.printStackTrace();
280                     }
281                 }
282             }
283         }
284         
285         return stus;
286     }
287 
288 }

 

 

7.3.10. 快速生成單元測試類

一個dao層或者service編寫代碼以后,需要為每一個功能都進行單元測試,一個dao中的方法很多。我們快速為這個dao層的類生成單元測試類,(dao的每一個方法都自動生成一個測試方法)

 

 

 

 

 

 

 

 

 

 

 

7.4. 代碼初步重構

上述的DAO方法中的代碼,存在的問題:

 

問題1:每個DAO方法中都會寫:驅動名稱/url/賬號/密碼,不利於維護.

    解決方案: 聲明為成員變量即可.(在被類中任何地方都可以訪問)

 

問題2:問題1的解決方案有問題.

    每個DAO實現類里都有一模一樣的4行代碼,不利於維護(考慮有100個DAO實現類,就得重復99次).

    解決方案: 把驅動名稱/url/賬號/密碼這四行代碼,專門抽取到一個JDBC的工具類中.---->JdbcUtil.

問題3:其實DAO方法,每次操作都只想需要Connection對象即可,而不關心是如何創建的.

    解決方案:把創建Connection的代碼,抽取到JdbcUtil中,並提供方法getConn用於向調用者返回Connection對象即可.

問題4:每次調用者調用getConn方法的時候,都會創建一個Connection對象.

      但是,每次都會加載注冊驅動一次.--->沒必要的.

      解決方案:把加載注冊驅動的代碼放在靜態代碼塊中--->只會在所在類被加載進JVM的時候,執行一次.

問題5:每個DAO方法都要關閉資源.(雞肋代碼).

      解決方案:把關閉資源的代碼,抽取到JdbcUtil中.

      public static void close(Connection conn, Statement st, ResultSet rs) {}

      調用者:

        DML:  JdbcUtil.close(conn,st,null);

        DQL:  JdbcUtil.close(conn,st,rs);

問題6 :連接數據庫的賬號密碼寫死在JdbcUtil工具類中了,不利於維護

     抽取 db.properties 配置文件,將數據庫對應的賬號密碼寫到配置文件中,然后使用程序讀取配置文件內容即可

 

7.4.1. JdbcUtil工具類

 1 package cn.sxt.jdbc.util;
 2 
 3 import java.io.InputStream;
 4 import java.sql.Connection;
 5 import java.sql.DriverManager;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.sql.SQLException;
 9 import java.util.Properties;
10 
11 
12 public class JdbcUtil {
13 
14     // alt+shif+a 多行修改,修改以后還原 alt+shif+a
15 
16     /*private static String driverClassName = "com.mysql.jdbc.Driver";
17     private static String url = "jdbc:mysql://localhost:3306/jdbcdemo";
18     private static String username = "root";
19     private static String password = "root";*/
20     
21     private static Properties p = new Properties();
22     
23     static {
24         try {
25             //1.獲取類加載器
26             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
27             //2,使用類加載器獲取項目 類路徑下面的文件
28             InputStream inputStream = classLoader.getResourceAsStream("db.properties");
29             
30             //3.使用Priperties加載配置文件對應的輸入流
31             p.load(inputStream);
32             
33             Class.forName(p.getProperty("driverClassName"));
34         } catch (Exception e) {
35             e.printStackTrace();
36         }
37     }
38 
39     public static Connection getConnection() {
40         try {
41             
42             return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"), p.getProperty("password"));
43         } catch (Exception e) {
44             e.printStackTrace();
45             throw new RuntimeException("親,連接數據庫失敗", e);
46         }
47     }
48     
49     public static void close(Connection conn,PreparedStatement ps,ResultSet rs) {
50         try {
51             if(rs !=null) {
52                 rs.close();
53             }
54         } catch (SQLException e) {
55             e.printStackTrace();
56         }finally {
57             try {
58                 if(ps !=null) {
59                     ps.close();
60                 }
61             } catch (SQLException e) {
62                 e.printStackTrace();
63             }finally {
64                 try {
65                     if(conn !=null) {
66                         conn.close();
67                     }
68                 } catch (SQLException e) {
69                     e.printStackTrace();
70                 }
71             }
72         }
73     }
74 }

 

 

7.4.2. 使用工具類以后的DAO實現類效果

  1 package cn.sxt.jdbc.dao.impl;
  2 
  3 import java.sql.Connection;
  4 import java.sql.PreparedStatement;
  5 import java.sql.ResultSet;
  6 import java.sql.SQLException;
  7 import java.util.ArrayList;
  8 import java.util.List;
  9 
 10 import cn.sxt.jdbc.dao.StudentDao;
 11 import cn.sxt.jdbc.domain.Student;
 12 import cn.sxt.jdbc.util.JdbcUtil;
 13 
 14 public class StudentDaoImpl implements StudentDao {
 15     
 16     
 17 
 18     @Override
 19     public int saveStudent(Student stu) {
 20         String sql = "insert into t_student(name,age) values (?,?)";
 21         
 22         Connection conn = null;
 23         PreparedStatement ps = null;
 24         try {
 25             conn = JdbcUtil.getConnection();
 26             
 27             // 3.創建預編譯語句對象
 28             ps = conn.prepareStatement(sql);
 29             //3.1設置占位符參數
 30             ps.setString(1, stu.getName());
 31             ps.setInt(2, stu.getAge());
 32             
 33             // 4.執行SQL語句:注意不要帶SQL參數
 34             return ps.executeUpdate();
 35             
 36         } catch (Exception e) {
 37             e.printStackTrace();
 38         }finally {
 39             JdbcUtil.close(conn, ps, null);
 40         }
 41         return 0;
 42     }
 43 
 44     @Override
 45     public int deleteById(int id) {
 46         
 47         String sql = "delete from t_student where id = ?";
 48         
 49         Connection conn = null;
 50         PreparedStatement ps = null;
 51         try {
 52             
 53             conn = JdbcUtil.getConnection();
 54             // 3.創建預編譯語句對象
 55             ps = conn.prepareStatement(sql);
 56             //3.1設置占位符參數
 57             ps.setInt(1, id);
 58             
 59             // 4.執行SQL語句:注意不要帶SQL參數
 60             return ps.executeUpdate();
 61             
 62             
 63         } catch (Exception e) {
 64             e.printStackTrace();
 65         }finally {
 66             JdbcUtil.close(conn, ps, null);
 67         }
 68         return 0;
 69     }
 70 
 71     @Override
 72     public int updateStudentById(Student stu) {
 73         
 74         String sql = "update t_student set name = ?,age = ? where id = ?";
 75         
 76         Connection conn = null;
 77         PreparedStatement ps = null;
 78         try {
 79             
 80             conn = JdbcUtil.getConnection();
 81             // 3.創建預編譯語句對象
 82             ps = conn.prepareStatement(sql);
 83             //3.1設置占位符參數
 84             ps.setString(1, stu.getName());
 85             ps.setInt(2, stu.getAge());
 86             ps.setInt(3, stu.getId());
 87             // 4.執行SQL語句:注意不要帶SQL參數
 88             return ps.executeUpdate();
 89             
 90             
 91         } catch (Exception e) {
 92             e.printStackTrace();
 93         }finally {
 94             JdbcUtil.close(conn, ps, null);
 95         }
 96         return 0;
 97     }
 98 
 99     @Override
100     public Student selectById(int id) {
101         String sql = "select * from t_student where id = ?";
102         
103         Connection conn = null;
104         PreparedStatement ps = null;
105         ResultSet rs = null;
106         
107         try {
108             conn = JdbcUtil.getConnection();
109             // 3.創建語句對象
110             ps = conn.prepareStatement(sql);
111             //3.1設置占位符參數對應的值
112             ps.setInt(1, id);
113             
114             // 4.執行SQL語句
115             rs = ps.executeQuery();
116             if(rs.next()) {
117                 //通過數據庫數據和Java對應的數據類型獲取對應的只
118                 String name = rs.getString("name");
119                 int age = rs.getInt("age");
120                 //System.out.println(id+","+name+","+age);
121                 //將獲取的數據封裝成對應的Student對象
122                 Student stu = new  Student(id, name, age);
123                 return stu;
124             }
125             
126         } catch (Exception e) {
127             // TODO: handle exception
128         }finally {
129             try {
130                 if(rs !=null) {
131                     rs.close();
132                 }
133             } catch (SQLException e) {
134                 e.printStackTrace();
135             }finally {
136                 JdbcUtil.close(conn, ps, rs);
137             }
138         }
139         
140         return null;
141     }
142 
143     @Override
144     public List<Student> selectList() {
145         String sql = "select * from t_student";
146         //創建list集合用於封裝Student對象
147         List<Student> stus = new ArrayList<>();
148         
149         Connection conn = null;
150         PreparedStatement ps = null;
151         ResultSet rs = null;
152         
153         try {
154             
155             conn = JdbcUtil.getConnection();
156             // 3.創建語句對象
157             ps = conn.prepareStatement(sql);
158             
159             // 4.執行SQL語句
160             rs = ps.executeQuery();
161             while(rs.next()) {
162                 //通過數據庫數據和Java對應的數據類型獲取對應的只
163                 int id = rs.getInt("id");
164                 String name = rs.getString("name");
165                 int age = rs.getInt("age");
166                 //System.out.println(id+","+name+","+age);
167                 
168                 //將獲取的數據封裝成對應的Student對象
169                 Student stu = new  Student(id, name, age);
170                 //將一個個Student對象添加到list集合中
171                 stus.add(stu);
172             }
173             
174         } catch (Exception e) {
175             // TODO: handle exception
176         }finally {
177             JdbcUtil.close(conn, ps, rs);
178         }
179         
180         return stus;
181     }
182 
183 }

 

7.5. 知識點補充,類加載器

在項目的 類路徑(src)下面創建一個 db.properties配置文件,專門配置連接數據庫的賬號密碼

 

如何使用類加載器加載配置文件

 

7.5.1. 配置文件

 

 

7.5.1.1. 配置文件創建的位置

配置文件一般都放在項目的src 源目錄下面

 

 

 

7.5.2. 加載代碼

 1 package cn.sxt.jdbc.test;
 2 
 3 import static org.junit.Assert.*;
 4 
 5 import java.io.InputStream;
 6 import java.util.Properties;
 7 
 8 import org.junit.Test;
 9 
10 public class PropertiesTest {
11     
12     @Test
13     public void testName() throws Exception {
14         
15          /*
16           * ClassLoader 類加載器
17           * ClassLoader :可以從項目的類路徑下面讀取對應的配置文件返回一個輸入流
18           * ClassLoader 在程序運行的時候JVM已經為每一個項目都創建了一個,我們開發者只需要獲取即可
19           * 獲取類加載器方式
20           * 1、使用當前線程
21           * ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
22           * 2、通過某一類的字節碼實例也可以獲取
23           * ClassLoader classLoader = PropertiesTest.class.getClassLoader();
24           */
25         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
26         //使用類加載器獲取項目 類路徑下面的文件
27         InputStream inputStream = classLoader.getResourceAsStream("db.properties");
28         
29         
30         /*
31          * Properties 是Map集合下面的一個 專門用於讀取配置文件的對象
32          * 可以讀取當前類路徑下面的  xxx.properites類型的配置文件
33          * 
34          * xxx.properites的內容必須是key=value 鍵值對的數據
35          */
36         
37         //1.創建Properties對象
38         Properties p = new Properties();
39         
40         //2.加載配置文件
41         p.load(inputStream);
42         
43         System.out.println(p);
44         
45         //獲取具體某一個key對應的值
46         String driverClassName = p.getProperty("driverClassName");
47         System.out.println(driverClassName);
48     }
49 }

 

7.5.3. 效果

 

 

8. 連接池

8.1. 遇到的問題-引出連接池

 

 

8.2. 連接池思想

 

 

8.3. 連接池的概述

 

Java,連接池使用javax.sql.DataSource接口來表示連接池.

 

 

 

注意:DataSource僅僅只是一個接口,由各大服務器廠商來實現(Tomcat.JBoss,阿里巴巴).

 

常用的DataSource的實現:

 

  DBCP:  Spring推薦的

 

  C3P0:  Hibernate推薦的

 

  Druid : (德魯伊)阿里巴巴開源的,性能最好,速度最快

 

DataSource(數據源)和連接池(Connection Pool)是同一個.

 

8.4. 使用連接池和不使用連接池的區別在哪里

 

 

8.5. Druid連接池的使用

8.5.1. 准備druid 連接池jar包到項目

 

從代碼上:

不使用連接池: Conenction對象由DriverManager獲取.

  Connection conn = DriverManager.getConnection(url,username,password);

 

使用連接池:

  如何創建DataSource對象,如何在DataSource中設置url,賬號,密碼.

  Connection conn = DataSource對象.getConnection();

--------------------------------------------------------------------

使用連接池的時候:

  釋放資源: Connection對象.close():

  是把Connection放回給連接池,而不是和數據庫斷開.

 

 1 package cn.sxt.jdbc.test;
 2 
 3 import static org.junit.Assert.*;
 4 
 5 import java.io.InputStream;
 6 import java.io.Reader;
 7 import java.sql.Connection;
 8 import java.util.Properties;
 9 
10 import javax.sql.DataSource;
11 
12 import org.junit.Test;
13 
14 import com.alibaba.druid.pool.DruidDataSource;
15 import com.alibaba.druid.pool.DruidDataSourceFactory;
16 import com.alibaba.druid.pool.DruidPooledConnection;
17 
18 public class DataSourceTest {
19     // 直接創建連接池對象
20     @Test
21     public void testName() throws Exception {
22         // 1.創建連接池對象
23         DruidDataSource ds = new DruidDataSource();
24         // 2.設置連接數據庫的賬號密碼
25         ds.setDriverClassName("com.mysql.jdbc.Driver");
26         ds.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
27         ds.setUsername("root");
28         ds.setPassword("root");
29         ds.setMaxActive(10);// 最大連接數
30         // 3.獲取連接對象
31         Connection conn = ds.getConnection();
32         System.out.println(conn);
33     }
34 
35     // 使用工廠對象創建連接池對象,工廠對象的好處,不需要直接設置賬號密碼等等,只需要將
36     // 連接數據庫的賬號密碼等等以指定的 key的名稱配置到 xxx.properties文件中即可,工廠對象底層自動讀取
37     @Test
38     public void testDataSourceByFactory() throws Exception {
39 
40         // 1.獲取類加載器用於加載clsspath下面的 配置文件
41         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
42         // 2.讀取druid.properties配置文件
43         InputStream inputStream = classLoader.getResourceAsStream("druid.properties");
44         // 3.創建Properties對象,並讀取配置文件對應的輸入流
45         Properties p = new Properties();
46         p.load(inputStream);
47 
48         // 4.創建連接池對象
49         DataSource ds = DruidDataSourceFactory.createDataSource(p);
50         // 5.獲取連接對象
51         Connection conn = ds.getConnection();
52         System.out.println(conn);
53     }
54 }

 

 

 

 

8.5.2. db.propperties

 

 

8.5.3. 使用Druid抽取的工具類

 

 

9. 事務

 

案例:銀行轉賬:從張無忌賬戶上給趙敏轉1000.

 

准備:account(賬戶表):

 

---------------------------------------------------------------

 

id            name(賬號,唯一)           balance(余額)

 

1             張無忌                    20000

 

2             趙敏                      0

 

---------------------------------------------------------------

 

轉賬的思路:

 

   1.檢查張無忌的賬號余額是否大於等於1000.

 

        SQL: SELECT balance FROM account WHERE name = '張無忌' AND balance >=1000

 

        余額>=1000:GOTO 2:

 

        余額 <1000:提示:,你的余額不足.

 

   2.在張無忌的賬號余額上減少1000.

 

        SQL: UPDATE account SET balance = balance-1000 WHERE name = '張無忌'

 

   3.在趙敏的賬戶余額尚增加1000.

 

        SQL: UPDATE account SET balance = balance+1000 WHERE name = '趙敏'

 

-------------------------------------------------------------------------------------------

 

注意:在第二步和第三步之間,停電了.

 

     使用異常模擬停電:System.out.println(1/0);

 

9.1. 事務概述

 

事務(Transaction,簡寫為tx):

在數據庫中,所謂事務是指一組邏輯操作單元,使數據從一種狀態變換到另一種狀態。

為確保數據庫中數據的一致性,數據的操縱應當是離散的成組的邏輯單元:

  當每個邏輯操作單元全部完成時,數據的一致性可以保持,

  而當這個單元中的一部分操作失敗,整個事務應全部視為錯誤,所有從起始點以后的操作應全部回退到開始狀態。

 

事務的操作:先定義開始一個事務,然后對數據作修改操作,這時如果提交(commit),這些修改就永久地保存下來,如果回退(rollback),數據庫管理系統將放棄您所作的所有修改而回到開始事務時的狀態。

 

--------------------------------------------------

事務的ACID屬性:

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

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

3. 隔離性(Isolation

事務的隔離性是指一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對並發的其他事務是隔離的,並發執行的各個事務之間不能互相干擾。

4. 持久性(Durability
持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來的其他操作和數據庫故障不應該對其有任何影響

 

--------------------------------------------------

事務:指構成單個邏輯工作單元的操作集合

事務處理:保證所有事務都作為一個工作單元來執行,即使出現了故障,都不能改變這種執行方式。當在一個事務中執行多個操作時,要么所有的事務都被提交(commit),要么整個事務回滾(rollback)到最初狀態

處理事務的兩個動作:

       提交:commit:   當整個事務中,所有的邏輯單元都正常執行成功.  ---->提交事務.---數據已經提交,不能更改.

       回滾:rollback: 當整個事務中,有一個邏輯單元執行失敗,        ---->回滾事務.  

                      撤銷該事務中的所有操作--->恢復到最初的狀態.

 

---------------------------------------------------------------------------------------------------

如何在代碼中去處理事務:

1.JDBC,事務是默認自動提交的.  必須先設置事務為手動提交.

connection對象.setAutoCommit(false);//設置事務為手動提交.

2.手動的提交事務.

connection對象.commit();

3.若出現異常必須回滾事務:

   不回滾事務,總余額依然是正確的. 若不回滾事務,不會釋放數據庫資源.

   connection對象.rollback();

-----------------------------------------------------------------------------------

1.JDBC在事務是默認提交的,那是在什么時候提交的.

在執行一個DML/DDL操作的時候,就已經提交事務了.

2.針對於CRUD操作. 只有DML操作才有事務,查詢操作沒有事務.

  但是,我們一般會把查詢也放在事務里面.

  1. 以后,凡是發現自己編寫的代碼是正確的,測試也通過,但是就是數據庫表中的數據不變----->事務沒提交的問題.

 

 

4.MySQL,InnoDB支持外鍵.支持事務,MyISAM不支持外鍵,不支持事務.

 

 

InnoDB存儲引擎: 支持事務,支持外鍵,但是查詢效率略低,(金融,理財,p2p

MyISAM存儲引擎:不支持事務和外鍵,但是查詢效率較高(新聞網站)

 

Oracle 不存在存儲引擎,都有事務

 

9.2. 事務處理代碼

 1 public class TransactionTest {
 2     @Test
 3     public void testName() throws Exception {
 4         Connection conn = null;
 5         Statement st = null;
 6         ResultSet rs = null;
 7         try {
 8             conn = DruidUtil.getConnection();
 9             //將事務設置為手動提交
10             conn.setAutoCommit(false);
11             
12             st = conn.createStatement();
13             // 1.檢查張無忌的賬號余額是否大於等於1000.
14             rs = st.executeQuery("SELECT balance FROM account WHERE name = '張無忌' AND balance >=1000");
15             if(!rs.next()) {
16                 throw new RuntimeException("親,您的賬戶余額不夠");
17             }
18             // 余額>=1000:GOTO 2:
19             // 余額 <1000:提示:親,你的余額不足.
20             // 2.在張無忌的賬號余額上減少1000.
21             st.executeUpdate("UPDATE account SET balance = balance-1000 WHERE name = '張無忌'");
22             
23             System.out.println(1/0);
24             
25             // 3.在趙敏的賬戶余額尚增加1000.
26             st.executeUpdate("UPDATE account SET balance = balance+1000 WHERE name = '趙敏'");
27             
28             //提交事務
29             conn.commit();
30         
31             
32         } catch (Exception e) {
33             e.printStackTrace();
34             //回滾事務
35             conn.rollback();
36             
37         }finally {
38             DruidUtil.close(conn, st, rs);
39         }
40         
41     }
42 }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM