PostgreSql?JDBC事務(wù)操作方法詳解
JDBC事務(wù)相關(guān)方法簡(jiǎn)介
本文將借助示例,簡(jiǎn)單講解下JDBC操作Pg事務(wù)的流程。
首先來簡(jiǎn)單講解下事務(wù)的定義:為了確保兩個(gè)(多個(gè))數(shù)據(jù)庫(kù)操作都生效,或者兩個(gè)操作都不發(fā)生,可以使用事務(wù)。根據(jù)定義,事務(wù)是作為單個(gè)單元執(zhí)行的一組語句。換句話說,要么所有語句都成功執(zhí)行,要么沒有執(zhí)行。
禁用自動(dòng)提交模式
當(dāng)建立與PostgreSQL數(shù)據(jù)庫(kù)的連接時(shí),它處于自動(dòng)提交模式。這意味著每個(gè)SQL語句都被視為事務(wù)并自動(dòng)提交。
如果要在事務(wù)中封裝一個(gè)或多個(gè)語句,則必須禁用自動(dòng)提交模式。為此,我們可以調(diào)用Connection.setAutoCommit()方法來修改SQL提交模式:
Connection.setAutoCommit(false);
最佳做法是僅對(duì)事務(wù)模式禁用自動(dòng)提交模式。它避免為多個(gè)語句保留數(shù)據(jù)庫(kù)鎖。
提交事務(wù)
要提交事務(wù),請(qǐng)調(diào)用Connection對(duì)象的commit方法,如下所示:
Connection.commit();
當(dāng)調(diào)用commit()方法,所有前面的SQL語句作為一個(gè)單元一起提交。
回滾事務(wù)
既然使用了事務(wù),那我們肯定會(huì)有回滾的時(shí)候,我們可以使用rollback()方法來中止當(dāng)前事務(wù)并將值恢復(fù)為原始值。
Connection.rollback();
PostgreSQL JDBC 事務(wù)示例
讓我們舉一個(gè)使用JDBC API執(zhí)行PostgreSQL事務(wù)的示例。
首先,創(chuàng)建一個(gè)表示ProRank的實(shí)體類,如下所示:
import lombok.Data;
@Data
public class ProRank {
Integer id;
String name;
String team;
String line;
Integer rank;
}
然后,編寫以下代碼,供我們測(cè)試事務(wù)操作。
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.sql.*;
@SpringBootTest
class JdbcTrasationTests {
private final String url = "jdbc:p6spy:postgresql://localhost:5432/postgres";
private final String user = "postgres";
private final String password = "112233";
/**
* 連接PostgreSql數(shù)據(jù)庫(kù)
*
* @return Connection
* @throws SQLException
*/
public Connection connect() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
@Test
void testTrasation() {
ProRank proRank = new ProRank();
proRank.setLine("Mid");
proRank.setName("Faker");
proRank.setTeam("T1");
proRank.setRank(0);
//調(diào)用
addProAndUpdateRank(proRank,2222);
}
/**
* 關(guān)閉一個(gè)AutoCloseable對(duì)象
*
* @param closeable
*/
private void close(AutoCloseable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
/**
* 插入一條選手記錄,更新他的rank值
*
* @param proRank
* @param rank
*/
public void addProAndUpdateRank(ProRank proRank, Integer rank) {
Connection conn = null;
PreparedStatement pstmt = null;
PreparedStatement pstmt2 = null;
ResultSet rs = null;
// 插入一條數(shù)據(jù)
String SQL = "INSERT INTO pro_rank(name,team,line,rank) VALUES(?,?,?,?)";
// 更新他的rank值
String SQLUpdateRank = "UPDATE pro_rank SET rank = ? WHERE id = ?;";
int id = 0;
try {
// 鏈接數(shù)據(jù)庫(kù)
conn = connect();
conn.setAutoCommit(false);
// 插入一條數(shù)據(jù)
pstmt = conn.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, proRank.getName());
pstmt.setString(2, proRank.getTeam());
pstmt.setString(3, proRank.getLine());
pstmt.setInt(4, proRank.getRank());
int affectedRows = pstmt.executeUpdate();
// 判斷是否生效
if (affectedRows > 0) {
// 獲取返回的id
rs = pstmt.getGeneratedKeys();
if (rs.next()) {
id = rs.getInt(1);
if (id > 0) {
pstmt2 = conn.prepareStatement(SQLUpdateRank);
pstmt2.setInt(2, id);
pstmt2.setInt(1, rank);
pstmt2.executeUpdate();
}
}
} else {
// 如果新增數(shù)據(jù)失敗,回滾
conn.rollback();
}
// 提交事務(wù)
conn.commit();
System.out.println("插入選手?jǐn)?shù)據(jù)成功!更新選手rank成功,數(shù)據(jù)id:" + id);
} catch (SQLException sqlException) {
System.out.println(sqlException.getMessage());
sqlException.printStackTrace();
// 回滾事務(wù)
System.out.println("回滾事務(wù)...");
try {
if (conn != null) {
conn.rollback();
}
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
} finally {
close(rs);close(pstmt);close(pstmt2);close(conn);
}
}
}
讓我們看一下上面的代碼,他包含三個(gè)方法
connect() 方法建立與數(shù)據(jù)庫(kù)連接,并返回連接對(duì)象。
close() 方法關(guān)閉數(shù)據(jù)庫(kù)操作可關(guān)閉的對(duì)象,如Resultset、Statement和Connection。
addProAndUpdateRank()方法插入新的選手,并在事務(wù)中更新選手的rank字段。此方法包含邏輯如下:
- 首先,在
pro_rank表中插入一條新的選手?jǐn)?shù)據(jù)。 - 接下來,獲取新插入的選手?jǐn)?shù)據(jù)的id
- 然后,更新插入選手的rank值。
- 之后,如果步驟2和3均成功,則提交事務(wù)。否則,回滾事務(wù)
- 最后,關(guān)閉ResultSet、PreparedStatement和Connection對(duì)象。
如果我們?cè)诘谝粋€(gè)場(chǎng)景中執(zhí)行程序,我們會(huì)得到以下結(jié)果:
插入選手?jǐn)?shù)據(jù)成功!更新選手rank成功,數(shù)據(jù)id:14

我們可以通過查詢pro_rank表格,來查看上述代碼執(zhí)行結(jié)果:
SELECT * FROM "public"."pro_rank" LIMIT 1000 OFFSET 0;

現(xiàn)在,讓我們測(cè)試一下事務(wù)回滾的情況,比如,我們可以在插入一條數(shù)據(jù)的時(shí)候,將name字段賦值為超出數(shù)據(jù)庫(kù)長(zhǎng)度的字串,運(yùn)行程序結(jié)果如下:

ERROR: value too long for type character varying(7)

事務(wù)將回滾,并且沒有任何內(nèi)容插入pro_rank表
以上就是PostgreSql JDBC事務(wù)操作方法詳解的詳細(xì)內(nèi)容,更多關(guān)于PostgreSql JDBC事務(wù)操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PostgreSQL忘記postgres賬號(hào)密碼的解決方法
這篇文章主要介紹了PostgreSQL忘記postgres賬號(hào)的密碼的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
在PostgreSQL中使用ltree處理層次結(jié)構(gòu)數(shù)據(jù)的方法
這篇文章主要介紹了在PostgreSQL中使用ltree處理層次結(jié)構(gòu)數(shù)據(jù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
使用PostgreSQL的JSONB數(shù)據(jù)類型進(jìn)行高效查詢的示例代碼
PostgreSQL的JSONB數(shù)據(jù)類型提供了一種靈活的方式來存儲(chǔ)和查詢JSON格式的數(shù)據(jù),下面我們將詳細(xì)討論如何使用JSONB數(shù)據(jù)類型進(jìn)行高效查詢,并提供相應(yīng)的解決方案和示例代碼,需要的朋友可以參考下2024-04-04
postgresql使用filter進(jìn)行多維度聚合的解決方法
這篇文章給大家介紹postgresql使用filter進(jìn)行多維度聚合的解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-07-07
Postgresql根據(jù)響應(yīng)數(shù)據(jù)反向?qū)崿F(xiàn)建表語句與insert語句的過程
根據(jù)已有數(shù)據(jù),可構(gòu)建名為products的表,包含id(自增主鍵)、title(非空字符串)、progress(非空整數(shù))三個(gè)字段,建表后,可通過insert語句插入數(shù)據(jù),這種反向操作有助于從現(xiàn)有數(shù)據(jù)結(jié)構(gòu)出發(fā),快速構(gòu)建數(shù)據(jù)庫(kù)表,并進(jìn)行數(shù)據(jù)填充,感興趣的朋友跟隨小編一起看看吧2022-02-02
基于PostgreSQL/openGauss?的分布式數(shù)據(jù)庫(kù)解決方案
ShardingSphere-Proxy?作為透明數(shù)據(jù)庫(kù)代理,用戶無需關(guān)心?Proxy?如何協(xié)調(diào)背后的數(shù)據(jù)庫(kù)。今天通過本文給大家介紹基于PostgreSQL/openGauss?的分布式數(shù)據(jù)庫(kù)解決方案,感興趣的朋友跟隨小編一起看看吧2021-12-12

