从开始写java程序就一直被灌输着一种思想,如果使用jdbc一定要使用PreparedStatement,而不要使用Statement对象。
其中的原因有好多,比如可以防止SQL注入攻击,防止数据库缓冲池溢出,代码的可读性,可维护性。这些都很正确。
但是还有一点人们经常提的就是PreparedStatement能够显著的提高执行效率。
看了两篇关于PreparedStatement和Statement的帖子
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=10397&start=0&tstart=0
http://www.iteye.com/topic/5631?page=1
里面提到,PreparedStatement并不一定比Statement快,于是想自己动手测试一下
一共分5种情况测试
[code]
stmt pre-stmt
--1:每次都单独连数据库--100条
21.936 22.076
22.05 22.051
22.172 22.178
--2:Stmt使用相同的SQL语句,参数值也相同--100条
0.78 0.796
0.718 0.749
0.749 0.764
--3:Stmt使用相同的SQL语句,参数值不同--100条
0.967 0.749
0.78 0.874
0.749 0.749
--4:Stmt使用相同的SQL语句,参数值也相同--10000条
33.079 36.154
34.156 39.306
34.359 36.138
--5:Stmt使用相同的SQL语句,参数值不同--10000条
32.799 34.125
32.564 35.53
35.701 34.952
32.582 40.798
38.893 42.345
35.082 41.736
[/code]
分析:
第一种情况:
由于我测试时采用jdbc直接链接数据库,所以在第一种情况下插入速度很慢,时间都消耗在了数据库链接的创建上了,符合常理,没什么疑义。
第二种情况:
由于使用Statement插入时sql语句都相同,我通过阅读上面的两篇帖子,猜想可能是Statement语句也被DB缓存了,所以跟
PreparedStatement速度差不多,我想如果每次插入的sql都不同,那么Statement应该慢下来了吧。
第三种情况:
并非像我在执行第二种情况时想象的那样,PreparedStatement还是跟Statement差不多,于是我想是不是数据量不够大呀,于是我增大了
插入数据量,希望PreparedStatement能够比Statement快些
第四/五种情况:
测试结果PreparedStatement反到更慢了。
[color=blue]
PreparedStatement什么情况下才会比Statement快?那位大侠来指点一下!
[/color]
代码如下:
DDL
[code]
CREATE TABLE dbo.jdbc_stmt
(
id numeric(10,0) IDENTITY,
name varchar(10) NOT NULL,
grad int NOT NULL,
age int NOT NULL,
dept int NOT NULL
)
[/code]
测试程序
[code]
public void jdbcStmtPerformance()
{
//1:每次都单独连数据库--100条
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// getJdbcTemplate().update(stmtSQL);
// }
//2:Stmt使用相同的SQL语句,参数值也相同--100条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL);
// }
// return null;
// }
// });
//3:Stmt使用相同的SQL语句,参数值不同--100条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL+i+")");
// }
// return null;
// }
// });
// 4:Stmt使用相同的SQL语句,参数值也相同--10000条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 10000; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL);
// }
// return null;
// }
// });
// 5:Stmt使用相同的SQL语句,参数值不同--10000条
getJdbcTemplate().execute(new StatementCallback(){
public Object doInStatement(Statement stmt) throws SQLException
{
String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,";
for(int i = 0; i< 10000; i++)
{
logger.debug("stmt #"+i);
stmt.executeUpdate(stmtSQL+i+")");
}
return null;
}
});
}
public void jdbcPreStmtPerformance()
{
//1:每次都单独连数据库--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// getJdbcTemplate().update(stmtSQL, new Object[]{"ivanl", new Integer(2), new Integer(25), new Integer(1002)});
// }
//2:Stmt使用相同的SQL语句,参数值也相同--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, 1002);
// ps.execute();
// }
// return null;
// }
// });
//3:Stmt使用相同的SQL语句,参数值不同--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, i);
// ps.execute();
// }
// return null;
// }
// });
//4:Stmt使用相同的SQL语句,参数值也相同--10000条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 10000; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, 1002);
// ps.execute();
// }
// return null;
// }
// });
//5:Stmt使用相同的SQL语句,参数值不同--10000条
String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
{
for(int i = 0; i< 10000; i++)
{
logger.debug("pre-stmt #"+i);
ps.setString(1, "ivanl");
ps.setInt(2, 2);
ps.setInt(3, 25);
ps.setInt(4, i);
ps.execute();
}
return null;
}
});
}
[/code]
其中的原因有好多,比如可以防止SQL注入攻击,防止数据库缓冲池溢出,代码的可读性,可维护性。这些都很正确。
但是还有一点人们经常提的就是PreparedStatement能够显著的提高执行效率。
看了两篇关于PreparedStatement和Statement的帖子
http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=10397&start=0&tstart=0
http://www.iteye.com/topic/5631?page=1
里面提到,PreparedStatement并不一定比Statement快,于是想自己动手测试一下
一共分5种情况测试
[code]
stmt pre-stmt
--1:每次都单独连数据库--100条
21.936 22.076
22.05 22.051
22.172 22.178
--2:Stmt使用相同的SQL语句,参数值也相同--100条
0.78 0.796
0.718 0.749
0.749 0.764
--3:Stmt使用相同的SQL语句,参数值不同--100条
0.967 0.749
0.78 0.874
0.749 0.749
--4:Stmt使用相同的SQL语句,参数值也相同--10000条
33.079 36.154
34.156 39.306
34.359 36.138
--5:Stmt使用相同的SQL语句,参数值不同--10000条
32.799 34.125
32.564 35.53
35.701 34.952
32.582 40.798
38.893 42.345
35.082 41.736
[/code]
分析:
第一种情况:
由于我测试时采用jdbc直接链接数据库,所以在第一种情况下插入速度很慢,时间都消耗在了数据库链接的创建上了,符合常理,没什么疑义。
第二种情况:
由于使用Statement插入时sql语句都相同,我通过阅读上面的两篇帖子,猜想可能是Statement语句也被DB缓存了,所以跟
PreparedStatement速度差不多,我想如果每次插入的sql都不同,那么Statement应该慢下来了吧。
第三种情况:
并非像我在执行第二种情况时想象的那样,PreparedStatement还是跟Statement差不多,于是我想是不是数据量不够大呀,于是我增大了
插入数据量,希望PreparedStatement能够比Statement快些
第四/五种情况:
测试结果PreparedStatement反到更慢了。
[color=blue]
PreparedStatement什么情况下才会比Statement快?那位大侠来指点一下!
[/color]
代码如下:
DDL
[code]
CREATE TABLE dbo.jdbc_stmt
(
id numeric(10,0) IDENTITY,
name varchar(10) NOT NULL,
grad int NOT NULL,
age int NOT NULL,
dept int NOT NULL
)
[/code]
测试程序
[code]
public void jdbcStmtPerformance()
{
//1:每次都单独连数据库--100条
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// getJdbcTemplate().update(stmtSQL);
// }
//2:Stmt使用相同的SQL语句,参数值也相同--100条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL);
// }
// return null;
// }
// });
//3:Stmt使用相同的SQL语句,参数值不同--100条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL+i+")");
// }
// return null;
// }
// });
// 4:Stmt使用相同的SQL语句,参数值也相同--10000条
// getJdbcTemplate().execute(new StatementCallback(){
// public Object doInStatement(Statement stmt) throws SQLException
// {
// String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,1001)";
// for(int i = 0; i< 10000; i++)
// {
// logger.debug("stmt #"+i);
// stmt.executeUpdate(stmtSQL);
// }
// return null;
// }
// });
// 5:Stmt使用相同的SQL语句,参数值不同--10000条
getJdbcTemplate().execute(new StatementCallback(){
public Object doInStatement(Statement stmt) throws SQLException
{
String stmtSQL = "insert into jdbc_stmt values('ivanl',2,25,";
for(int i = 0; i< 10000; i++)
{
logger.debug("stmt #"+i);
stmt.executeUpdate(stmtSQL+i+")");
}
return null;
}
});
}
public void jdbcPreStmtPerformance()
{
//1:每次都单独连数据库--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// getJdbcTemplate().update(stmtSQL, new Object[]{"ivanl", new Integer(2), new Integer(25), new Integer(1002)});
// }
//2:Stmt使用相同的SQL语句,参数值也相同--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, 1002);
// ps.execute();
// }
// return null;
// }
// });
//3:Stmt使用相同的SQL语句,参数值不同--100条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 100; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, i);
// ps.execute();
// }
// return null;
// }
// });
//4:Stmt使用相同的SQL语句,参数值也相同--10000条
// String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
// getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
// public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
// {
// for(int i = 0; i< 10000; i++)
// {
// logger.debug("pre-stmt #"+i);
// ps.setString(1, "ivanl");
// ps.setInt(2, 2);
// ps.setInt(3, 25);
// ps.setInt(4, 1002);
// ps.execute();
// }
// return null;
// }
// });
//5:Stmt使用相同的SQL语句,参数值不同--10000条
String stmtSQL = "insert into jdbc_stmt values(?,?,?,?)";
getJdbcTemplate().execute(stmtSQL,new PreparedStatementCallback(){
public Object doInPreparedStatement(PreparedStatement ps) throws SQLException
{
for(int i = 0; i< 10000; i++)
{
logger.debug("pre-stmt #"+i);
ps.setString(1, "ivanl");
ps.setInt(2, 2);
ps.setInt(3, 25);
ps.setInt(4, i);
ps.execute();
}
return null;
}
});
}
[/code]