statement prepareStatement的一点体会?

1、PrepareStatement 是预编译的,对于批量处理(Batch)处理可以大大提高效率,也叫JDBC存储过程

2、使用Statement对象。在对数据库只执行一次性存取的时候,用Statement对象进行处理,PrepareStatement对象的开销比Statement大,对于一次性操作并不会带来额外的好处。

3、statement每次执行sql语句,相关数据库都要执行sql语句的编译,prepareStatement是预编译的,并且支持Batch处理

**如果只执行一次的话,两者没有什么明显的差异,如果sql执行多次,预编译过的sql只需要DBMS运行sql语句,而不必先编译后执行,预编译的sql只需要更改其中变量的值,便可重新执行SQL语句。

4、执行许多SQL语句的JDBC程序产生大量的Statement和PrepareStatement,通常认为prepareStatement对象比Statement更有效,特别是如果带有不同参数的同一SQL语句被多次执行的时候,PrepareStatement对象允许数据库预编译SQL语句,这样在随后的运行中key节省时间并增加代码的可读性。

5、还有一个更好的原因使我们在企业应用程序中更喜欢使用PreparedStatement对象,那就是安全性。传递给PreparedStatement对象的参数可以被强制进行类型转换,使开发人员可以确保在插入或查询数据时与底层的数据库格式匹配。

6、当处理公共Web站点上的用户传来的数据的时候,安全性的问题就变得极为重要。传递给PreparedStatement的字符串参数会自动被驱动器忽略。最简单的情况下,这就意味着当你的程序试着将字符串“D’Angelo”插入到VARCHAR2中时,该语句将不会识别第一个“,”,从而导致悲惨的失败。几乎很少有必要创建你自己的字符串忽略代码。

7、prepareStatement预防绝大多数的SQL注入,SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or ‘1=1’也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令

8、JDBC驱动的最佳化是基于使用的是什么功能. 选择PreparedStatement还是Statement取决于你要怎么使用它们. 对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的.

9、prepareStatement=>JDBC驱动会发送一个网络请求到数据解析和优化这个查询. 而执行时会产生另一个网络请求,而对于Statement, 同一个查询只会产生一次网络到数据库的通讯.

10、使用prepareStatement的Batch批处理功能
直接上例子

connection.setAutoCommit(false);//去掉自动提交事务
PreparedStatement ps = conn.prepareStatement(  
   "INSERT into employees values (?, ?, ?)");  

for (n = 0; n < 100; n++) {  

  ps.setString(name[n]);  
  ps.setLong(id[n]);  
  ps.setInt(salary[n]);  
  ps.addBatch();  
}  
ps.executeBatch();  

使用批量插入的好处: , 当在100次INSERT操作中使用addBatch()方法时, 只有两次网络往返. 1次往返是预储statement, 另一次是执行batch命令. 虽然Batch命令会用到更多的数据库的CPU周期, 但是通过减少网络往返,性能得到提高. 记住, JDBC的性能最大的增进是减少JDBC驱动与数据库之间的网络通讯. 如果没有使用批处理则网络往返101次这样会耗很多时间,自然效率也就一般

**mysql 5.5.28 批量执行的数据最大限度是多少不清楚,但自己试了1w,2w,3w 都没问题,记得在url 后面添加:rewriteBatchedStatements=true 表示批量插入,如果不添加的话即使使用addbatch() ,executeBatch() 在后台入库的地方还是不会一次请求入库而是多次请求入库。

11、使用更加高效的getter方法(字段索引)
JDBC提供多种方法从ResultSet中取得数据, 像getInt(), getString(), 和getObject()等等. 而getObject()方法是最泛化了的, 提供了最差的性能。 这是因为JDBC驱动必须对要取得的值的类型作额外的处理以映射为特定的对象. 所以就对特定的数据类型使用相应的方法.
要更进一步的改善性能, 应在取得数据时提供字段的索引号, 例如, getString(1), getLong(2), 和getInt(3)等来替代字段名. 如果没有指定字段索引号, 网络交通不会受影响, 但会使转换和查找的成本增加. 例如, 假设你使用getString(“foo”) … JDBC驱动可能会将字段名转为大写(如果需要), 并且在到字段名列表中逐个比较来找到”foo”字段. 如果可以, 直接使用字段##索引##, 将为你节省大量的处理时间.

例如, 假设你有一个100行15列的ResultSet, 字段名不包含在其中. 你感兴趣的是三个字段 EMPLOYEENAME (字串型), EMPLOYEENUMBER (长整型), 和SALARY (整型). 如果你指定getString(“EmployeeName”), getLong(“EmployeeNumber”), 和getInt(“Salary”), 查询旱每个字段名必须被转换为metadata中相对应的大小写, 然后才进行查找. 如果你使用getString(1), getLong(2), 和getInt(15). 性能就会有显著改善.

12、获取自动生成的键值
JDBC3.0之前

//插入行  
int rowcount = stmt.executeUpdate (  
   "insert into table1(name) values ('kd')");  
// 现在为新插入的行取得磁盘位置 - rowid  
ResultSet rs = stmt.executeQuery (  
   "select rowid from table1 where name = 'kd'");  

这种取得隐含列的方式有两个主要缺点. 第一, 取得隐含列是在一个独立的查询中, 它要透过网络送到服务器后再执行. 第二, 因为不是主键, 查询条件可能不是表中的唯一性ID. 在后面一个例子中, 可能返回了多个隐含列的值, 程序无法知道哪个是最后插入的行的值.

JDBC3.0之后

// 插入行并返回键值  
int rowcount = stmt.executeUpdate ("insert into table1 (name) values ('kd')", Statement.RETURN_GENERATED_KEYS);   
// 得到生成的键值
ResultSet rs = stmt.getGeneratedKeys ();  

现在, 程序中包含了一个唯一性ID, 可以用来作为查询条件来快速的存取数据行, 甚至于表中没有主键的情况也可以.

**现在, 程序中包含了一个唯一性ID, 可以用来作为查询条件来快速的存取数据行, 甚至于表中没有主键的情况也可以

13、选择合适的数据类型
接受和发送某些数据可能代价昂贵,当你设计一个schema时,应选择能被最有效地处理的数据类型,例如,整型数就比浮点数活实处理要快一些,浮点数的定义是数据的内部规定的格式,通常是一种压缩格式,数据必须被解压和转换到另外种样式,这样他才能被数据的协议处理

14、获取ResultSet
通常情况下,请不要写那种依赖于结果集行数(ResultSet.getRow())的代码, 因为驱动程序必须获取所有的数据集以便知道查询会返回多少行数据.

15、尽量使用prepareStatement,代码可读性,运行高效性,防止sql注入等足够你有理由选择prepareStatement

16、光标类型有待研究…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值