最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中實(shí)現(xiàn)事務(wù)的幾種方法代碼示例

 更新時(shí)間:2026年01月08日 10:56:44   作者:阿賈克斯的黎明  
事務(wù)是應(yīng)用程序中一系列嚴(yán)密的操作,所有操作必須成功完成,否則在每個(gè)操作中所作的所有更改都會被撤消,這篇文章主要介紹了Java中實(shí)現(xiàn)事務(wù)的幾種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

事務(wù)是數(shù)據(jù)庫操作中的重要概念,它確保了一組操作要么全部成功,要么全部失敗,從而保證數(shù)據(jù)的一致性和完整性。在 Java 中,我們有多種方式來實(shí)現(xiàn)事務(wù)管理。本文將詳細(xì)介紹幾種常用的事務(wù)實(shí)現(xiàn)方法,并提供相應(yīng)的代碼示例。

1. JDBC 原生事務(wù)

JDBC 提供了最基礎(chǔ)的事務(wù)控制方式,通過 Connection 對象來管理事務(wù)。默認(rèn)情況下,JDBC 是自動(dòng)提交事務(wù)的,我們可以通過手動(dòng)設(shè)置來控制事務(wù)。

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

public class JDBCTransactionExample {
    // 數(shù)據(jù)庫連接信息
    private static final String URL = "jdbc:mysql://localhost:3306/testdb";
    private static final String USER = "root";
    private static final String PASSWORD = "password";
    
    public void transferMoney(int fromAccountId, int toAccountId, double amount) {
        Connection connection = null;
        PreparedStatement debitStmt = null;
        PreparedStatement creditStmt = null;
        
        try {
            // 獲取數(shù)據(jù)庫連接
            connection = DriverManager.getConnection(URL, USER, PASSWORD);
            
            // 關(guān)閉自動(dòng)提交,開始事務(wù)
            connection.setAutoCommit(false);
            
            // 從源賬戶扣款
            String debitSql = "UPDATE accounts SET balance = balance - ? WHERE id = ?";
            debitStmt = connection.prepareStatement(debitSql);
            debitStmt.setDouble(1, amount);
            debitStmt.setInt(2, fromAccountId);
            debitStmt.executeUpdate();
            
            // 向目標(biāo)賬戶存款
            String creditSql = "UPDATE accounts SET balance = balance + ? WHERE id = ?";
            creditStmt = connection.prepareStatement(creditSql);
            creditStmt.setDouble(1, amount);
            creditStmt.setInt(2, toAccountId);
            creditStmt.executeUpdate();
            
            // 所有操作成功,提交事務(wù)
            connection.commit();
            System.out.println("轉(zhuǎn)賬成功!");
            
        } catch (SQLException e) {
            System.err.println("轉(zhuǎn)賬失敗,回滾事務(wù): " + e.getMessage());
            try {
                // 發(fā)生異常,回滾事務(wù)
                if (connection != null) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                System.err.println("回滾事務(wù)失敗: " + ex.getMessage());
            }
        } finally {
            // 關(guān)閉資源
            try {
                if (debitStmt != null) debitStmt.close();
                if (creditStmt != null) creditStmt.close();
                if (connection != null) {
                    // 恢復(fù)自動(dòng)提交模式
                    connection.setAutoCommit(true);
                    connection.close();
                }
            } catch (SQLException e) {
                System.err.println("關(guān)閉資源失敗: " + e.getMessage());
            }
        }
    }
    
    public static void main(String[] args) {
        JDBCTransactionExample example = new JDBCTransactionExample();
        // 示例:從賬戶1向賬戶2轉(zhuǎn)賬100元
        example.transferMoney(1, 2, 100.0);
    }
}

JDBC 事務(wù)的核心 API:

  • setAutoCommit(false):關(guān)閉自動(dòng)提交,開始事務(wù)
  • commit():提交事務(wù)
  • rollback():回滾事務(wù)
  • setSavepoint():設(shè)置保存點(diǎn),可部分回滾

2. Spring 編程式事務(wù)

Spring 框架提供了更靈活的事務(wù)管理方式。編程式事務(wù)通過 TransactionTemplate 或直接使用 PlatformTransactionManager 來控制事務(wù)。

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

public class SpringProgrammaticTransactionExample {
    
    private final TransactionTemplate transactionTemplate;
    private final JdbcTemplate jdbcTemplate;
    
    // 通過構(gòu)造函數(shù)注入依賴
    public SpringProgrammaticTransactionExample(TransactionTemplate transactionTemplate, JdbcTemplate jdbcTemplate) {
        this.transactionTemplate = transactionTemplate;
        this.jdbcTemplate = jdbcTemplate;
    }
    
    public void transferMoney(int fromAccountId, int toAccountId, double amount) {
        // 使用TransactionTemplate執(zhí)行事務(wù)
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 從源賬戶扣款
                    jdbcTemplate.update(
                        "UPDATE accounts SET balance = balance - ? WHERE id = ?",
                        amount, fromAccountId
                    );
                    
                    // 向目標(biāo)賬戶存款
                    jdbcTemplate.update(
                        "UPDATE accounts SET balance = balance + ? WHERE id = ?",
                        amount, toAccountId
                    );
                    
                    System.out.println("轉(zhuǎn)賬成功!");
                } catch (Exception e) {
                    System.err.println("轉(zhuǎn)賬失敗,準(zhǔn)備回滾: " + e.getMessage());
                    // 標(biāo)記事務(wù)為回滾狀態(tài)
                    status.setRollbackOnly();
                }
            }
        });
    }
    
    public static void main(String[] args) {
        // 實(shí)際應(yīng)用中,這些會由Spring容器管理
        // ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // SpringProgrammaticTransactionExample example = context.getBean(SpringProgrammaticTransactionExample.class);
        
        // 示例調(diào)用
        // example.transferMoney(1, 2, 100.0);
    }
}

Spring 編程式事務(wù)的配置(XML 方式):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd">
    
    <!-- 數(shù)據(jù)源配置 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/testdb"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    </bean>
    
    <!-- 事務(wù)管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 配置TransactionTemplate -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
        <!-- 可以設(shè)置默認(rèn)的事務(wù)屬性 -->
        <property name="isolationLevelName" value="ISOLATION_READ_COMMITTED"/>
        <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
    </bean>
    
    <!-- JdbcTemplate配置 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!-- 業(yè)務(wù)類 -->
    <bean id="transactionExample" class="SpringProgrammaticTransactionExample">
        <constructor-arg ref="transactionTemplate"/>
        <constructor-arg ref="jdbcTemplate"/>
    </bean>
    
    <!-- 啟用事務(wù)注解支持 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

3. Spring 聲明式事務(wù)(注解方式)

聲明式事務(wù)是 Spring 中最常用的事務(wù)管理方式,它通過注解或 XML 配置來管理事務(wù),無需在代碼中顯式編寫事務(wù)控制邏輯。

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountService {
    
    private final JdbcTemplate jdbcTemplate;
    
    // 構(gòu)造函數(shù)注入JdbcTemplate
    public AccountService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    
    /**
     * 轉(zhuǎn)賬操作,使用@Transactional注解聲明事務(wù)
     * propagation = Propagation.REQUIRED:如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù);如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中
     * isolation = Isolation.READ_COMMITTED:讀取已提交的數(shù)據(jù)
     * rollbackFor = Exception.class:遇到任何異常都回滾
     */
    @Transactional(
        propagation = org.springframework.transaction.annotation.Propagation.REQUIRED,
        isolation = org.springframework.transaction.annotation.Isolation.READ_COMMITTED,
        rollbackFor = Exception.class
    )
    public void transferMoney(int fromAccountId, int toAccountId, double amount) {
        // 從源賬戶扣款
        jdbcTemplate.update(
            "UPDATE accounts SET balance = balance - ? WHERE id = ?",
            amount, fromAccountId
        );
        
        // 模擬可能出現(xiàn)的異常
        // if (true) throw new RuntimeException("模擬異常,觸發(fā)回滾");
        
        // 向目標(biāo)賬戶存款
        jdbcTemplate.update(
            "UPDATE accounts SET balance = balance + ? WHERE id = ?",
            amount, toAccountId
        );
        
        System.out.println("轉(zhuǎn)賬成功!");
    }
}

@Transactional 注解的主要屬性:

  • propagation:事務(wù)傳播行為,如 REQUIRED、REQUIRES_NEW 等
  • isolation:事務(wù)隔離級別,如 READ_COMMITTED、REPEATABLE_READ 等
  • rollbackFor:指定哪些異常觸發(fā)回滾
  • noRollbackFor:指定哪些異常不觸發(fā)回滾
  • timeout:事務(wù)超時(shí)時(shí)間
  • readOnly:是否為只讀事務(wù)

4. EJB 事務(wù)

EJB(Enterprise JavaBeans)也提供了事務(wù)管理功能,主要通過注解來聲明事務(wù)屬性。

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

@Stateless
public class AccountEJB {
    
    @PersistenceContext(unitName = "accountPU")
    private EntityManager em;
    
    /**
     * 轉(zhuǎn)賬操作,使用EJB的@Transactional注解
     * Transactional.TxType.REQUIRED:如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù);如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中
     */
    @Transactional(Transactional.TxType.REQUIRED)
    public void transferMoney(int fromAccountId, int toAccountId, double amount) {
        Account fromAccount = em.find(Account.class, fromAccountId);
        Account toAccount = em.find(Account.class, toAccountId);
        
        if (fromAccount == null || toAccount == null) {
            throw new IllegalArgumentException("賬戶不存在");
        }
        
        if (fromAccount.getBalance() < amount) {
            throw new IllegalStateException("余額不足");
        }
        
        // 執(zhí)行轉(zhuǎn)賬操作
        fromAccount.setBalance(fromAccount.getBalance() - amount);
        toAccount.setBalance(toAccount.getBalance() + amount);
        
        // 合并實(shí)體狀態(tài)
        em.merge(fromAccount);
        em.merge(toAccount);
        
        System.out.println("轉(zhuǎn)賬成功!");
    }
}

// 賬戶實(shí)體類
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
class Account {
    @Id
    private int id;
    private String name;
    private double balance;
    
    // getter和setter方法
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public double getBalance() { return balance; }
    public void setBalance(double balance) { this.balance = balance; }
}

EJB 事務(wù)的傳播級別主要有:

  • REQUIRED:默認(rèn)值,如果當(dāng)前有事務(wù)則加入,否則創(chuàng)建新事務(wù)
  • REQUIRES_NEW:總是創(chuàng)建新事務(wù)
  • SUPPORTS:如果當(dāng)前有事務(wù)則加入,否則非事務(wù)執(zhí)行
  • MANDATORY:必須在已有事務(wù)中執(zhí)行,否則拋出異常
  • NOT_SUPPORTED:非事務(wù)執(zhí)行,如果當(dāng)前有事務(wù)則暫停
  • NEVER:非事務(wù)執(zhí)行,如果當(dāng)前有事務(wù)則拋出異常

5. 分布式事務(wù)

在分布式系統(tǒng)中,事務(wù)可能涉及多個(gè)數(shù)據(jù)源或服務(wù),這時(shí)需要使用分布式事務(wù)解決方案。Java 中常用的分布式事務(wù)實(shí)現(xiàn)包括 JTA(Java Transaction API)和一些開源框架如 Seata、Hmily 等。

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.transaction.UserTransaction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

@Stateless
public class JTADistributedTransaction {
    
    // 注入JTA事務(wù)管理
    @Resource
    private UserTransaction utx;
    
    // 數(shù)據(jù)庫1連接信息
    private static final String DB1_URL = "jdbc:mysql://localhost:3306/db1";
    private static final String DB1_USER = "root";
    private static final String DB1_PASSWORD = "password";
    
    // 數(shù)據(jù)庫2連接信息
    private static final String DB2_URL = "jdbc:mysql://localhost:3306/db2";
    private static final String DB2_USER = "root";
    private static final String DB2_PASSWORD = "password";
    
    public void distributeTransaction() throws Exception {
        Connection conn1 = null;
        Connection conn2 = null;
        PreparedStatement stmt1 = null;
        PreparedStatement stmt2 = null;
        
        try {
            // 開始JTA事務(wù)
            utx.begin();
            
            // 連接第一個(gè)數(shù)據(jù)庫并執(zhí)行操作
            conn1 = DriverManager.getConnection(DB1_URL, DB1_USER, DB1_PASSWORD);
            // 注意:不要設(shè)置autoCommit,由JTA管理
            String sql1 = "INSERT INTO logs (message) VALUES (?)";
            stmt1 = conn1.prepareStatement(sql1);
            stmt1.setString(1, "操作1執(zhí)行成功");
            stmt1.executeUpdate();
            
            // 連接第二個(gè)數(shù)據(jù)庫并執(zhí)行操作
            conn2 = DriverManager.getConnection(DB2_URL, DB2_USER, DB2_PASSWORD);
            String sql2 = "INSERT INTO records (content) VALUES (?)";
            stmt2 = conn2.prepareStatement(sql2);
            stmt2.setString(1, "操作2執(zhí)行成功");
            stmt2.executeUpdate();
            
            // 提交事務(wù)
            utx.commit();
            System.out.println("分布式事務(wù)執(zhí)行成功!");
            
        } catch (Exception e) {
            System.err.println("分布式事務(wù)執(zhí)行失敗,準(zhǔn)備回滾: " + e.getMessage());
            // 回滾事務(wù)
            utx.rollback();
            throw e;
        } finally {
            // 關(guān)閉資源
            if (stmt1 != null) stmt1.close();
            if (stmt2 != null) stmt2.close();
            if (conn1 != null) conn1.close();
            if (conn2 != null) conn2.close();
        }
    }
}

總結(jié)

Java 提供了多種事務(wù)實(shí)現(xiàn)方式,每種方式都有其適用場景:

  1. JDBC 原生事務(wù):適合簡單應(yīng)用,直接操作數(shù)據(jù)庫連接,控制粒度細(xì)。
  2. Spring 編程式事務(wù):適合需要在代碼中精確控制事務(wù)邊界的場景。
  3. Spring 聲明式事務(wù):最常用的方式,通過注解或配置實(shí)現(xiàn),代碼侵入性低,適合大多數(shù)企業(yè)應(yīng)用。
  4. EJB 事務(wù):適合使用 EJB 技術(shù)的分布式企業(yè)應(yīng)用。
  5. 分布式事務(wù):適合跨多個(gè)數(shù)據(jù)源或服務(wù)的事務(wù)場景,實(shí)現(xiàn)復(fù)雜但必要時(shí)不可替代。

選擇合適的事務(wù)管理方式需要根據(jù)應(yīng)用的架構(gòu)、復(fù)雜度和性能要求來決定。在實(shí)際開發(fā)中,Spring 聲明式事務(wù)因其簡潔性和靈活性而被廣泛采用。

到此這篇關(guān)于Java中實(shí)現(xiàn)事務(wù)的幾種方法的文章就介紹到這了,更多相關(guān)Java實(shí)現(xiàn)事務(wù)方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java成員變量的隱藏(實(shí)例講解)

    Java成員變量的隱藏(實(shí)例講解)

    下面小編就為大家?guī)硪黄狫ava成員變量的隱藏(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • 自己動(dòng)手編寫一個(gè)Mybatis插件之Mybatis脫敏插件

    自己動(dòng)手編寫一個(gè)Mybatis插件之Mybatis脫敏插件

    這篇文章主要介紹了自己動(dòng)手編寫一個(gè)Mybatis插件之Mybatis脫敏插件,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot集成swagger3.0指南分享

    SpringBoot集成swagger3.0指南分享

    本文介紹了如何在Spring Boot項(xiàng)目中集成Swagger 3.0,包括添加依賴、配置Swagger、在Controller上添加注解以及配置訪問權(quán)限
    2024-11-11
  • Spring Security OAuth2認(rèn)證授權(quán)示例詳解

    Spring Security OAuth2認(rèn)證授權(quán)示例詳解

    這篇文章主要介紹了Spring Security OAuth2認(rèn)證授權(quán)示例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • SpringBoot整合spring-retry實(shí)現(xiàn)接口請求重試機(jī)制及注意事項(xiàng)

    SpringBoot整合spring-retry實(shí)現(xiàn)接口請求重試機(jī)制及注意事項(xiàng)

    今天通過本文給大家介紹我們應(yīng)該如何使用SpringBoot來整合spring-retry組件實(shí)現(xiàn)重試機(jī)制及注意事項(xiàng),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-08-08
  • mybatis中${}和#{}的區(qū)別以及底層原理分析

    mybatis中${}和#{}的區(qū)別以及底層原理分析

    這篇文章主要介紹了mybatis中${}和#{}的區(qū)別以及底層原理,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 詳解Java線程的創(chuàng)建及休眠

    詳解Java線程的創(chuàng)建及休眠

    今天帶大家學(xué)習(xí)的是Java的相關(guān)知識,文章圍繞著Java線程的創(chuàng)建及休眠展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • SpringBoot和Tomcat的關(guān)系解讀

    SpringBoot和Tomcat的關(guān)系解讀

    這篇文章主要介紹了SpringBoot和Tomcat的關(guān)系,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03
  • java?String到底有多長?String超出長度該如何解決

    java?String到底有多長?String超出長度該如何解決

    在Java中,由于字符串常量池的存在,String常量長度限制取決于String常量在常量池中的存儲大小,下面這篇文章主要給大家介紹了關(guān)于java?String到底有多長?String超出長度該如何解決的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 一文詳解Java如何防止DDoS攻擊

    一文詳解Java如何防止DDoS攻擊

    DDoS(分布式拒絕服務(wù))攻擊是一種常見的網(wǎng)絡(luò)攻擊手段在?Java?應(yīng)用開發(fā)中,了解?DDoS?攻擊的原理和防御策略至關(guān)重要,下面小編來和大家詳細(xì)講講
    2025-05-05

最新評論

阿鲁科尔沁旗| 福建省| 织金县| 新干县| 横峰县| 深圳市| 马鞍山市| 罗平县| 呼伦贝尔市| 安乡县| 汪清县| 绥江县| 清远市| 六盘水市| 个旧市| 衡山县| 浮山县| 大同市| 禹城市| 防城港市| 高邮市| 金乡县| 余江县| 边坝县| 灌云县| 大方县| 自治县| 宁国市| 瑞昌市| 新平| 徐汇区| 安化县| 西平县| 浦县| 镇巴县| 新安县| 宜良县| 乐都县| 扬中市| 乐至县| 灵寿县|