Java:在作用域出口自动调用函数(如c ++析构函数)

Hei*_*nzi 5 java jdbc

对于MySQL连接我有一个连接对象,并使用一个交易机制connection.startTransaction(),connection.commitTransaction(),connection.rollbackTransaction().

对于每一个startTransaction(),必须始终有要么打电话commitTransaction()或到rollbackTransaction().错过这样的电话或同时打电话都会破坏我的交易系统.

所以我用以下方式使用它们:

boolean i_am_in_a_transaction=true;
try {
    connection.startTransaction();
    ...
    i_am_in_a_transaction=false;
    connection.commitTransaction();
} finally {
    if(i_am_in_a_transaction) {
        connection.rollbackTransaction();
    }
}
Run Code Online (Sandbox Code Playgroud)

这确保了声明的调用顺序,但这是很费力的,因为我必须在我使用事务的地方写这些行.

在C++中,我将使用一个事务对象来检查它的析构函数,如果commit()函数被调用,否则调用rollback():

class Transaction {
    public:
        Transaction()
            :am_in_transaction(false) {
        }

        ~Transaction() {
            if(_am_in_transaction) {
                rollback();
            }
        }

        void startTransaction() {
            _am_in_transaction=true;
            ...start Transaction...
        }

        void commit() {
            _am_in_transaction=false;
            ...commit Transaction...
        }

        void rollback() {
            _am_in_transaction=false;
            ...rollback Transaction...
        }

    private:
        bool _am_in_transaction;
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以在一个地方实现逻辑,并且可以非常简单地使用它:

Transaction my_transaction;
my_transaction.startTransaction;
...
my_transaction.commit();
Run Code Online (Sandbox Code Playgroud)

这个代码比上面的带有try/finally块的java代码简单得多.

有没有办法在java中实现这种行为而不将逻辑专用于调用者并使他实现try/finally块?

类似于在范围退出时自动调用函数的方法会对我有所帮助.

Luc*_*ore 5

东西类似(非常重要的),析构函数在C++是方法finalize().不同之处在于无法保证垃圾收集器何时会实际调用它,因此不建议依赖它.

否则,你能做的最好就是try/finally阻止.


Ale*_*exR 5

Java没有析构函数.但是有几种"标准"解决方案可以帮助您.

1.使用名为"模板方法"的模式.

abstract class Base {
    public query() {
         openTransaction();
         doQuery();
         closeTransaction();
    }
    protected abstract doQuery();
}
Run Code Online (Sandbox Code Playgroud)

现在,您应该doQuery()在您创建的每个子类中实现它,并通过从基类调用'query()'来使用它.

2.使用面向方面的编程

3.使用装饰器(Wrapper)模式.

4.使用一种流行的ORM框架(Hibernate,iBatis等)为您解决所有这些问题,并且根本不处理低级JDBC的问题.


Bre*_*ode 4

我想到了几个解决方案......

正如 @Dark Falcon 指出的那样,这将是尝试资源调用的一个很好的用例,它将在尝试结束时自动清理您的资源。不幸的是,这仅在 Java 7 中可用。

Java 类确实定义了一个finalize()方法,当对象被垃圾回收时可以调用该方法,但重写该方法几乎从来都不是正确的做法。

我认为,如果您着迷于“在函数返回时执行代码”的想法,那么您唯一的其他选择就是使用面向方面编程。如果您阅读了一些包(例如AspectJ)或研究了将AOP 与 Spring一起使用,您可以执行一些配置魔法,通过拦截调用来在函数返回时获取要执行的代码。下面是一个使用 Spring AOP 在函数返回时执行其他代码的示例。