【问题标题】:jdbc transaction management : when releasing resources and distributed transactionsjdbc事务管理:释放资源和分布式事务时
【发布时间】:2011-04-21 05:43:26
【问题描述】:

你好 我是一名初学者 Java 开发人员,这是我发布的列表中的一个问题,因为我已经开始移植一个非常古老的 Web 服务。我正在尝试改进对 db 的访问,并且我发现很多我认为可能很危险的代码,但是我对 java 的经验不是很丰富,我不能确定。 实际上,我有一个管理数据库连接并保存对连接和语句对象的静态引用的类:它公开了一个初始化 sql 连接类成员变量的“openDb”方法。

问题1:类成员变量是静态的,如果多次调用openDb并且类的第一个(例如)实例仍在执行查询会发生什么?

上面的类公开了一个方法名“closeDb”,它释放所有资源(连接和语句都是静态成员!)和一个“closeStatement”方法,它只释放语句成员,并在外部使用。

问题2:必须在事务提交/回滚后关闭语句和结果集,还是可以立即关闭?

仍然是同一个类处理暴露一些方法的提交/回滚(将 autocommit 设置为 false、提交或回滚)。这个类的一个实例被传递给其他类实例(例如通常的员工部门类),它们在数据库上执行自己的查询,最后由连接管理器类调用提交/回滚。这种“架构”是否正确,或者您认为其中有什么危险?

提前谢谢你

【问题讨论】:

    标签: java jdbc transactions


    【解决方案1】:

    这是一个非常糟糕的设计,您对静态变量的观察是正确的。如果一个线程调用openDb 而另一个线程做同样的事情,事情就会出错。也许这种情况并非总是发生,这使得调试变得困难。

    关于问题 nr. 2:一旦你完成了它们,你应该关闭它们。这样您就不会占用不必要的资源。因此,当您从结果集中读取所有(必要的)数据时,请关闭它。让语句和结果集脱离事务边界也不是一个好主意。所以而不是:

    begin transaction
      open result set
    commit transaction
    read from result set
    

    你应该有:

    begin transaction
      open result set
      read from result set
    commit transaction
    

    为了使图片完整,在使用事务时应始终具有以下模式:

    begin transaction
      open connection
        read/modify data
      close connection
    commit transaction
    

    open connection/close connection 组合可能在一个事务中出现多次。

    编辑:为了进一步完善图片:在通常情况下,您的应用程序有几个层(例如 UI、业务、数据)。事务通常在业务层内启动和提交。从业务层调用成为事务一部分的一个或多个数据层方法:

    // Inside business layer:
    public void businessMethod(...) {
        try {
            // Begin transaction.
            dataMethod1(...);
            dataMethod2(...);
            ...
            // Commit transaction.
        }
        catch (...) {
        }
    }
    
    // Inside data layer.
    public void dataMethod1(...) {
        // Open connection.
        try {
            // Get data from database.
            // Manipulate data.
        }
        finally {
            // Close connection.
        }
    }
    

    一些补充说明:

    • 事务提交是 try/catch 中的最后一条语句(如果你想从你的方法中返回数据,它可以跟一个 return 语句)。这确保了事务仅在 一切 正常(即没有抛出异常)时提交。
    • 连接关闭位于 try 语句的 finally 部分。这确保它始终处于关闭状态,无论您的数据方法内部发生什么。

    【讨论】:

    • 非常感谢您快速而清晰的回答,还有一件事:您说打开/关闭连接可能会发生多次,但我想它总是相同的连接。在同一个事务中打开不同的连接怎么样?第二个连接会导致异常还是事务只会影响它关联的连接?
    • 第二次连接不会导致异常。它只会在同一个事务中运行。您不必担心重复使用相同的连接,只需在需要时打开一个新连接。 JDBC 使用连接池,因此创建新连接几乎不会对性能产生任何影响。
    • 最后两个问题:当你说“将在同一个事务中运行”时,你的意思是第二个连接是第一个连接事务的一部分还是第二个连接将独立于第一个连接?数据源提供的 jdbc 连接的更好策略是什么:连续打开和关闭连接或尝试使用较少的连接(我想第一个选项:不占用资源)
    • 这取决于您的应用程序设计以及什么更有意义。如果您在单个方法中并且需要在此方法中多次访问数据库,我将使用一个连接。如果您的事务跨越多个方法调用,您应该在每个方法中打开一个连接。我将在我的答案中添加更多信息来说明这种情况。
    • 很抱歉打扰您,我的意思是以下情况:conn1.setAutocommit(false); stmt1 = conn1.createstatement(); ... 一次或多次访问 db .. localhelperMethod1(); localhelpermethod2(); ... conn1.commit();如果类本地辅助方法仅访问 db 以检索数据,它们的内部连接将被纳入 conn1 事务还是独立的?我应该通过他们 conn1 还是我可以从数据源获得他们自己的连接。再次感谢您的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2021-01-20
    • 1970-01-01
    • 2023-03-29
    • 2011-02-03
    • 2011-07-12
    相关资源
    最近更新 更多