Spring事务及其与synchronized关键字的交互

发布于 2025-01-08 02:48:03 字数 485 浏览 0 评论 0原文

我有一个 DAO 类,它使用 Spring JDBC 访问 SQLite 数据库。我已经在 DAO 方法本身上声明了事务,因为我的服务层从不将查询组合到事务中。

由于我并行使用几个工作线程,但只有一个线程可以同时更新 SQLite DB,因此我使用 synchronized 来序列化对 DAO 的访问。

首先,我从服务类进行外部同步,例如:

synchronized (dao) {
    dao.update(...);
}

然后,我想我不妨摆脱外部同步,并将 synchronized 放在 DAO 方法本身上:

public synchronized void update(...) {
    // Spring JDBC calls here
}

奇怪的是:我的现在查询所需的时间是以前的两倍!

为什么?

I have a DAO class that uses Spring JDBC to access an SQLite database. I have declared transactions on the DAO methods themselves since my service layer never combines queries in a transaction.

Since I use a few worker threads in parallel but only one thread can update an SQLite DB at the same time, I use synchronized to serialize access to the DAO.

At first, I synchronized externally from my service class, for example:

synchronized (dao) {
    dao.update(...);
}

Then, I figured I might as well get rid of the external synchronization and put synchronized on the DAO method itself:

public synchronized void update(...) {
    // Spring JDBC calls here
}

The strange thing is: my queries now take twice the time they used to!

Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情深如许 2025-01-15 02:48:03

好吧,有一个区别是显而易见的:

synchronized (dao) {
    // here you are synchronizing on the transactional proxy
}

public synchronized void update(...) {
    // and here you are synchronizing on the target class, *inside* the proxy
}

这一点的含义取决于您的其他代码,但这就是明显的区别。

Well, one difference is obvious:

synchronized (dao) {
    // here you are synchronizing on the transactional proxy
}

public synchronized void update(...) {
    // and here you are synchronizing on the target class, *inside* the proxy
}

What the implications of this are depends on your other code, but that's the obvious difference.

知你几分 2025-01-15 02:48:03

我的猜测是您的更新方法或整个类都用事务注释或通过其他方式由事务代理包装。这意味着每当您调用 dao 的方法时,事务代理都会从池中检索数据库连接,打开一个事务,然后调用真正的方法。

在第一个场景中,您甚至在到达代理之前就进行了同步,因此不会发生连接和事务魔法。在第二种情况下,您在此之后进行等待呼叫。

如果有多个线程尝试同时执行更新,则只有一个线程执行更新,其余线程将首先打开新连接,然后等待 dao 访问。因此,您将使用多个连接,而不是不断地重复使用一个连接。我只能猜测这对性能有何影响,但您可以从一个开始尝试不同的池大小。

My guess is your update method or entire class is annotated with Transactional or wrapped by transactional proxy through other means. This means whenever you call dao's method, the transactional proxy retrieves db connection from the pool, opens a transaction and then calls the real method.

In your first scenario you synchronize before even reaching the proxy, thus no connection and transaction magic happens. In the second scenario you do the waiting call after that.

If there are multiple threads trying to perform simultaneous updates there will be only one doing the update and the rest will be first opening new connections and then waiting for dao access. As a consequence instead of one connection being constantly reused you will have multiple connections in use. I can only guess how this really affects the performance but you can experiment with different pool size starting with one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文