0

我有一个运行 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)

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

问候,乔伊

4

3 回答 3

0

将两个语句包装在一个事务中:

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

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

于 2011-11-14T12:23:20.690 回答
0

您是否使用任何类型的同步?首先,您需要将修改表的代码包装在:

synchronized(obj)
{
    // code
}

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

于 2011-11-14T12:23:23.723 回答
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 并发管理功能的简单机制。检查此链接以获取有关乐观锁定的更多信息http://en.wikipedia.org/wiki/Optimistic_concurrency_control#Examples

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

同样对于双重插入,您的交易被拒绝的事实很好,这意味着没有插入重复的密钥。您应该只处理异常并通知用户发生了什么。

于 2011-11-14T14:30:31.780 回答