




已阅读5页,还剩38页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
为什么要始终使用PreparedStatement代替Statement? 在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替Statement.也就是说,在任何时候都不要使用Statement.基于以下的原因:一.代码的可读性和可维护性.虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次:stmt.executeUpdate(insert into tb_name (col1,col2,col2,col4) values (+var1+,+var2+,+var3+,+var4+);perstmt = con.prepareStatement(insert into tb_name (col1,col2,col2,col4) values (?,?,?,?);perstmt.setString(1,var1);perstmt.setString(2,var2);perstmt.setString(3,var3);perstmt.setString(4,var4);perstmt.executeUpdate();不用我多说,对于第一种方法.别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心.二.PreparedStatement尽最大可能提高性能.每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句有可能被重复调用.所以语句在被DB的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中(相当于一个涵数)就会得到执行.这并不是说只有一个Connection中多次执行的预编译语句被缓存,而是对于整个DB中,只要预编译的语句语法和缓存中匹配.那么在任何时候就可以不需要再次编译而可以直接执行.而statement的语句中,即使是相同一操作,而由于每次操作的数据不同所以使整个语句相匹配的机会极小,几乎不太可能匹配.比如:insert into tb_name (col1,col2) values (11,22);insert into tb_name (col1,col2) values (11,23);即使是相同操作但因为数据内容不一样,所以整个个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次.当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.三.最重要的一点是极大地提高了安全性.即使到目前为止,仍有一些人连基本的恶义SQL语法都不知道.String sql = select * from tb_name where name= +varname+ and passwd=+varpasswd+;如果我们把 or 1 = 1作为varpasswd传入进来.用户名随意,看看会成为什么?select * from tb_name = 随意 and passwd = or 1 = 1;因为1=1肯定成立,所以可以任何通过验证.更有甚者:把;drop table tb_name;作为varpasswd传入进来,则:select * from tb_name = 随意 and passwd = ;drop table tb_name;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行.而如果你使用预编译语句.你传入的任何内容就不会和原来的语句发生任何匹配的关系.(前提是数据库本身支持预编译,但上前可能没有什么服务端数据库不支持编译了,只有少数的桌面数据库,就是直接文件访问的那些)只要全使用预编译语句,你就用不着对传入的数据做任何过虑.而如果使用普通的statement,有可能要对drop,;等做费尽心机的判断和过虑.上面的几个原因,还不足让你在任何时候都使用PreparedStatement吗?以上内容摘自bea论坛,虽然说的有点过,但是PreparedStatement有着让人无法拒绝的优点.虽然PreparedStatement有如此多优于Statement的地方,但在使用它的时候却没有Statement那样方便.对于Statement,我们在写其通用方法的时候只需要提供构造好的sql语句就行,而PreparedStatement则不同,在写它的通用方法时不仅需要sql,还需要不定个数的参数集合.难点就在处理这个参数集合传递上,诸如perstmt.setString(1,var1);perstmt.setInt(1,var2);这样的语句让我们找不到其共同点,我们也就无法找到一个恰当的方式来封装它让其提供简单接口.那么我们就真的束手无策了吗?回答肯定是否定的.因为api中还提供了这样一个设置参数的方法perstmt.setObject(int parameterIndex, Object x, int targetSqlType);,好象是专门为需要写通用程序的朋友设计的.解释下这三个参数的含义:第一个参数为参数序号,从1开始;第二个参数是输入参数值的对象,如果是基本类型,则需要转换成相应的对象,如int型需转换成Integer;第三个参数是数据库的 SQL 类型(定义于 java.sql.Types 中).有了这样的方法存在,我们封装PreparedStatement就好办多了,下面开始将具体代码帖出来,希望跟java爱好者多交流交流.因为写这个程序的时候正在做swt,所以就以这个swt工程为示例,下面给出工程的目录结构: 其中bin为输出目录,lib为项目支持文件所在目录,src为源文件目录.解释下这个工程所用到的包:从上至下com包及其子包下放置swt自动生成代码.common包下放置一些基础类db包下放置数据库连接代码,主要是一些接口跟相应辅助类,为持久层,直接跟数据库打交道db.impl包下放置db包中接口的具体实现类model包下放置实体类(或者叫模型,或者叫域对象,或者叫javabean?),在各层之间传输数据service包下放置业务逻辑接口,为中间层,涉及少许数据库代码service.impl包为service包的具体实现test包下为一些测试代码ui包为swt界面程序所在,为表示层,完全跟数据库代码分离本文需要的代码为:db包,db.impl包,model包,service包,service.impl,ui包首先介绍db包,包含DBHelper.java跟SQLParameter.java两个文件.其中DBHelper.java内容如下:package db;import java.sql.ResultSet;import java.sql.SQLException;import db.impl.DBHelperImpl;/* 封装常用的数据库操作,为应用程序提供更简单易用的接口* * see DBHelperImpl*/public interface DBHelper /* * 数据库更改辅助方法,无返回值,适用于:插入、修改、删除 * * param sql * param params * throws SQLException */ public void executeUpdate(String sql, SQLParameter params) throws SQLException; /* * 数据库查询辅助方法,返回一个集合 * * param sql * param params * return * throws SQLException */ public ResultSet find(String sql, SQLParameter params) throws SQLException; /* * 关闭数据库连接 * * throws SQLException */ public void closeConn() throws SQLException; /* * 关闭ResultSet * * throws SQLException */ public void closeRs() throws SQLException;SQLParameter.javapackage db;/* SQL参数类,用于为PrepareStatement的setObject()方法传递参数*/public class SQLParameter /* * 参数序号,从1开始 */ private int index; /* * 输入参数值的对象,如果是基本类型,则需要转换成相应的对象,如int型需转换成Integer */ private Object value; /* * 数据库的 SQL 类型(定义于 java.sql.Types 中) */ private int targetSqlType; public SQLParameter(int index, Object value, int targetSqlType) this.index = index; this.value = value; this.targetSqlType = targetSqlType; public int getIndex() return index; public void setIndex(int index) this.index = index; public int getTargetSqlType() return targetSqlType; public void setTargetSqlType(int targetSqlType) this.targetSqlType = targetSqlType; public Object getValue() return value; public void setValue(Object value) this.value = value; 接下来为db.impl包,只有一个文件DBHelperImpl.javapackage db.impl;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import db.DBHelper;import db.SQLParameter;public class DBHelperImpl implements DBHelper / private Element element; private Connection conn = null; private ResultSet rs = null; private String driverClassName = com.microsoft.jdbc.sqlserver.SQLServerDriver; private String url = jdbc:microsoft:sqlserver:/localhost:1433;databaseName=test; private String username = sa; private String password = 123456; public DBHelperImpl() try Class.forName(driverClassName); catch (java.lang.ClassNotFoundException e) / TODO: handle exception System.err.println(DBHelperImpl.class + : + e.getMessage(); /* * (non-Javadoc) * * see test.db.DBHelper#executeUpdate(java.lang.String, * test.db.SQLParameter) */ public void executeUpdate(String sql, SQLParameter params) throws SQLException / TODO Auto-generated method stub conn = getConnection(); PreparedStatement preparedStatement = conn.prepareStatement(sql); for (SQLParameter element : params) SQLParameter param = (SQLParameter) element; preparedStatement.setObject(param.getIndex(), param.getValue(), param.getTargetSqlType(); System.out.println(this.getPreparedSQL(sql, params); preparedStatement.executeUpdate(); preparedStatement.close(); conn.close(); /* * (non-Javadoc) * * see test.db.DBHelper#find(java.lang.String, test.db.SQLParameter) */ public ResultSet find(String sql, SQLParameter params) throws SQLException / TODO Auto-generated method stub conn = getConnection(); PreparedStatement preparedStatement = conn.prepareStatement(sql); for (SQLParameter element : params) SQLParameter param = (SQLParameter) element; preparedStatement.setObject(param.getIndex(), param.getValue(), param.getTargetSqlType(); System.out.println(this.getPreparedSQL(sql, params); rs = preparedStatement.executeQuery(); return rs; /* * 获得一个数据库连接 * * return * throws SQLException */ private Connection getConnection() throws SQLException conn = DriverManager.getConnection(url, username, password); return conn; /* * (non-Javadoc) * * see test.db.DBHelper#closeConn() */ public void closeConn() throws SQLException try conn.close(); catch (SQLException e) / TODO: handle exception e.printStackTrace(); throw e; finally conn.close(); /* * (non-Javadoc) * * see test.db.DBHelper#closeRs() */ public void closeRs() throws SQLException try rs.close(); catch (SQLException e) / TODO: handle exception e.printStackTrace(); throw e; finally rs.close(); /* * 获得PreparedStatement向数据库提交的SQL语句 * * param sql * param params * return */ private String getPreparedSQL(String sql, SQLParameter params) int paramNum = 0; / 如果参数集不为空,取得其长度 if (null != params) paramNum = params.length; / 如果没有参数,说明不是动态SQL语句,直接返回原sql if (1 paramNum) return sql; / 如果有参数,则是动态SQL语句,需要构造并返回新sql StringBuffer returnSQL = new StringBuffer(); String subSQL = sql.split(?); / 开始循环替换问号为参数值 for (int i = 0; i params.length) returnSQL.append(subSQLsubSQL.length - 1); return returnSQL.toString(); 接下来是model包,其中一个实体类为TelBox.javapackage model;public class TelBox private Long id; private String username; private String telphone; public Long getId() return id; public void setId(Long id) this.id = id; public String getTelphone() return telphone; public void setTelphone(String telphone) this.telphone = telphone; public String getUsername() return username; public void setUsername(String username) this.username = username; 编程网络 未经作者本人同意,请勿转载文章 送鲜花扔鸡蛋 回复本帖 wanderain 系统分析学习中 等级: 大学一年级 经验: 2656 性别: 男 文章: 452 威望: 5 发送私人消息给作者 查看我的好友的状态 使用铠甲保护该文章 发表时间:2007-06-25 16:55:38 第5层 然后是service包,对应TelBox类的service为TelBoxService.javapackage service;import java.util.List;import model.TelBox;import service.impl.TelBoxServiceImpl;/* see TelBoxServiceImpl*/public interface TelBoxService public void saveOrUpdate(TelBox telBox); public TelBox findById(Long id); public List findAll();其具体实现在service.impl包下,文件名为:TelBoxServiceImpl.javapackage service.impl;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Types;import java.util.LinkedList;import java.util.List;import model.TelBox;import service.TelBoxService;import db.DBHelper;import db.SQLParameter;import db.impl.DBHelperImpl;public class TelBoxServiceImpl implements TelBoxService public TelBox findById(Long id) / TODO Auto-generated method stub String sql = select * from telbox where id = ?; SQLParameter params = new SQLParameter1; params0 = new SQLParameter(1, id, Types.INTEGER); DBHelper dbHelper = new DBHelperImpl(); try ResultSet rs = dbHelper.find(sql, params); if (rs.next() TelBox telBox = new TelBox(); telBox.setId(new Long(rs.getString(id); telBox.setUsername(rs.getString(username); telBox.setTelphone(rs.getString(telphone); return telBox; catch (SQLException e) / TODO: handle exception e.printStackTrace(); return null; return null; public void saveOrUpdate(TelBox telBox) / TODO Auto-generated method stub String sql = insert into telbox(username, telphone) values(?, ?); SQLParameter params = new SQLParameter2; params0 = new SQLParameter(1, telBox.getUsername(), Types.VARCHAR); params1 = new SQLParameter(2, telBox.getTelphone(), Types.VARCHAR); DBHelper dbHelper = new DBHelperImpl(); try dbHelper.executeUpdate(sql, params); catch (SQLException e) / TODO: handle exception e.printStackTrace(); public List findAll() / TODO Auto-generated method stub String sql = select * from telbox; SQLParameter params = new SQLParameter0; DBHelper dbHelper = new DBHelperImpl(); List telBoxList = new LinkedList(); try ResultSet rs = dbHelper.find(sql, params); while (rs.next() TelBox telBox = new TelBox(); telBox.setId(new Long(rs.getString(id); telBox.setUsername(rs.getString(username); telBox.setTelphone(rs.getString(telphone); telBoxList.add(telBox); return telBoxList; catch (SQLException e) / TODO: handle exception e.printStackTrace(); return null; 到此为止,对数据库的操作已完全结束,剩下的就是调用我们的service来完成与用户的交互了,示例代码如下: TelBox telBox = new TelBox(); telBox.setTelphone(68291392); telBox.setUsername(wanderain); TelBoxService telBoxService = new TelBoxServiceImpl(); telBox = telBoxService.saveOrUpdate(telBox);这样,我们就完成了一条数据的添加.在使用jdbc操作数据库中,最常用的操作便是对数据库实现增,删,改,查四种基本的操作,在一般的java操作模式下,常用的是使用一个数据对象(就是和数据库中表列对应的数据结构,只用set和get方法),但是,在写的过程中,使用PreparedStatement时,就会出现,对象的参数之间的对应耦合太强还要写太多的set参数方法,很繁琐。,所以我就为此写了一个封装类,其实很简单,就是使用一个对象数组保存不确定的?参数。具体的看代码: /* * /* * Title: * Description:对数据库实际操作的封装类 * Copyright: Copyright (c) 2004 * Company: * author 陈少坤 qq:29189725 * version 1.0 DBOperator */ import java.sql.*;public class DBOperator private DBConnectionManager db = null; private java.sql.PreparedStatement ps = null; private java.sql.ResultSet rs=null; private Connection con = null; public DBOperator() initialize(); private void initialize() db = DBConnectionManager.getInstance(); con = db.getConnection(idb); /* *所有对数据库操作中需要返回RestsultSet的字符串 for example select * param sql sql字符串 * param params * return public ResultSet select(String sql, Object params) rs = null; try ps = con.prepareStatement(sql); int index = 1; if (params != null) int n = params.length; if (n 2 | n % 2 != 0 | (n/2)!=this.getStrNum(sql,?) throw new IllegalArgumentException( 参数为奇数或者是小于2,或者是参数的个数不一致); for (int i = 0; i params.length; i += 2) paramsi+1=this.pareObjToStr(paramsi+1);/把第二个参数对象转换为字符串类型 if ( ( (String) paramsi).toLowerCase().equals(string) ps.setString(index+, (String) paramsi + 1); if ( ( (String) paramsi).toLowerCase().equals(long) ps.setLong(index+, Long.parseLong( (String) paramsi + 1); if ( ( (String) paramsi).toLowerCase().equals(int) ps.setInt(index+, Integer.parseInt( (String) paramsi + 1); if ( ( (String) paramsi).toLowerCase().equals(date) ps.setString(index+, (String) paramsi + 1); if ( ( (String) paramsi).toLowerCase().equals(float) ps.setFloat(index+, Float.parseFloat(String) paramsi + 1); &nbp; if ( ( (String) paramsi).toLowerCase().equals(double) ps.setDouble(index+, Double.parseDouble(String) paramsi + 1); if ( ( (String) paramsi).toLowerCase().equals(image) ps.setBytes(index+, (byte) paramsi + 1); num = ps.executeUpdate(); catch (NumberFormatException ex) ex.printStackTrace(); catch (SQLException ex) ex.printStackTrace(); return num; /* * 把Object类型对象按照相应的类型进行转换,返回String类型 * param obj * return 返回String类型 */ private String pareObjToStr(Object obj) if(obj=null) return null; if(obj instanceof String) return obj.toString(); if(obj instanceof Integer) return (Integer)obj).toString(); if(obj instanceof Long) return (Long)obj).toString(); if(obj instanceof Float) return (Float)obj).toString(); if(obj instanceof Double) return (Double)obj).toString(); if(obj instanceof java.util.Date) return new java.text.SimpleDateFormat(yyyy-MM-dd HH:mm:ss).format(java.util.Date)obj); return obj.toString(); /* *统计原来的字符串中包含的实际字符串的个数 * param sql 原来的字符串 * param str 其中包含的字符串 * return 原字符从串中包含的字符串的个数 */ private int getStrNum(String sql,String str) int num = 0; int index = sql.indexOf(str); while (index != -1) num+; index=sql.indexOf(str,index+str.length(); return num; /* * 释放数据库连接资源 */ public void freeCon() try if (rs != null) rs.close(); if (ps != null) ps.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 设备检修仓库管理制度
- 设备研发建设管理制度
- 设备设施变更管理制度
- 设计公司会计管理制度
- 设计外委外协管理制度
- 评估财务收款管理制度
- 诊所医疗器具管理制度
- 诊所行业安全管理制度
- 诗词社团工作管理制度
- 财务部水电费管理制度
- 按揭贷款业务合作协议书范本
- 2025年smed快速换模试题及答案
- 2022年11月全国翻译专业资格(水平)英语二级笔译实务试题真题及答案
- 2025年河北省中等职业学校对口升学文化考试语文试卷样卷+
- 现代城市配送中无人配送车的发展趋势分析
- 大学生创业项目案例路演
- 医院感染的器械器材管理
- 安徽省蚌埠市2023-2024学年高一下学期7月期末考试 化学 含解析
- 高中物理选择性必修第二册全册考试高分突破必刷检测卷(基础版)
- 课程《爆破工程》课件绪论 爆破工程发展简史
- 口腔拔牙手术知情同意书
评论
0/150
提交评论