当前位置: 代码网 > it编程>编程语言>Java > Java中实现事务的几种方法代码示例

Java中实现事务的几种方法代码示例

2026年01月08日 Java 我要评论
前言事务是数据库操作中的重要概念,它确保了一组操作要么全部成功,要么全部失败,从而保证数据的一致性和完整性。在 java 中,我们有多种方式来实现事务管理。本文将详细介绍几种常用的事务实现方法,并提供

前言

事务是数据库操作中的重要概念,它确保了一组操作要么全部成功,要么全部失败,从而保证数据的一致性和完整性。在 java 中,我们有多种方式来实现事务管理。本文将详细介绍几种常用的事务实现方法,并提供相应的代码示例。

1. jdbc 原生事务

jdbc 提供了最基础的事务控制方式,通过 connection 对象来管理事务。默认情况下,jdbc 是自动提交事务的,我们可以通过手动设置来控制事务。

import java.sql.connection;
import java.sql.drivermanager;
import java.sql.preparedstatement;
import java.sql.sqlexception;

public class jdbctransactionexample {
    // 数据库连接信息
    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 {
            // 获取数据库连接
            connection = drivermanager.getconnection(url, user, password);
            
            // 关闭自动提交,开始事务
            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();
            
            // 向目标账户存款
            string creditsql = "update accounts set balance = balance + ? where id = ?";
            creditstmt = connection.preparestatement(creditsql);
            creditstmt.setdouble(1, amount);
            creditstmt.setint(2, toaccountid);
            creditstmt.executeupdate();
            
            // 所有操作成功,提交事务
            connection.commit();
            system.out.println("转账成功!");
            
        } catch (sqlexception e) {
            system.err.println("转账失败,回滚事务: " + e.getmessage());
            try {
                // 发生异常,回滚事务
                if (connection != null) {
                    connection.rollback();
                }
            } catch (sqlexception ex) {
                system.err.println("回滚事务失败: " + ex.getmessage());
            }
        } finally {
            // 关闭资源
            try {
                if (debitstmt != null) debitstmt.close();
                if (creditstmt != null) creditstmt.close();
                if (connection != null) {
                    // 恢复自动提交模式
                    connection.setautocommit(true);
                    connection.close();
                }
            } catch (sqlexception e) {
                system.err.println("关闭资源失败: " + e.getmessage());
            }
        }
    }
    
    public static void main(string[] args) {
        jdbctransactionexample example = new jdbctransactionexample();
        // 示例:从账户1向账户2转账100元
        example.transfermoney(1, 2, 100.0);
    }
}

jdbc 事务的核心 api:

  • setautocommit(false):关闭自动提交,开始事务
  • commit():提交事务
  • rollback():回滚事务
  • setsavepoint():设置保存点,可部分回滚

2. spring 编程式事务

spring 框架提供了更灵活的事务管理方式。编程式事务通过 transactiontemplate 或直接使用 platformtransactionmanager 来控制事务。

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;
    
    // 通过构造函数注入依赖
    public springprogrammatictransactionexample(transactiontemplate transactiontemplate, jdbctemplate jdbctemplate) {
        this.transactiontemplate = transactiontemplate;
        this.jdbctemplate = jdbctemplate;
    }
    
    public void transfermoney(int fromaccountid, int toaccountid, double amount) {
        // 使用transactiontemplate执行事务
        transactiontemplate.execute(new transactioncallbackwithoutresult() {
            @override
            protected void dointransactionwithoutresult(transactionstatus status) {
                try {
                    // 从源账户扣款
                    jdbctemplate.update(
                        "update accounts set balance = balance - ? where id = ?",
                        amount, fromaccountid
                    );
                    
                    // 向目标账户存款
                    jdbctemplate.update(
                        "update accounts set balance = balance + ? where id = ?",
                        amount, toaccountid
                    );
                    
                    system.out.println("转账成功!");
                } catch (exception e) {
                    system.err.println("转账失败,准备回滚: " + e.getmessage());
                    // 标记事务为回滚状态
                    status.setrollbackonly();
                }
            }
        });
    }
    
    public static void main(string[] args) {
        // 实际应用中,这些会由spring容器管理
        // applicationcontext context = new classpathxmlapplicationcontext("applicationcontext.xml");
        // springprogrammatictransactionexample example = context.getbean(springprogrammatictransactionexample.class);
        
        // 示例调用
        // example.transfermoney(1, 2, 100.0);
    }
}

spring 编程式事务的配置(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">
    
    <!-- 数据源配置 -->
    <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>
    
    <!-- 事务管理器 -->
    <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"/>
        <!-- 可以设置默认的事务属性 -->
        <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>
    
    <!-- 业务类 -->
    <bean id="transactionexample" class="springprogrammatictransactionexample">
        <constructor-arg ref="transactiontemplate"/>
        <constructor-arg ref="jdbctemplate"/>
    </bean>
    
    <!-- 启用事务注解支持 -->
    <tx:annotation-driven transaction-manager="transactionmanager"/>
</beans>

3. spring 声明式事务(注解方式)

声明式事务是 spring 中最常用的事务管理方式,它通过注解或 xml 配置来管理事务,无需在代码中显式编写事务控制逻辑。

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;
    
    // 构造函数注入jdbctemplate
    public accountservice(jdbctemplate jdbctemplate) {
        this.jdbctemplate = jdbctemplate;
    }
    
    /**
     * 转账操作,使用@transactional注解声明事务
     * propagation = propagation.required:如果当前没有事务,就新建一个事务;如果已经存在一个事务中,加入到这个事务中
     * isolation = isolation.read_committed:读取已提交的数据
     * 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
        );
        
        // 模拟可能出现的异常
        // if (true) throw new runtimeexception("模拟异常,触发回滚");
        
        // 向目标账户存款
        jdbctemplate.update(
            "update accounts set balance = balance + ? where id = ?",
            amount, toaccountid
        );
        
        system.out.println("转账成功!");
    }
}

@transactional 注解的主要属性:

  • propagation:事务传播行为,如 requiredrequires_new 等
  • isolation:事务隔离级别,如 read_committedrepeatable_read 等
  • rollbackfor:指定哪些异常触发回滚
  • norollbackfor:指定哪些异常不触发回滚
  • timeout:事务超时时间
  • readonly:是否为只读事务

4. ejb 事务

ejb(enterprise javabeans)也提供了事务管理功能,主要通过注解来声明事务属性。

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;
    
    /**
     * 转账操作,使用ejb的@transactional注解
     * transactional.txtype.required:如果当前没有事务,就新建一个事务;如果已经存在一个事务中,加入到这个事务中
     */
    @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("余额不足");
        }
        
        // 执行转账操作
        fromaccount.setbalance(fromaccount.getbalance() - amount);
        toaccount.setbalance(toaccount.getbalance() + amount);
        
        // 合并实体状态
        em.merge(fromaccount);
        em.merge(toaccount);
        
        system.out.println("转账成功!");
    }
}

// 账户实体类
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 事务的传播级别主要有:

  • required:默认值,如果当前有事务则加入,否则创建新事务
  • requires_new:总是创建新事务
  • supports:如果当前有事务则加入,否则非事务执行
  • mandatory:必须在已有事务中执行,否则抛出异常
  • not_supported:非事务执行,如果当前有事务则暂停
  • never:非事务执行,如果当前有事务则抛出异常

5. 分布式事务

在分布式系统中,事务可能涉及多个数据源或服务,这时需要使用分布式事务解决方案。java 中常用的分布式事务实现包括 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事务管理
    @resource
    private usertransaction utx;
    
    // 数据库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";
    
    // 数据库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事务
            utx.begin();
            
            // 连接第一个数据库并执行操作
            conn1 = drivermanager.getconnection(db1_url, db1_user, db1_password);
            // 注意:不要设置autocommit,由jta管理
            string sql1 = "insert into logs (message) values (?)";
            stmt1 = conn1.preparestatement(sql1);
            stmt1.setstring(1, "操作1执行成功");
            stmt1.executeupdate();
            
            // 连接第二个数据库并执行操作
            conn2 = drivermanager.getconnection(db2_url, db2_user, db2_password);
            string sql2 = "insert into records (content) values (?)";
            stmt2 = conn2.preparestatement(sql2);
            stmt2.setstring(1, "操作2执行成功");
            stmt2.executeupdate();
            
            // 提交事务
            utx.commit();
            system.out.println("分布式事务执行成功!");
            
        } catch (exception e) {
            system.err.println("分布式事务执行失败,准备回滚: " + e.getmessage());
            // 回滚事务
            utx.rollback();
            throw e;
        } finally {
            // 关闭资源
            if (stmt1 != null) stmt1.close();
            if (stmt2 != null) stmt2.close();
            if (conn1 != null) conn1.close();
            if (conn2 != null) conn2.close();
        }
    }
}

总结

java 提供了多种事务实现方式,每种方式都有其适用场景:

  1. jdbc 原生事务:适合简单应用,直接操作数据库连接,控制粒度细。
  2. spring 编程式事务:适合需要在代码中精确控制事务边界的场景。
  3. spring 声明式事务:最常用的方式,通过注解或配置实现,代码侵入性低,适合大多数企业应用。
  4. ejb 事务:适合使用 ejb 技术的分布式企业应用。
  5. 分布式事务:适合跨多个数据源或服务的事务场景,实现复杂但必要时不可替代。

选择合适的事务管理方式需要根据应用的架构、复杂度和性能要求来决定。在实际开发中,spring 声明式事务因其简洁性和灵活性而被广泛采用。

到此这篇关于java中实现事务的几种方法的文章就介绍到这了,更多相关java实现事务方法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com