我正在开发一个具有某种'facebook like'功能的应用程序。每当用户发布的内容被“喜欢”时,他的标点符号就会增加。该应用程序将被公司周围的大量用户使用,因此我们期待同一行的大量并发更新。
简化代码
Punctuation(
userId NVARCHAR2(32),
value NUMBER(10,0)
)/
public class Punctuation(){
private String userId;
private int value;
public Punctuation(final String userId, final int value){
this.userId = userId;
this.value = value;
}
public String getUserId();
public int getValue();
}
//simplified code
public final class PunctuationController{
private PunctuationController(){}
public static void addPunctuation(final Punctuation punctuation){
final Transaction transaction = TransactionFactory.createTransaction();
Connection conn = null;
PreparedStatment statment = null;
try{
synchronized(punctuation){
transaction.begin();
conn = transaction.getConnection();
statment = conn.preparedStatment("UPDATE Punctuation SET value = value + ? where userId = ?");
statment.setString('1', punctuation.getUserId());
statment.setInt('2', punctuation.getValue());
transaction.commit();
}
}catch (Exception e){
transaction.rollback();
}finally{
transaction.dispose();
if(statment !=null){
statment.close();
}
}
}
我们担心更新期间会出现死锁。 Oracle允许在单个查询上进行求和,我不必检索值并使用新值进行第二次查询更新,这很好。另外在这里阅读其他一些帖子,他们说要创建一个同步块来锁定一个对象,让Java处理不同线程之间的同步。我选择方法接收的标点符号实例,这样我想象用户和值的不同组合将允许并发访问此方法,但会阻止具有相同值的实例(我是否必须在标点符号上实现equals()?)
我们的数据库是Oracle 10g,Server Weblogic 11g,Java 6和Linux(我不知道哪种风格)。
提前谢谢!
答案 0 :(得分:3)
你的同步策略错了。 synchronized
使用括号内对象的内部锁。如果你有两个Punctuation
实例,你可能认为它们是相同的,因为它们引用相同的user_id
,Java不关心:2个对象,所以2个锁,所以没有互斥。
我真的不明白为什么上面没有synchronized
的情况会产生死锁:你正在更新表中的一行。如果你有两个并发事务,一个更新user1,然后是user2,另一个更新user2,然后是user1,你可能会遇到死锁。但即使这样,数据库也会检测死锁并为其中一个事务抛出异常。
答案 1 :(得分:0)
您需要使用乐观锁定模式。请查看此处了解更多详情http://docs.jboss.org/jbossas/docs/Server_Configuration_Guide/4/html/The_CMP_Engine-Optimistic_Locking.html
使用乐观锁识别并发问题后,您可能希望重新尝试 - 您可以完全控制该怎么做