Java事务之四——成功的案例

Java 事务详解及简单应用实例 主要介绍了Java 事务详解及简单应用实例的相关资料,java事务能够保证数据的完整性和一致性,当然这是书本上的知识,具体如何应用这里举例说明,需要的朋友可以参考下 立即下载

Java事务之四——成功的案例

本文转载自:http://www.cnblogs.com/davenkin/archive/2013/02/23/java-tranaction-4.html,侵删。

  在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。

 

  这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码:

git clone https://github.com/davenkin/java_transaction_workshop.git

 

  ConnectionHolder的工作机制是:我们将Connection对象放在一个全局公用的地方,然后在不同的操作中都从这个地方取得Connection,从而完成Connection共享的目的,这也是一种ServiceLocator模式,有点像JNDI。定义一个ConnectionHolder类如下:

复制代码
package davenkin.step3_connection_holder;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class ConnectionHolder
{
    private Map<DataSource, Connection> connectionMap = new HashMap<DataSource, Connection>();

    public Connection getConnection(DataSource dataSource) throws SQLException
    {
        Connection connection = connectionMap.get(dataSource);
        if (connection == null || connection.isClosed())
        {
            connection = dataSource.getConnection();
            connectionMap.put(dataSource, connection);
        }

        return connection;
    }

    public void removeConnection(DataSource dataSource)
    {
        connectionMap.remove(dataSource);
    }
}
复制代码

 

  从ConnectionHolder类中可以看出,我们维护了一个键为DataSource、值为Connection的Map,这主要用于使ConnectionHolder可以服务多个DataSource。在调用getConnection方法时传入了一个DataSource对象,如果Map里面已经存在该DataSource对应的Connection,则直接返回该Connection,否则,调用DataSource的getConnection方法获得一个新的Connection,再将其加入到Map中,最后返回该Connection。这样在同一个事务过程中,我们先后从ConnectionHolder中取得的Connection是相同的,除非在中途我们调用了ConnectionHolder的removeConnection方法将当前Connection移除掉或者调用了Connection.close()将Connection关闭,然后在后续的操作中再次调用ConnectionHolder的getConnection方法,此时返回的则是一个新的Connection对象,从而导致事务处理失败,你应该不会做出这种中途移除或关闭Connection的事情。

 

  然而,虽然我们不会自己手动地在中途移除或者关闭Conncetion对象(当然,在事务处理末尾我们应该关闭Conncetion),我们却无法阻止其他线程这么做。比如,ConnectionHolder类是可以在多个线程中同时使用的,并且这些线程使用了同一个DataSource,其中一个线程使用完Connection后便将其关闭,而此时另外一个线程正试图使用这个Connection,问题就出来了。因此,上面的ConnectionHolder不是线程安全的。

 

  为了获得线程安全的ConnectionHolder类,我们可以引入Java提供的ThreadLocal类,该类保证一个类的实例变量在各个线程中都有一份单独的拷贝,从而不会影响其他线程中的实例变量。定义一个SingleThreadConnectionHolder类如下:

复制代码
package davenkin.step3_connection_holder;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class SingleThreadConnectionHolder
{
    private static ThreadLocal<ConnectionHolder> localConnectionHolder = new ThreadLocal<ConnectionHolder>();

    public static Connection getConnection(DataSource dataSource) throws SQLException
    {
        return getConnectionHolder().getConnection(dataSource);
    }

    public static void removeConnection(DataSource dataSource)
    {
        getConnectionHolder().removeConnection(dataSource);
    }

    private static ConnectionHolder getConnectionHolder()
    {
        ConnectionHolder connectionHolder = localConnectionHolder.get();
        if (connectionHolder == null)
        {
            connectionHolder = new ConnectionHolder();
            localConnectionHolder.set(connectionHolder);
        }
        return connectionHolder;
    }

}
复制代码

 

  有了一个线程安全的SingleThreadConnectionHolder类,我们便可以在service层和各个DAO中使用该类来获取Connection对象:

        Connection connection = SingleThreadConnectionHolder.getConnection(dataSource);

 

  当然,此时我们需要传入一个DataSource,这个DataSource可以作为DAO类的实例变量存在,所以我们不用像上一篇文章那样将Connection对象直接传给DAO的方法。这里你可能要问,既然可以将DataSource作为实例变量,那么在上一篇文章中,为什么不可以将Connection也作为实例变量呢,这样不就不会造成丑陋的API了吗?原因在于:将Connection对象作为实例变量同样会带来线程安全问题,当多个线程同时使用同一个DAO类时,一个线程关闭了Connection而另一个正在使用,这样的问题和上面讲到的ConnectionHolder的线程安全问题一样。

  关于Bank DAO和Insurance DAO类的源代码这里就不列出了,他们和上篇文章只是获得Connection对象的方法不一样而已,你可以参考github源代码。

  接下来,我们再来看看TransactionManager类,在上几篇文章中,我们都是在service类中直接写和事务处理相关的代码,而更好的方式是声明一个TransactionManger类将事务处理相关工作集中管理:

复制代码
package davenkin.step3_connection_holder;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class TransactionManager
{
    private DataSource dataSource;

    public TransactionManager(DataSource dataSource)
    {
        this.dataSource = dataSource;
    }

    public final void start() throws SQLException
    {
        Connection connection = getConnection();
        connection.setAutoCommit(false);
    }

    public final void commit() throws SQLException
    {
        Connection connection = getConnection();
        connection.commit();
    }

    public final void rollback()
    {
        Connection connection = null;
        try
        {
            connection = getConnection();
            connection.rollback();

        } catch (SQLException e)
        {
            throw new RuntimeException("Couldn't rollback on connection[" + connection + "].", e);
        }
    }

    public final void close()
    {
        Connection connection = null;
        try
        {
            connection = getConnection();
            connection.setAutoCommit(true);
            connection.setReadOnly(false);
            connection.close();
            SingleThreadConnectionHolder.removeConnection(dataSource);
        } catch (SQLException e)
        {
            throw new RuntimeException("Couldn't close connection[" + connection + "].", e);
        }
    }

    private Connection getConnection() throws SQLException
    {
        return SingleThreadConnectionHolder.getConnection(dataSource);
    }
}
复制代码

 

  可以看出,TransactionManager对象也维护了一个DataSource实例变量,并且也是通过SingleThreadConnectionHolder来获取Connection对象的。然后我们在service类中使用该TransactionManager:

复制代码
package davenkin.step3_connection_holder;

import davenkin.BankService;
import javax.sql.DataSource;

public class ConnectionHolderBankService implements BankService
{
    private TransactionManager transactionManager;
    private ConnectionHolderBankDao connectionHolderBankDao;
    private ConnectionHolderInsuranceDao connectionHolderInsuranceDao;

    public ConnectionHolderBankService(DataSource dataSource)
    {
        transactionManager = new TransactionManager(dataSource);
        connectionHolderBankDao = new ConnectionHolderBankDao(dataSource);
        connectionHolderInsuranceDao = new ConnectionHolderInsuranceDao(dataSource);

    }

    public void transfer(int fromId, int toId, int amount)
    {
        try
        {
            transactionManager.start();
            connectionHolderBankDao.withdraw(fromId, amount);
            connectionHolderInsuranceDao.deposit(toId, amount);
            transactionManager.commit();
        } catch (Exception e)
        {
            transactionManager.rollback();
        } finally
        {
            transactionManager.close();
        }
    }
}
复制代码

 

  在ConnectionHolderBankService中,我们使用TransactionManager来管理事务,由于TransactionManger和两个DAO类都是使用SingleThreadConnectionHolder来获取Connection,故他们在整个事务处理过程中使用了相同的Connection对象,事务处理成功。我们也可以看到,在两个DAO的withdraw和deposit方法没有接受和业务无关的对象,消除了API污染;另外,使用TransactionManager来管理事务,使Service层代码也变简洁了。

 

  在下一篇文章中,我们将讲到使用Template模式来完成事务处理。

Silvaco Atlas从头开始(四)——定义材料参数和模型 这部分是关于定义材料参数和模型。 阅读详情

相关推荐

【软件介绍】RVC本地部署使用方法

【摘要】RVC是一款功能强大的开源语音转换工具,具有实时处理、多音效选择、高质量音频处理等特点。文章详细介绍了RVC的安装与使用方法:1)配置Python环境;2)根据电脑系统选择对应安装包解压;3)启动程序进入浏览器操作界面。重点讲解了声音克隆的关键步骤:建议使用短音频素材,选择合适训练方法(推荐pm或rmvpe),设置100次训练轮数,生成的模型文件存入weights文件夹。最后通过上传音频即可实现声音克隆。操作过程需注意保持程序运行状态,并提供了相关资源下载地址。

心动的那一刻,记忆便盛开了花 2976

JAVA-事务

事务(transaction)是访问并可能更新数据库中各数据项的一个程序执行单元。由事务开始到事务结束之间的全部操作组成。

ljp1245620870的博客 8164

IC618新手避坑指南:从零在Linux上配置Cadence Virtuoso环境(含cds.lib文件详解)

本文详细介绍了在Linux系统上配置Cadence Virtuoso IC618环境的完整指南,特别针对新手常见问题提供解决方案。重点解析了cds.lib文件的关键配置,包括库路径定义和工艺库管理,并分享了高效工作流设置和典型问题排查技巧,帮助工程师快速搭建稳定的EDA设计环境。

weixin_26805597的博客 552

Java事务详解

AOP术语切面(Aspect)就是你要实现的交叉的非核心业务功能连接点(Joinpoint)应用程序执行过程中插入切面的地点,可以是方法调用,异常抛出......通知(Advice)通知切面的实际实现代码切入点(Pointcut)定义通知应用在哪些连接点目标对象(Target)被通知的对象代理(Proxy)将通知应用到目标对象后创建的对象织入(Weaving)将切面应用到目标对象从而创建一个新的代理对象的过程。事务的持久性,表示事务完成之后,对系统的影响是永久性的。...

火车头的博客 1万+

Android 16(API 36)状态栏颜色适配全攻略:从沉浸式到自定义背景

本文全面解析Android 16(API 36)强制沉浸式状态栏带来的适配挑战,提供了从FrameLayout包裹法到动态修改Window背景色的核心解决方案。针对传统状态栏颜色设置失效问题,详细阐述了如何利用WindowInsets API实现自定义背景,并涵盖全屏模式、Fragment切换及第三方ROM兼容性等实战场景,为开发者提供一站式适配指南。

weixin_29227425的博客 594

CPU设计实战:Loongarch版 lab6--20条指令单周期CPU

这个debug卡我时间最长的就是通用寄存器的写使能信号,当时一直没找到,甚至把golden—trace生成了一遍又一遍,对照test,检查了各种,卡了很长时间,我都以为是我之前哪一步搞错了,或者环境什么的,但是一步步做下来并没有,并且“机器永远是对的”让我终于查到了错。debug到一半才想起来写个博客,就不写过程了,下个lab再写过程。下面是两个模块的代码,运行已通过仿真验证。其他的bug就还好,如果认真跟着。就能马上找出来,,上面的每一句话都很重要。走,按逻辑检查并且查。

m0_65369544的博客 6301

Java中的事务

在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。简单来说就是把数据库的各种操作封装到一个事务中,这些操作数据库的动作要么都执行要么都不执行。把多个要做的操作组合到一个整体,利用事务的特性来保证操作的安全性。如果一个事务做到一半出现任何错误,就会进行回滚操作,来恢复成最初的操作。

m0_65224643的博客 4557

华为ENSP完整安装教程

华为ENSP完整安装教程

Hnm456756的博客 7330

Java 中的事务详解以及使用

Java 中的事务详解以及使用一、事务的盖帘二、手动提交事务三、Spring 中的事务注解四、代码实现 一、事务的盖帘 二、手动提交事务 三、Spring 中的事务注解 四、代码实现

qq_34377273的博客 5849

从编解码芯片看Tesla T4的隐藏实力:双NVDEC如何实现70路1080P解码?

本文深入剖析了英伟达Tesla T4显卡的隐藏实力,重点解读其独特的双NVDEC硬件解码器设计如何突破性能瓶颈。通过分析Turing架构、对比HEVC/H.264解码差异,并结合驱动与SDK优化,揭示了实现高达70路1080P视频流并发解码的原理与实战配置,为云游戏、直播转码等高并发场景提供高效解决方案。

weixin_29209801的博客 485

【FPGA教程案例59】深度学习案例6——基于FPGA的CNN卷积神经网络之整体实现

在课程,我们对的基本原理有了初步认识。在上一个课程,我们完成了CNN的Relu激活层、pool池化层、卷积层以及图像输入层的实现,如下图所示:在本课程中,我们将上述四个模块结合起来,构建一个简单的CNN卷积神经网络。...

FPGA/MATLAB学习教程/源码/项目合作开发 2635

java中使用事务案例_Java事务之四——成功的案例

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码:git clone https://github.com/da...

weixin_42517854的博客 495

【局部规划模块曲线算法】曲线平滑介绍

本文先对轨迹平滑问题做个简单的介绍,具体内容后续再更,其他模块可以参考去我其他文章提示:以下是本篇文章正文内容(1)适合给移动机器人运动的路径【满足运动学,高阶平滑】(2)高阶的运动学不能够突变的【至少三阶的加速度不能突变,最好四阶的jerk和五阶的snap也不能突变】(3)在转弯的地方不会停下来(4)加减速均衡,节省能量(5)节省时间的。

qq_35635374的博客 5715

java中使用事务案例_Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)...

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。ConnectionHolder的工作机制是:我们将Connection对象放在一个全局公用的地方,然后在不同的操作中都从这个地方取得Con...

weixin_28907247的博客 321

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: Git clone https://

SunshineLPL的博客 541

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: git clone https://

huilangeliuxin的专栏 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

java事务全解析(四)--成功的案例(自己实现一个线程安全的TransactionManager)

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: Git clone https://

java小强的博客 533

Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager) Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionM...

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。 这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: git clonehttps://github...

weixin_33850890的博客 285

java事务学习笔记(四)--成功的案例(自己实现一个线程安全的TransactionManager)

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。   这是一个关于Java事务处理的系列文章,请通过以下方式下载github源代码: git clone https://

JordanInShenzhen的博客 997

Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)...

在本系列的上一篇文章中我们讲到,要实现在同一个事务中使用相同的Connection对象,我们可以通过传递Connection对象的方式达到共享的目的,但是这种做法是丑陋的。在本篇文章中,我们将引入另外一种机制(ConnectionHolder)来完成事务管理。 ConnectionHolder的工作机制是:我们将Connection对象放在一个全局公用的地方,然后在不同的操作中都从这个地方...

weixin_30414245的博客 73

Java学习日志(三十五): 事务,三层思想实现转账案例

Java学习日志(三十五) 事务: 事务概述, 使用原生JDBC完成转账案例, 使用DbUtils和C3P0完成转账案例, 三层思想: 三层思想概述, 三层思想转账案例_dao层, 三层思想转账案例_service层, 三层思想转账案例_web层。

Sakuraaaaaaa的博客 401
上一篇: Java事务之三——丑陋的案例
下一篇: Java事务之五——Template模式
TaiSung
博客等级 码龄15年 49粉丝 132原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值