背景:
最近公司在做食堂POS机研发,有个功能是上传离线交易。每次向服务器提交1000~2000条数据,我们现在是循环将每一条save进去,现想优化下用存储过程来实现,减少jdbc连接。
1.准备
说明:我们数据库是:orcale 11g,java 是7
1.1 创建一张表
create table A
(
aa VARCHAR2(30),
b VARCHAR2(30),
c VARCHAR2(40)
)
1.2 java创建一个类带main方法的类
/**
*
* @类功能说明 TODO
* @类修改者
* @修改日期
* @修改说明
* @公司名称 Dlk
* @作者 樊强
* @创建时间 2015年10月8日 上午11:28:34
* @版本 V1.0
*
*/
public class JDBCProTest {
public static void main(String[] args) {
<span style="white-space:pre"> </span>
}
}
1.3 java 基本数据
private static String X_DRIVER = "oracle.jdbc.driver.OracleDriver";
private static String X_USERNAME = "bpim";
private static String X_PASSWORD = "123456";
private static String X_URL = "jdbc:oracle:thin:@192.168.1.25:1521:orcl";
2.直接在java程序里调用存储过程无参数无返回值。
2.1 存储过程
CREATE OR REPLACE PROCEDURE A_PROC
IS
BEGIN
INSERT INTO A (aa)values('1');
COMMIT;
END A_PROC;
2.2 java程序
/**
*
* @throws Exception
* @创建时间 2015年10月8日 上午11:35:03
* @作者 樊强
* @返回值 void
* @描述 测试调用存储过程:无返回值 无参数
*
*/
public static void testProcNoInNoOut() throws Exception {
System.out.println("------- start 测试调用存储过程:无返回值 无参数");
Connection conn = null;
CallableStatement callStmt = null;
try {
Class.forName(X_DRIVER);
conn = DriverManager.getConnection(X_URL, X_USERNAME, X_PASSWORD);
callStmt = conn.prepareCall("{call A_PROC()}");
callStmt.execute();
System.out.println("------- 测试调用存储过程:无返回值 无参数 End.");
} catch (Exception e) {
e.printStackTrace(System.out);
} finally {
if (null != callStmt) {
callStmt.close();
}
if (null != conn) {
conn.close();
}
}
}
public static void main(String[] args) {
try {
testProcNoInNoOut();
}catch (Exception e) {
e.printStackTrace();
}
}
2.3 结果
3.直接在java程序里调用存储过程带参数无返回值。
CREATE OR REPLACE PROCEDURE AA_PROC(AA IN VARCHAR2) IS
BEGIN
INSERT INTO A (aa)values(AA);
COMMIT;
END AA_PROC;
3.2 java程序
/**
*
*
* @param String a
* @throws Exception
* @创建时间 2015年10月8日 下午2:07:48
* @作者 樊强
* @返回值 void
* @描述 测试调用存储过程:无返回值 有参数
*
*/
public static void testProc(String a) throws Exception {
System.out.println("------- start 测试调用存储过程:无返回值 有参数");
Connection conn = null;
CallableStatement callStmt = null;
try {
Class.forName(X_DRIVER);
conn = DriverManager.getConnection(X_URL, X_USERNAME, X_PASSWORD);
callStmt = conn.prepareCall("{call AA_PROC(?)}");
callStmt.setString(1, a);
callStmt.execute();
System.out.println("------- 测试调用存储过程:无返回值 有参数 End.");
} catch (Exception e) {
e.printStackTrace(System.out);
} finally {
if (null != callStmt) {
callStmt.close();
}
if (null != conn) {
conn.close();
}
}
}
public static void main(String[] args) {
try {
testProc("中文");
} catch (Exception e) {
e.printStackTrace();
}
}
3.3 结果
4.直接测试带循环的存储过程
4.1 存储过程
CREATE OR REPLACE PROCEDURE AAA_PROC is
begin
for i in 1 .. 5 loop
insert into A (AA) values (i);
commit;
end loop;
end AAA_PROC;
4.2 测试存储过程
begin
aaa_proc;
end;
4.3 结果
5.调用带list参数的存储过程
带list参数的存储过程其实应该是array参数的存储过程,都是需要用list转化为array传到数据库中的。
5.1 存储过程
create or replace type a_table is table of number;
create or replace type b_table is table of varchar2(30);
create or replace type c_table is table of varchar2(30);
在存储过程创建之前先声明这个array中的数据类型。(1 这里不是很确定)
CREATE OR REPLACE PROCEDURE AAAAA_PROC(
v_1 a_table,
v_2 b_table,
v_3 c_table)is
v_count number;
begin
v_count := v_1.count;
for i in 1..v_count
loop
insert into A(AA, B, C)values(v_1(i),v_2(i), v_3(i));
commit;
end loop;
end AAAAA_PROC;
5.2java程序调用
/**
*
*
* @param a
* @throws Exception
* @创建时间 2015年10月8日 下午2:07:48
* @作者 樊强
* @返回值 void
* @描述 测试调用存储过程:无返回值 有参数list 多字段
*
*/
public static void testProcList(List<Number> a1,List<String> a2,List<String> a3) throws Exception {
System.out.println("------- start 测试调用存储过程:无返回值 有参数list<span style="background-color: rgb(255, 255, 255); "> 多字段</span>");
Connection conn = null;
CallableStatement callStmt = null;
try {
Class.forName(X_DRIVER);
conn = DriverManager.getConnection(X_URL, X_USERNAME, X_PASSWORD);
callStmt = conn.prepareCall("{call AAAAA_PROC(?,?,?)}");
ArrayDescriptor tabDesc = ArrayDescriptor.createDescriptor("A_TABLE", conn);
ArrayDescriptor tabDesc1 = ArrayDescriptor.createDescriptor("B_TABLE", conn);
ArrayDescriptor tabDesc2 = ArrayDescriptor.createDescriptor("C_TABLE", conn);
ARRAY vArray1 = new ARRAY(tabDesc, conn, a1.toArray());
ARRAY vArray2 = new ARRAY(tabDesc1, conn, a2.toArray());
ARRAY vArray3 = new ARRAY(tabDesc2, conn, a3.toArray());
callStmt.setArray(1, vArray1);
callStmt.setArray(2, vArray2);
callStmt.setArray(3, vArray3);
callStmt.execute();
System.out.println("------- 测试调用存储过程:无返回值 有参数list<span style="background-color: rgb(255, 255, 255); ">多字段 End.");</span>
} catch (Exception e) {
e.printStackTrace(System.out);
} finally {
if (null != callStmt) {
callStmt.close();
}
if (null != conn) {
conn.close();
}
}
}
public static void main(String[] args) {
try {
long aaaa=System.currentTimeMillis();
List<Number> a=new ArrayList<Number>();
List<String> b=new ArrayList<String>();
List<String> c=new ArrayList<String>();
a.add(1);
b.add("A"+1);
c.add("AA"+1);
testProcList(a,b,c);
long bbbb=System.currentTimeMillis();
System.out.println((bbbb-aaaa)/ 1000.00);
<span style="white-space:pre"> </span>} catch (Exception e) {
e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
5.3 结果
0.488秒
下面对这个调用过程做了个时间的验证
public static void main(String[] args) {
try {
long aaaa = System.currentTimeMillis();
// testProcNoOut();
// testProc("中文");
List<Number> a = new ArrayList<Number>();
List<String> b = new ArrayList<String>();
List<String> c = new ArrayList<String>();
for (int i = 0; i < 1000000; i++) {
a.add(i);
b.add("A" + i);
c.add("AA" + i);
}
testProcList(a, b, c);
long bbbb = System.currentTimeMillis();
System.out.println((bbbb - aaaa) / 1000.00);
} catch (Exception e) {
e.printStackTrace();
}
}
100条 0.592秒
1000条 0.604秒
10000条 1.306秒
100000条 8.663秒
1000000条 85.3秒