我有一个运行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)
你知道如何解决这个问题吗?谢谢。
此致 乔伊
答案 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管理实现,但你的问题必须考虑到这些。
同样对于双重插入,您的事务被拒绝的事实是好的,这意味着不会插入重复的键。您应该只处理异常并通知用户发生了什么。