根据数据库中的可用性插入/更新行

时间:2012-04-11 05:38:44

标签: java mysql hibernate jpa jdbc

这是一种常见的情况,但我想知道性能优化方式和最佳实践的方式。

我有一个包含4列的表:id,name和另外两个字段。 Id是PK,名称是唯一键。我正在从excel文件中读取数据,填充Domain对象中每行的值,然后保存它。保存时,我想查看是否已存在同名的记录,如果存在,我想更新它。否则将其保存为新记录。

我可以使用普通的选择查询来查找名称并检查null,并根据该插入或更新但我要从excel文件中读取数千行,并且要求的非功能性要求是性能即可。

那么请告诉我哪种方法可以处理这种情况?我还没有开始编写我的持久层部分,所以我可以根据你的建议切换到ORM或普通的jdbc。

编辑: 如果我使用name作为主键,那么我认为我可以使用saveOrUpdate或从ORM合并,以满足我的需要。这是不是一个好主意??? 谢谢&问候, Prasath。

2 个答案:

答案 0 :(得分:3)

我认为最快的方法是在数据库本身执行所有插入/更新,而不是连接到它并使用大量语句。

请注意,这是Oracle特定的,但其他数据库可能有类似的概念。

我会使用以下方法:首先将Excel数据保存为数据库服务器上的CSV文件(/mydatadir/mydata.csv),然后在Oracle中我将使用external table

create or replace directory data_dir as '/mydatadir/';
create table external_table (
  id number(18),
  name varchar2(30),
  otherfield1 varchar2(40),
  otherfield2 varchar2(40))
organization external (
  type oracle_loader
  default directory data_dir
  access parameters
  ( fields terminated by ',' )
  location ('mydata.csv')
)

(注意,不必每次都设置外部表)

然后您可以使用以下命令将merge数据放入表中:

merge into yourtable t
using external_table e
on t.name = e.name
when matched then
   update set t.id = e.id, 
              t.otherfield1 = e.otherfield1, 
              t.otherfield2 = t.otherfield2
when not matched then
   insert (t.id, t.name, t.otherfield1, t.otherfield2)
   values (e.id, e.name, e.otherfield1, e.otherfield2)

这将在一个Oracle命令中将yourtable中的行挂起,因此所有工作都将由数据库执行。

编辑:

这个merge命令可以通过纯JDBC发出(虽然我更喜欢使用Spring的SimpleJdbcTemplate

EDIT2:

在MySQL中,您可以使用以下构造来执行合并:

insert into yourtable (id, name, otherfield1, otherfield2)
values (?, ?, ?, ?), 
       (?, ?, ?, ?), 
       (?, ?, ?, ?) --repeat for each row in the Excel sheet...
on duplicate Key update
set otherfield1 = values(otherfield1),
    otherfield2 = values(otherfield2)

这可以作为普通的JDBC语句发布,并且比单独的更新和插入更好,并且您可以从电子表格中批量调用(比如)一百行。这意味着Excel表格中每100行有一次JDBC调用,并且应该运行良好。这将允许您在没有外部表的情况下执行此操作(您需要在名称列上使用UNIQUE索引才能使其工作,我不会更改主键,因为如果您需要更改,这可能会导致外键问题某人的名字)。

MySQL也有external tables的概念,我认为这比按上述批量插入数据更快。只要将csv文件上载到正确的位置,导入就可以快速完成。

答案 1 :(得分:0)

读取Set中的所有名称并从excel文件中读取名称集合中减去使用组合可能是合理的。

Set dbSet=//fill it from SQl query;
Set newSet//fill it from the file;

newSet.removeAll(dbSet); //left non existing ones to be inserted.

originalNewSet(可能是初始的克隆)

originalNewSet.removeAll(insertingSet); //left records to be updated.