如何启用多线程/连接修改相同的mysql表?

时间:2011-11-14 12:18:30

标签: java mysql acid

我有一个运行2个线程的程序,每个线程都有自己的数据库JDBC连接,他们将访问/修改同一个数据库表A,如下所示。表A只有2列(id,name),主键是id和name的组合。

statement stmt;

// first delete it if the record has exist in table
stmt.addBatch("delete from A where id='arg_id' and name='arg_name';");

// then insert it to table
stmt.addBatch("insert into A values (arg_id, arg_name);");

stmt.executeBatch();

2个线程可能会向表中插入相同的数据,我得到以下异常,

java.sql.BatchUpdateException: Duplicate entry '0001-joey' for key 1
        at com.mysql.jdbc.Statement.executeBatch(Statement.java:708)
        at com.mchange.v2.c3p0.impl.NewProxyStatement.executeBatch(NewProxyStatement.java:743)
        at proc.Worker.norD(NW.java:450)

你知道如何解决这个问题吗?谢谢。

此致 乔伊

3 个答案:

答案 0 :(得分:0)

在事务中包装两个语句:

BEGIN;
DELETE FROM a WHERE ...;
INSERT INTO a VALUES (...);
COMMIT;

请注意,只要表只包含主键,只有在表末未修改时才会出现此冲突;我假设您要添加更多列,在这种情况下,您应该使用UPDATE ... WHERE语法来更改值。

答案 1 :(得分:0)

您使用的是同步吗?首先,您需要包装修改表的代码:

synchronized(obj)
{
    // code
}

其中obj是两个线程都可以访问的对象。 我不知道你的表修改的确切语义,但如果它们都插入id,你还需要保持一个“全局”id并在每个线程中以原子方式递增它,这样它们都不会得到相同的值

答案 2 :(得分:0)

为什么不在数据库中引入简单的乐观锁定机制?

添加版本列并在执行删除或更新事务时跟踪版本号。

你的桌子看起来像是

create table test(
id int not null primary key,
name varchar,
rowversion int default = 0);

每次检索行时,都应检索行版本,以便执行

update test set name='new name' rowversion=rowversion+1 where id=id and rowversion=retrieved row version;

与删除相同

delete from test where id=id and rowversion=retrievedRowVersion;

这是一种利用dbms concurency管理功能的简单机制。有关乐观锁定http://en.wikipedia.org/wiki/Optimistic_concurrency_control#Examples

的更多信息,请查看此链接

这显然只是一个非常简单的concurency管理实现,但你的问题必须考虑到这些。

同样对于双重插入,您的事务被拒绝的事实是好的,这意味着不会插入重复的键。您应该只处理异常并通知用户发生了什么。