2012-02-22 44 views
0

我有一个使用Spring JDBC访问SQLite数据库的DAO类。我已经在DAO方法本身上声明了事务,因为我的服务层从不在事务中组合查询。春季交易及其与同步关键字的互动

因为我并行使用一些工作线程,但只有一个线程可以同时更新SQLite数据库,我使用​​序列化访问DAO。

起初,我从我的服务类外部同步,例如:

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

然后,我想我也可以摆脱外部同步,并把​​在DAO方法本身:

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

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

为什么?

+0

自从将服务方法同步到DAO方法后,它们需要两倍的时间? – MarianP 2012-02-22 09:02:42

+0

@MarianP:正确。 – 2012-02-22 09:15:31

回答

0

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

在第一种情况下,您甚至在到达代理之前进行同步,因此无法进行连接和事务处理。在第二种情况下,您在此之后等待电话。

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

+0

我使用了一个界限为4的BoundedExecutor,因此有4个线程正在进行计算,然后并行更新数据库。我用C3p0连接池做了一些测试,结果如下:池中有1个连接 - > 7秒,2个conns - > 13s,3个conns - > 13s,10个conns - > 13s和256 conns-> 13s。因此,当连接池大小大于1时,性能实际上会降低。有任何想法吗? – 2012-02-22 10:04:26

+0

如果您只进行更新,您可以尝试摆脱同步并使用一个连接使用池。至于执行比单个更糟糕的多个连接是非常清楚的。您实际上只允许在一次交易中使用,因此您不需要管理这些额外连接的开销。虽然我宁愿预计时间增加到4个连接,但保持不变。 – mrembisz 2012-02-22 10:22:26

1

嘛,一个区别是显而易见的:

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 
} 

这是什么是影响取决于你的其他代码,但是这是有明显区别。

+0

我猜在DAO的update()方法返回的**后面的情况下,1)其中的'synchronized'块结束,2)事务代理提交它的事务,所以它仍然有效同时更新SQLite数据库,即完全是我试图阻止的东西。这听起来似乎合理吗? – 2012-02-26 10:16:35