Hibernate insert 效率

tpz_stamp 2009-11-23 10:23:46
我借助Hibernate的 cascade机制往数据库插入新纪录,一次插入大概要2000来条记录,运行起来相当慢,请问有什么优化的方案吗?数据库是oracle 10g
...全文
322 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
crazylaa 2009-11-24
  • 打赏
  • 举报
回复

另外说明下,代码是按楼主需求拼凑的。所以:
1。方法insParentChils两个参数的ArrayList长度必须一致。就是说,一个Parent必须对应一个Child列表。
针对有Parent无Child或有Child无Parent的情况,这里都没有做处理。
2。对于List为空,或size()==0等异常没有处理。
3。一个Parent对应的Child列表的Child个数可以是不同的,例如,TestOracleArray.java中,
ArrayList<ArrayList<Child>> clstMap = new ArrayList<ArrayList<Child>>();
for (int i = 0; i < 100; i++) {
ArrayList<Child> clst = new ArrayList<Child>();
for (int j = 0; j < 100; j++) {
if((i%2==0)&&(j>=50)){
break;
}
Child c = new Child();
c.setChildName("childName" + j);
c.setChildTitle("childT" + j);
c.setChildContent("childContent"+j);
clst.add(c);
}
clstMap.add(clst);
}

同样可以插入。

4。祝楼主好运,早日解决你的问题。

5。再顶一个,嘿嘿。
crazylaa 2009-11-24
  • 打赏
  • 举报
回复
接上:
OracleArray.java

package test.oracle.array;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;

import oracle.jdbc.driver.OracleTypes;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

public class OracleArray {
private static final String T_PARENT = "T_PARENT";

private static final String T_PARENT_LST = "T_PARENT_LST";

private static final String T_CHILD = "T_CHILD";

private static final String T_CHILD_LST = "T_CHILD_LST";

private static final String T_CHILD_LST_MAP = "T_CHILD_LST_MAP";

private static final String PROC_INS_PARENT_CHILD = "{ call PROC_INS_PARENT_CHILD(?,?,?)}";

public static int insParentChils(ArrayList<Parent> plst,
ArrayList<ArrayList<Child>> clstMap, Connection con)
throws Exception {
CallableStatement cstmt = null;

int retVal = -1;

try {

ArrayDescriptor parentLstDesc = ArrayDescriptor.createDescriptor(
T_PARENT_LST, con);
StructDescriptor parentDesc = StructDescriptor.createDescriptor(
T_PARENT, con);
ArrayDescriptor childLstMapDesc = ArrayDescriptor.createDescriptor(
T_CHILD_LST_MAP, con);
ArrayDescriptor childLstDesc = ArrayDescriptor.createDescriptor(
T_CHILD_LST, con);
StructDescriptor childDesc = StructDescriptor.createDescriptor(
T_CHILD, con);

ArrayList<STRUCT> pstruct = new ArrayList<STRUCT>();

// 转换plst为Oracle 对象数组
for (int i = 0; i < plst.size(); i++) {
Parent p = plst.get(i);
Object[] record = new Object[2];
record[0] = p.getName();
record[1] = p.getTitle();
STRUCT item = new STRUCT(parentDesc, con, record);
pstruct.add(item);
}

ARRAY dataps = new ARRAY(parentLstDesc, con, pstruct.toArray());

ArrayList<ARRAY> cMap = new ArrayList<ARRAY>();

// 转换clst为Oracle 对象数组
for (int i = 0; i < clstMap.size(); i++) {
ArrayList<Child> childLst = clstMap.get(i);
ArrayList<STRUCT> cstruct = new ArrayList<STRUCT>();
for (int j = 0; j < childLst.size(); j++) {
Child c = childLst.get(j);
Object[] record = new Object[3];

record[0] = c.getChildName();
record[1] = c.getChildTitle();
record[2] = c.getChildContent();
STRUCT item = new STRUCT(childDesc, con, record);
cstruct.add(item);
}
ARRAY datacs = new ARRAY(childLstDesc, con, cstruct.toArray());
cMap.add(datacs);
}

ARRAY datacsMap = new ARRAY(childLstMapDesc, con, cMap.toArray());
cstmt = con.prepareCall(PROC_INS_PARENT_CHILD);
cstmt.setArray(1, dataps);
cstmt.setArray(2, datacsMap);
cstmt.registerOutParameter(3, OracleTypes.INTEGER);
cstmt.execute();
retVal = cstmt.getInt(3);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
if (cstmt != null) {
cstmt.close();
}

} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
return retVal;
}
}


OConnection.java

package test.oracle.conn;

import java.sql.Connection;
import java.sql.DriverManager;

public class OConnection {
public static Connection getConn() {
String URL = "jdbc:oracle:thin:@127.0.0.1:1521:oradb";
String user = "cartoon";// 这里替换成你自已的数据库用户名
String password = "oracle";// 这里替换成你自已的数据库用户密码
Connection connection = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
System.out.println("类实例化成功!");

connection = DriverManager.getConnection(URL, user, password);
System.out.println("创建连接对像成功!");

} catch (Exception err) {
err.printStackTrace();
return null;
}

return connection;
}

}


TestOracleArray.java


package test.oracle;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;

import test.oracle.array.Child;
import test.oracle.array.OracleArray;
import test.oracle.array.Parent;
import test.oracle.conn.OConnection;

public class TestOracleArray {

public static void main(String[] args) {

ArrayList<Parent> plst = new ArrayList<Parent>();
for (int i = 0; i < 100; i++) {
Parent p = new Parent();
p.setName("name" + i);
p.setTitle("title" + i);
plst.add(p);
}

ArrayList<ArrayList<Child>> clstMap = new ArrayList<ArrayList<Child>>();
for (int i = 0; i < 100; i++) {
ArrayList<Child> clst = new ArrayList<Child>();
for (int j = 0; j < 100; j++) {
Child c = new Child();
c.setChildName("childName" + j);
c.setChildTitle("childT" + j);
c.setChildContent("childContent"+j);
clst.add(c);
}
clstMap.add(clst);
}
Connection con = null;
try {
long startTime = 0;
long endTime = 0;
con = OConnection.getConn();
startTime = new Date().getTime();
OracleArray.insParentChils(plst, clstMap, con);
endTime = new Date().getTime();
System.out.println("It takes " + (endTime - startTime)
+ " milliseconds to execute");

} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null) {
con.close();
System.out.println("disconnected");
}
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
System.exit(0);
}

}
crazylaa 2009-11-24
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 tpz_stamp 的回复:]
引用 13 楼 crazylaa 的回复:
引用楼主 tpz_stamp 的回复:
我借助Hibernate的 cascade机制往数据库插入新纪录,一次插入大概要2000来条记录,运行起来相当慢,请问有什么优化的方案吗?数据库是oracle 10g,插入涉及多表,多表之间有关联怎么办?


jdbc直连调用oracle 存储过程,用数组作为传入参数。快得很。


能不能举个例子,比如有Parent Child两张表,
Child里有parent_id的column,
要插入多个Parent ,每个Parent有多个Child。
[/Quote]

[Quote=引用 18 楼 tpz_stamp 的回复:]
引用 13 楼 crazylaa 的回复:
引用楼主 tpz_stamp 的回复:
我借助Hibernate的 cascade机制往数据库插入新纪录,一次插入大概要2000来条记录,运行起来相当慢,请问有什么优化的方案吗?数据库是oracle 10g,插入涉及多表,多表之间有关联怎么办?


jdbc直连调用oracle 存储过程,用数组作为传入参数。快得很。


能不能举个例子,比如有Parent Child两张表,
Child里有parent_id的column,
要插入多个Parent ,每个Parent有多个Child。
[/Quote]

给写了一个Oracle存储过程操作数组的例子,给楼主参考。
按照楼主描述的。建纯表,未建PK,索引。
测试机器:
Intel(R) Core(TM)2 Duo CPU
T5450 @ 1.66GHz
980MHz,0.99G的内存
测试前
在本机已开Oracle/Jbuilder2007的情况下,
任务管理器显示内存 提交更改:1105M /2436M

数据量:Parent表和Child表

SQL> select count(*) from Parent;

COUNT(*)
----------
1700

SQL> select count(*) from Child;

COUNT(*)
----------
300550


插入耗时:Parent 100,Child 3000的情况下
IWAV0055I Java Bean test.oracle.TestOracleArray started with the main method
类实例化成功!
创建连接对像成功!
It takes 1188 milliseconds to execute
disconnected


插入耗时:Parent 100, Child 10000的情况下
IWAV0055I Java Bean test.oracle.TestOracleArray started with the main method
类实例化成功!
创建连接对像成功!
It takes 3532 milliseconds to execute
disconnected


楼主可以自己测试。附代码清单:

数组、二维数组、类型、存储过程.sql

create table parent(
id number(10),
name varchar2(100),
title varchar2(10)
);

create table child(
id number(10),
parent_id number(10),
child_name varchar2(100),
child_title varchar2(10),
child_content varchar2(200),
child_time timestamp
);

create sequence seq_p_c_id
minvalue 1
maxvalue 9999999999
start with 1
increment by 1
nocache;

drop type t_child_lst_map;
drop type t_child_lst;
drop type t_parent_lst;

create or replace type t_parent as object (
name varchar2(100),
title varchar2(10)
);
/

create or replace type t_child as object (
child_name varchar2(100),
child_title varchar2(10),
child_content varchar2(200)
);
/

create or replace type t_parent_lst as table of t_parent;
/

create or replace type t_child_lst as table of t_child;
/

create or replace type t_child_lst_map as table of t_child_lst;
/

create or replace procedure proc_ins_parent_child(
i_parent_lst in t_parent_lst, --parent列表
i_child_map_lst in t_child_lst_map, --child列表集合,一个map元素对应一个child_lst,其下标与 parent列表的下标相同。
o_ret out number
) as
var_parent t_parent;
var_child_lst t_child_lst;
var_child t_child;
var_parent_id number;
var_child_id number;
begin
for i in 1..i_parent_lst.count loop
--取得parent各列的值
var_parent := i_parent_lst(i);

--取得parent_id;
select seq_p_c_id.nextVal into var_parent_id from dual;

--插入parent表
insert into parent(
id,
name,
title
)
values(
var_parent_id,
var_parent.name,
var_parent.title
);

--取得该parent对应的child列表
var_child_lst := i_child_map_lst(i);

for j in 1..var_child_lst.count loop
var_child := var_child_lst(j);

--取得child_id;
select seq_p_c_id.nextVal into var_child_id from dual;

--插入child表
insert into child(
id,
parent_id,
child_name,
child_title,
child_content,
child_time
)
values(
var_child_id,
var_parent_id,
var_child.child_name,
var_child.child_title,
var_child.child_content,
systimestamp
);
end loop;

end loop;
o_ret := 0;

exception when others then
begin
o_ret := -1;
raise;
end;
end proc_ins_parent_child;
/



Parent.java
package test.oracle.array;

public class Parent {
private String id;

private String name;

private String title;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String toString() {
return "Parent{id=" + this.id + ",name=" + this.name + ",title="
+ this.title + "}";
}
}


Child.java

package test.oracle.array;

public class Child {
private String id;

private String parentId;

private String childName;

private String childTitle;

private String childContent;

private String childTime;

public String getChildContent() {
return childContent;
}

public void setChildContent(String childContent) {
this.childContent = childContent;
}

public String getChildName() {
return childName;
}

public void setChildName(String childName) {
this.childName = childName;
}

public String getChildTime() {
return childTime;
}

public void setChildTime(String childTime) {
this.childTime = childTime;
}

public String getChildTitle() {
return childTitle;
}

public void setChildTitle(String childTitle) {
this.childTitle = childTitle;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getParentId() {
return parentId;
}

public void setParentId(String parentId) {
this.parentId = parentId;
}

public String toString() {
return "Child{id=" + this.id + ",parentId=" + this.parentId
+ ",childName=" + this.childName + ",childTitle="
+ this.childTitle + ",childContent=" + this.childContent
+ ",childTime=" + this.childTime + "}";
}
}
tpz_stamp 2009-11-24
  • 打赏
  • 举报
回复
感谢楼上的兄弟,如果我稍微改动一下oracle的object,child被嵌套到parent里面,java 代码应该如何传参数到存储过程呢?

create type t_child as object (
child_name varchar2(100),
child_title varchar2(10),
child_content varchar2(200)
);


create type t_child_lst as table of t_child;

create type t_parent as object (
name varchar2(100),
title varchar2(10),
children t_child_lst
);
crazylaa 2009-11-24
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 tpz_stamp 的回复:]
感谢楼上的兄弟,如果我稍微改动一下oracle的object,child被嵌套到parent里面,java 代码应该如何传参数到存储过程呢?

create  type t_child as object (
    child_name varchar2(100),
    child_title varchar2(10),
    child_content varchar2(200)
);


create  type t_child_lst as table of t_child;

create type t_parent as object (
    name varchar2(100),
    title varchar2(10),
    children t_child_lst
);
[/Quote]

针对 t_child_lst,仍然按我代码里面的组织成ARRAY。
t_parent则使用STRUCT来转换即可。你把你的t_parent里面的 children当作一个与title类似的列,只不过它的列类型是自定义的不定长数组而已。
ma309385560 2009-11-23
  • 打赏
  • 举报
回复
不知道你是从哪来的数据要是从数据库里边的数据 用plsql的装载函数 如果是外边传入的数据 批量插入 如果不用cascade 批量加plsql触发器
tpz_stamp 2009-11-23
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 invoked 的回复:]
JDBC要快的多,Hibernate这样太慢了
[/Quote]
插入涉及多表,多表之间有关联怎么办?
tpz_stamp 2009-11-23
  • 打赏
  • 举报
回复
补充一下,插入对象涉及多张表。
invoked 2009-11-23
  • 打赏
  • 举报
回复
JDBC要快的多,Hibernate这样太慢了
phyerbarte 2009-11-23
  • 打赏
  • 举报
回复
使用纯JDBC看是否能够提高速度,如果明显,建议这部分直接使用hibernate调用纯SQL来做,封装太多影响效率非常明显,上百万级就哭吧。。
doney_dongxiang 2009-11-23
  • 打赏
  • 举报
回复
使用批处理 或者 直接使用 jdbc方式 编写 效果很明显
hbwhwang 2009-11-23
  • 打赏
  • 举报
回复
你的这种需求,根本不适合用cascade来做
直接用批处理insert
lzt2008 2009-11-23
  • 打赏
  • 举报
回复
建议换种方式 ,拼sql语句
把压力转向数据库
kokobox 2009-11-23
  • 打赏
  • 举报
回复
你先查查是不是hibernate的问题,不要慢就觉得hibernate的问题,这点数据对于hibernate来说不算什么,你先看看你的表是否建立索引太多,有没有触发器之类的动作设置。
closewbq 2009-11-23
  • 打赏
  • 举报
回复
可能是session缓存的问题
这样改下:

int i=0;
int sum=集合的大小.
for (Object xxx: 数据集合) {
session.save(xxx);
i++;
if (i ==sum) {
tx.commit();
i = 0;
session.flush();
session.clear();
tx = session.beginTransaction();
}
}
if (i != 0) {
tx.commit();
session.flush();
session.clear();
}
tpz_stamp 2009-11-23
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 warison2008 的回复:]
使用批处理啊
[/Quote]

cascade了好几层,我只save了 顶层的 root object,下面就靠cascade去处理了,这种情况如何批处理?
道光2008 2009-11-23
  • 打赏
  • 举报
回复
使用批处理啊
liguominz 2009-11-23
  • 打赏
  • 举报
回复
关注一下~
blliy117 2009-11-23
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 closewbq 的回复:]
可能是session缓存的问题
这样改下:
Java codeint i=0;int sum=集合的大小.for (Object xxx: 数据集合) {
session.save(xxx);
i++;if (i==sum) {
tx.commit();
i=0;
session.flush();
session.clear();
tx= session.beginTransaction();
}
}if (i!=0) {
tx.commit();
session.flush();
session.clear();
}
[/Quote]
这段代码可以参考一下!
JamesLiu 2009-11-23
  • 打赏
  • 举报
回复
慢的话就换JDBC啦,或者直接PL/SQL
加载更多回复(7)

81,092

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧