讲师中心 微信公众号

工具推荐

视频效率加速
Laper
Laper

剧本策划到成片协作

立刻MV
立刻MV

低成本歌曲 MV、视频生成

Seko
Seko

AI短剧一键生成成片

AniShort
AniShort

AI短剧协同制作平台

Java JDBC 事务管理怎么实现分库分表

梦芳吖_6779

梦芳吖_6779

发布时间:2026-11-10 12:30:32

|

737人浏览过

|

来源于php中文网

原创

java jdbc 实现分库分表事务管理,核心在于放弃单一数据库的本地事务,转而采用基于全局唯一事务 id 的全局事务协调机制。具体做法是:在应用层维护一个全局事务上下文(threadlocal),为每个逻辑事务分配唯一的 transaction id;在执行跨库操作前,先向各数据源发起“开始事务”指令并绑定该 id;执行过程中,若某一步骤失败,则根据全局状态向所有已开启事务的数据源发送“回滚”指令,成功则发送“提交”指令。这种模式通过应用层代码显式控制事务边界和生命周期,确保分布式环境下的最终一致性。

Java JDBC 事务管理怎么实现分库分表

如何设计全局事务上下文与数据源路由

要实现上述机制,第一步是建立能够感知当前业务线程的事务上下文,并确保 SQL 能正确路由到对应的物理分片。我们使用 TransactionContext 类来存储全局事务 ID 和当前状态,利用 ThreadLocal 保证线程隔离。同时,需要一个 DataSourceRouter 根据业务键(如用户 ID)计算出目标数据源索引,从而获取正确的 Connection。这一步解决了“事务属于谁”以及“SQL 发给谁”的问题,为后续的多步操作奠定基础。

Java JDBC 事务管理怎么实现分库分表

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

// 全局事务上下文
public class TransactionContext {
    private static final ThreadLocal<String> TRANSACTION_ID = new ThreadLocal<>();
    private static final ThreadLocal<Integer> STATUS = new ThreadLocal<>(); // 0: active, 1: committed, 2: rolled back

    public static void begin() {
        TRANSACTION_ID.set(java.util.UUID.randomUUID().toString());
        STATUS.set(0);
    }

    public static String getTransactionId() {
        return TRANSACTION_ID.get();
    }

    public static int getStatus() {
        return STATUS.get();
    }

    public static void commit() {
        if (STATUS.get() == 0) STATUS.set(1);
    }

    public static void rollback() {
        if (STATUS.get() == 0) STATUS.set(2);
    }

    public static void clear() {
        TRANSACTION_ID.remove();
        STATUS.remove();
    }
}

// 模拟多数据源路由
public class DataSourceRouter {
    private static final Map<Integer, String> DB_URLS = new HashMap<>();
    static {
        DB_URLS.put(0, "jdbc:mysql://localhost:3306/db_0");
        DB_URLS.put(1, "jdbc:mysql://localhost:3306/db_1");
    }

    public static Connection getConnection(int shardIndex) throws SQLException {
        String url = DB_URLS.get(shardIndex % DB_URLS.size());
        return DriverManager.getConnection(url, "user", "password");
    }
}

如何在跨库操作中执行提交与回滚

在有了上下文和路由后,第二步是实现具体的事务执行逻辑。我们需要一个 DistributedTransactionManager 来封装 begin、commit 和 rollback 行为。当调用 commit 时,管理器会遍历所有参与本次事务的连接,依次执行 connection.commit();当发生异常调用 rollback 时,同样遍历所有连接执行 connection.rollback()。关键在于,必须确保即使某个库的回滚失败,也要尝试清理其他库的状态,或者记录日志以便人工介入,但在基础实现中,我们主要关注标准流程的执行顺序和异常捕获。

Java调试
Java调试

通过 JDWP 实现 Java 远程调试:连接远程 JVM、设置断点、单步执行代码、查看变量值、获取调用栈。适用于需要调试远程 Java 应用、排查运行时状态、追踪代码执行流程的场景。 术语注解 JDWP:Java Debug Wire Protocol,Java 调试有线协议(Java 远程调试底层通信协议) remote JVM:远程 Java 虚拟机 step through code:代码单步调试(步入 / 步过 / 步出调试) inspect variables:变量查看 / 变量检视 stac

下载

立即学习“Java免费学习笔记(深入)”;

Java JDBC 事务管理怎么实现分库分表

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class DistributedTransactionManager {
    private List<Connection> connections = new ArrayList<>();

    // 注册参与事务的连接
    public void registerConnection(Connection conn) {
        try {
            conn.setAutoCommit(false);
            connections.add(conn);
        } catch (SQLException e) {
            throw new RuntimeException("Failed to set autoCommit", e);
        }
    }

    // 提交全局事务
    public void commit() {
        for (Connection conn : connections) {
            try {
                conn.commit();
            } catch (SQLException e) {
                // 实际生产中需记录错误并可能触发补偿机制
                System.err.println("Commit failed on connection: " + e.getMessage());
            }
        }
        TransactionContext.commit();
        cleanup();
    }

    // 回滚全局事务
    public void rollback() {
        for (Connection conn : connections) {
            try {
                conn.rollback();
            } catch (SQLException e) {
                System.err.println("Rollback failed on connection: " + e.getMessage());
            }
        }
        TransactionContext.rollback();
        cleanup();
    }

    private void cleanup() {
        for (Connection conn : connections) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        connections.clear();
        TransactionContext.clear();
    }
}

// 使用示例
public class Main {
    public static void main(String[] args) {
        try {
            TransactionContext.begin();
            DistributedTransactionManager txManager = new DistributedTransactionManager();
            
            // 假设根据 user_id=1001 路由到 db_0,user_id=2002 路由到 db_1
            Connection conn1 = DataSourceRouter.getConnection(0); 
            Connection conn2 = DataSourceRouter.getConnection(1);
            
            txManager.registerConnection(conn1);
            txManager.registerConnection(conn2);
            
            // 执行 SQL...
            // conn1.prepareStatement("INSERT INTO users..." ).executeUpdate();
            // conn2.prepareStatement("INSERT INTO orders..." ).executeUpdate();
            
            txManager.commit();
            System.out.println("Transaction committed successfully.");
        } catch (Exception e) {
            TransactionContext.rollback(); // 简化处理,实际应调用 manager.rollback()
            System.out.println("Transaction rolled back due to error.");
        }
    }
}

如果第二个数据源连接超时,事务状态如何保持

当程序运行到第二节描述的 commit 或 rollback 阶段时,如果第二个数据源(db_1)发生网络超时或连接断开,conn.commit() 将抛出 SQLException。此时,第一个数据源(db_0)可能已经成功提交。由于我们的 DistributedTransactionManager 在循环中使用了 try-catch 块,第一个库的提交不会中断,但第二个库的提交会失败并被打印错误。这导致了一个不一致的状态:db_0 已提交,db_1 未提交。在这种基础实现下,事务无法自动恢复一致,必须由外部监控检测到该异常,并根据业务逻辑进行人工干预或异步补偿(例如,从 db_0 读取已提交数据,手动在 db_1 重放或标记失败)。因此,简单的 JDBC 分库分表事务仅能保证“全有或全无”的理想情况,在实际生产环境中,通常需要引入 TCC、Saga 或消息队列等更复杂的分布式事务方案来处理此类部分失败场景。

热门AI工具

更多
函子Zion

一款支持AI搭建、可视化编辑和多端发布的全栈无代码开发平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

12297

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

9382

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

8012

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1304

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1028

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

1556

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

3229

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

20471

2023.08.03

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

60

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn