PostgreSql JDBC事务操作方法详解

目录
  • JDBC事务相关方法简介
  • 禁用自动提交模式
  • 提交事务
  • 回滚事务
  • PostgreSQL JDBC 事务示例

JDBC事务相关方法简介

本文将借助示例,简单讲解下JDBC操作Pg事务的流程。

首先来简单讲解下事务的定义:为了确保两个(多个)数据库操作都生效,或者两个操作都不发生,可以使用事务。根据定义,事务是作为单个单元执行的一组语句。换句话说,要么所有语句都成功执行,要么没有执行。

禁用自动提交模式

当建立与PostgreSQL数据库的连接时,它处于自动提交模式。这意味着每个SQL语句都被视为事务并自动提交。

如果要在事务中封装一个或多个语句,则必须禁用自动提交模式。为此,我们可以调用Connection.setAutoCommit()方法来修改SQL提交模式:

Connection.setAutoCommit(false);

最佳做法是仅对事务模式禁用自动提交模式。它避免为多个语句保留数据库锁。

提交事务

要提交事务,请调用Connection对象的commit方法,如下所示:

Connection.commit();

当调用commit()方法,所有前面的SQL语句作为一个单元一起提交。

回滚事务

既然使用了事务,那我们肯定会有回滚的时候,我们可以使用rollback()方法来中止当前事务并将值恢复为原始值。

Connection.rollback();

PostgreSQL JDBC 事务示例

让我们举一个使用JDBC API执行PostgreSQL事务的示例。

首先,创建一个表示ProRank的实体类,如下所示:

import lombok.Data;
@Data
public class ProRank {
    Integer id;
    String name;
    String team;
    String line;
    Integer rank;
}

然后,编写以下代码,供我们测试事务操作。

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数据库
     *
     * @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);
        //调用
        addProAndUpdateRank(proRank,2222);
    }
    /**
     * 关闭一个AutoCloseable对象
     *
     * @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;
        // 插入一条数据
        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 {
            // 链接数据库
            conn = connect();
            conn.setAutoCommit(false);
            // 插入一条数据
            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 {
                // 如果新增数据失败,回滚
                conn.rollback();
            }
            // 提交事务
            conn.commit();
            System.out.println("插入选手数据成功!更新选手rank成功,数据id:" + id);
        } catch (SQLException sqlException) {
            System.out.println(sqlException.getMessage());
            sqlException.printStackTrace();
            // 回滚事务
            System.out.println("回滚事务...");
            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);
        }
    }
}

让我们看一下上面的代码,他包含三个方法

connect() 方法建立与数据库连接,并返回连接对象。

close() 方法关闭数据库操作可关闭的对象,如Resultset、Statement和Connection。

addProAndUpdateRank()方法插入新的选手,并在事务中更新选手的rank字段。此方法包含逻辑如下:

  • 首先,在pro_rank表中插入一条新的选手数据。
  • 接下来,获取新插入的选手数据的id
  • 然后,更新插入选手的rank值。
  • 之后,如果步骤2和3均成功,则提交事务。否则,回滚事务
  • 最后,关闭ResultSet、PreparedStatement和Connection对象。

如果我们在第一个场景中执行程序,我们会得到以下结果:

插入选手数据成功!更新选手rank成功,数据id:14

我们可以通过查询pro_rank表格,来查看上述代码执行结果:

SELECT * FROM "public"."pro_rank" LIMIT 1000 OFFSET 0;

现在,让我们测试一下事务回滚的情况,比如,我们可以在插入一条数据的时候,将name字段赋值为超出数据库长度的字串,运行程序结果如下:

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

事务将回滚,并且没有任何内容插入pro_rank表

以上就是PostgreSql JDBC事务操作方法详解的详细内容,更多关于PostgreSql JDBC事务操作的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java使用JDBC连接postgresql数据库示例

    本文实例讲述了Java使用JDBC连接postgresql数据库.分享给大家供大家参考,具体如下: package tool; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class PsqlConnectionTool { p

  • springboot+springJdbc+postgresql 实现多数据源的配置

    背景 最近公司在服务拆迁,接口转移,相同的功能接口到要迁移到对应的服务中,因为时间比较赶,别问为什么没给时间,没人,没资源,但是活还是得干的,为了减少工作量和稳妥的需要分两步走 先迁移相关代码,保证包的路径不变,请求接口的路径不变 将迁移的相关代码进行迁表迁库(这目前还没做,计划9月实施) 实施 配置文件 数据库配置相关类 import com.alibaba.druid.pool.DruidDataSource; import java.io.Serializable; import java

  • Postgresql删除数据库表中重复数据的几种方法详解

    一直使用Postgresql数据库,有一张表是这样的: DROP TABLE IF EXISTS "public"."devicedata"; CREATE TABLE "public"."devicedata" ( "Id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL, "DeviceId&qu

  • 史上最全PostgreSQL DBA最常用SQL

    目录 背景 常用查询 背景 建立视图, 方便查询 create schema dba; create view dba.invalid_index as select indisvalid, indexrelid::regclass, indrelid::regclass, pg_get_indexdef(indexrelid) from pg_index where not indisvalid; create view dba.ro_conflicts as select datname,p

  • PostgreSQL 数组类型操作使用及特点详解

    目录 PostgreSQL 数组类型使用详解 下面列出一些PostgreSQL的特点 数组类型的基本操作 1 查询 2 插入数据 3 条件查询 4 更新 4.1 更新标签的名称 4.2 添加一个标签 5 删除 总结 PostgreSQL 数组类型使用详解 可能大家对 PostgreSQL这个关系型数据库不太熟悉,因为大部分人最熟悉的,公司用的最多的是 MySQL 我们先对PostgreSQL数据库 (下面简称 PG)简单的介绍一下,以后有机会,再单独写一篇专门介绍pgSql的文章 The Wor

  • JDBC中使用Java8的日期LocalDate和LocalDateTime操作mysql、postgresql

    前言 相信大家应该都知道,在实体Entity里面,可以使用java.sql.Date.java.sql.Timestamp.java.util.Date来映射到数据库的date.timestamp.datetime等字段 但是,java.sql.Date.java.sql.Timestamp.java.util.Date这些类都不好用,很多方法都过时了. Java8里面新出来了一些API,LocalDate.LocalTime.LocalDateTime 非常好用 如果想要在JDBC中,使用Ja

  • PostgreSql JDBC事务操作方法详解

    目录 JDBC事务相关方法简介 禁用自动提交模式 提交事务 回滚事务 PostgreSQL JDBC 事务示例 JDBC事务相关方法简介 本文将借助示例,简单讲解下JDBC操作Pg事务的流程. 首先来简单讲解下事务的定义:为了确保两个(多个)数据库操作都生效,或者两个操作都不发生,可以使用事务.根据定义,事务是作为单个单元执行的一组语句.换句话说,要么所有语句都成功执行,要么没有执行. 禁用自动提交模式 当建立与PostgreSQL数据库的连接时,它处于自动提交模式.这意味着每个SQL语句都被视

  • JSP 中spring事务配置详解

    JSP 中spring事务配置详解 前几天被问到,如何防止服务器宕机,造成的数据操作的不完全. 问了一下同事,是事务.哎,恍然大悟,迷糊一时了. 声明式的事务配置,这个是最推荐的,配置到service层. <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context=&

  • Spring JDBC的使用详解

    JDBC介绍 从这篇文章开始,我们将会介绍SpringBoot另外一个核心的技术,即数据库访问技术,提到数据访问,学习Java的同学瞬间能就想起JDBC技术,JDBC 是 Java Database Connectivity 的全称,是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的一套标准的API,这套标准不同的数据库厂家之间共同准守,并提供各自的具体实现.如图所示: 这样设计的好处,就是Java程序只需要和JDBC API交互,从而屏蔽了访问

  • jQuery中each()、find()和filter()等节点操作方法详解(推荐)

    1.each(callback) 官方解释: 返回值:jQuery 概述 以每一个匹配的元素作为上下文来执行一个函数. 意味着,每次执行传递进来的函数时,函数中的this关键字都指向一个不同的DOM元素(每次都是一个不同的匹配元素).而且,在每次执行函数时,都会给函数传递一个表示作为执行环境的元素在匹配的元素集合中所处位置的数字值作为参数(从零开始的整型). 返回 'false' 将停止循环 (就像在普通的循环中使用 'break').返回 'true' 跳至下一个循环(就像在普通的循环中使用'

  • Python之str操作方法(详解)

    1. str.format():使用"{}"占位符格式化字符串(占位符中的索引号形式和键值对形式可以混合使用). >>> string = 'python{}, django{}, tornado{}'.format(2.7, 'web', 'tornado') # 有多少个{}占位符就有多少个值与其对应,按照顺序"填"进字符串中 >>> string 'python2.7, djangoweb, tornadotornado'

  • django基础之数据库操作方法(详解)

    Django 自称是"最适合开发有限期的完美WEB框架".本文参考<Django web开发指南>,快速搭建一个blog 出来,在中间涉及诸多知识点,这里不会详细说明,如果你是第一次接触Django ,本文会让你在感性上对Django有个认识,完成本文操作后会让你有兴趣阅读的相关书籍和文档. 本文客操作的环境,如无特别说明,后续都以下面的环境为基础: =================== Windows 7/10 python 3.5 Django 1.10 ======

  • Python之re操作方法(详解)

    一:re.search():search返回的是查找结果的对象,可以使用group()或groups()方法得到匹配成功的字符串. ①group() 默认返回匹配成功的整个字符串(忽略pattern中的括号),也可以指定返回匹配成功的括号中第几个字符串(从1开始计数): ②groups() 以元组的形式返回匹配成功的pattern中括号中的内容,若pattern中没有括号,则返回空元组. 以上这篇Python之re操作方法(详解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多

  • Python之os操作方法(详解)

    1. os.path.driname(path):返回路径的上一级路径字符串. >>> os.path.dirname('D:\Games') 'D:\\' >>> 2. os.path.basename(path):返回路径的最后一级目录名(文件夹名)或文件名(全称). >>> os.path.basename('D:\Games\9yin_632\蜗牛整包\\0x0804.ini') '0x0804.ini' >>> 3. os.

  • mysql的存储过程、游标 、事务实例详解

    mysql的存储过程.游标 .事务实例详解 下面是自己曾经编写过的mysql数据库存储过程,留作存档,以后用到的时候拿来参考. 其中,涉及到了存储过程.游标(双层循环).事务. [说明]:代码中的注释只针对当时业务而言,无须理会. 代码如下: DELIMITER $$ DROP PROCEDURE IF EXISTS `transferEmailTempData`$$ CREATE PROCEDURE transferEmailTempData(IN jobId VARCHAR(24)) BEG

  • jquery属性,遍历,HTML操作方法详解

    Jquery属性遍历.HTML操作. Jquery拥有可操作HTML元素和属性的强大方法. 下面是我整理的一些jquery遍历函数: .add() 将元素添加到匹配元素的集合中. .andSelf() 把堆栈中之前的元素集添加到当前集合中. .children() 获得匹配元素集合中每个元素的所有子元素. .closest() 从元素本身开始,逐级向上级元素匹配,并返回最先匹配的祖先元素. .contents() 获得匹配元素集合中每个元素的子元素,包括文本和注释节点. .each() 对 jQ

随机推荐