`
songhongchen
  • 浏览: 122759 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

PreparedStatement与Statement的区别

阅读更多

PreparedStatement jdk的解释是

An object that represents a precompiled SQL statement. 
A SQL statement is precompiled and stored in a PreparedStatement object.


主要特点是:
1、提高了安全性,可以防止SQL注入;
2、调试不方便,看不到sql语句,需要额外使用p6spy等辅助包;
2、预编译语句。
并不是说PreparedStatement在所有的DB上都不会提高效率,PreparedStatement需要服务器端的支持,比如在Oracle上就会有显著效果。而MySQL比较明确地说明了不支持PreparedStatement。至于为什么预编译就会提高效率呢?因为oracle中会将所有的sql语句先编译,叫做“执行计划”,放在oracle内部的一个特定的缓存中,每次遇到相同的sql,就会预先调用缓存中,如果不预编译,每次都用statement,那么每次都要编译,在缓冲中会有很多重复的“执行计划”,影响数据库的效能。
还有一点就是在使用setObject()的时候,记得一定要使用带targetSqlType参数的方法,来提高效率。
以下是mysql驱动包中有关setObject()的源代码

public void setObject(int parameterIndex, Object parameterObj,
			int targetSqlType, int scale) throws SQLException {
		if (parameterObj == null) {
			setNull(parameterIndex, java.sql.Types.OTHER);
		} else {
			try {
				switch (targetSqlType) {
				case Types.BOOLEAN:
					if (parameterObj instanceof Boolean) {
						setBoolean(parameterIndex, ((Boolean) parameterObj)
								.booleanValue());

						break;
					} else if (parameterObj instanceof String) {
						setBoolean(parameterIndex, "true"
								.equalsIgnoreCase((String) parameterObj)
								|| !"0".equalsIgnoreCase((String) parameterObj));

						break;
					} else if (parameterObj instanceof Number) {
						int intValue = ((Number) parameterObj).intValue();

						setBoolean(parameterIndex, intValue != 0);

						break;
					} else {
						throw new SQLException("No conversion from "
								+ parameterObj.getClass().getName()
								+ " to Types.BOOLEAN possible.",
								SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
					}

				case Types.BIT:
				case Types.TINYINT:
				case Types.SMALLINT:
				case Types.INTEGER:
				case Types.BIGINT:
				case Types.REAL:
				case Types.FLOAT:
				case Types.DOUBLE:
				case Types.DECIMAL:
				case Types.NUMERIC:

					setNumericObject(parameterIndex, parameterObj,
							targetSqlType, scale);

					break;

				case Types.CHAR:
				case Types.VARCHAR:
				case Types.LONGVARCHAR:
					if (parameterObj instanceof BigDecimal) {
						setString(
								parameterIndex,
								(StringUtils
										.fixDecimalExponent(StringUtils
												.consistentToString((BigDecimal) parameterObj))));
					} else {
						setString(parameterIndex, parameterObj.toString());
					}

					break;

				case Types.CLOB:

					if (parameterObj instanceof java.sql.Clob) {
						setClob(parameterIndex, (java.sql.Clob) parameterObj);
					} else {
						setString(parameterIndex, parameterObj.toString());
					}

					break;

				case Types.BINARY:
				case Types.VARBINARY:
				case Types.LONGVARBINARY:
				case Types.BLOB:

					if (parameterObj instanceof byte[]) {
						setBytes(parameterIndex, (byte[]) parameterObj);
					} else if (parameterObj instanceof java.sql.Blob) {
						setBlob(parameterIndex, (java.sql.Blob) parameterObj);
					} else {
						setBytes(parameterIndex, StringUtils.getBytes(
								parameterObj.toString(), this.charConverter,
								this.charEncoding, this.connection
										.getServerCharacterEncoding(),
								this.connection.parserKnowsUnicode()));
					}

					break;

				case Types.DATE:
				case Types.TIMESTAMP:

					java.util.Date parameterAsDate;

					if (parameterObj instanceof String) {
						ParsePosition pp = new ParsePosition(0);
						java.text.DateFormat sdf = new java.text.SimpleDateFormat(
								getDateTimePattern((String) parameterObj, false),
								Locale.US);
						parameterAsDate = sdf.parse((String) parameterObj, pp);
					} else {
						parameterAsDate = (java.util.Date) parameterObj;
					}

					switch (targetSqlType) {
					case Types.DATE:

						if (parameterAsDate instanceof java.sql.Date) {
							setDate(parameterIndex,
									(java.sql.Date) parameterAsDate);
						} else {
							setDate(parameterIndex, new java.sql.Date(
									parameterAsDate.getTime()));
						}

						break;

					case Types.TIMESTAMP:

						if (parameterAsDate instanceof java.sql.Timestamp) {
							setTimestamp(parameterIndex,
									(java.sql.Timestamp) parameterAsDate);
						} else {
							setTimestamp(parameterIndex,
									new java.sql.Timestamp(parameterAsDate
											.getTime()));
						}

						break;
					}

					break;

				case Types.TIME:

					if (parameterObj instanceof String) {
						java.text.DateFormat sdf = new java.text.SimpleDateFormat(
								getDateTimePattern((String) parameterObj, true),
								Locale.US);
						setTime(parameterIndex, new java.sql.Time(sdf.parse(
								(String) parameterObj).getTime()));
					} else if (parameterObj instanceof Timestamp) {
						Timestamp xT = (Timestamp) parameterObj;
						setTime(parameterIndex, new java.sql.Time(xT.getTime()));
					} else {
						setTime(parameterIndex, (java.sql.Time) parameterObj);
					}

					break;

				case Types.OTHER:
					setSerializableObject(parameterIndex, parameterObj);

					break;

				default:
					throw new SQLException(Messages
							.getString("PreparedStatement.16"), //$NON-NLS-1$
							SQLError.SQL_STATE_GENERAL_ERROR);
				}
			} catch (Exception ex) {
				if (ex instanceof SQLException) {
					throw (SQLException) ex;
				}

				throw new SQLException(
						Messages.getString("PreparedStatement.17") //$NON-NLS-1$
								+ parameterObj.getClass().toString()
								+ Messages.getString("PreparedStatement.18") //$NON-NLS-1$
								+ ex.getClass().getName()
								+ Messages.getString("PreparedStatement.19") + ex.getMessage(), //$NON-NLS-1$
						SQLError.SQL_STATE_GENERAL_ERROR);
			}
		}
	}



不带targetSqlType参数的setObject()方法

public void setObject(int parameterIndex, Object parameterObj)
			throws SQLException {
		if (parameterObj == null) {
			setNull(parameterIndex, java.sql.Types.OTHER);
		} else {
			if (parameterObj instanceof Byte) {
				setInt(parameterIndex, ((Byte) parameterObj).intValue());
			} else if (parameterObj instanceof String) {
				setString(parameterIndex, (String) parameterObj);
			} else if (parameterObj instanceof BigDecimal) {
				setBigDecimal(parameterIndex, (BigDecimal) parameterObj);
			} else if (parameterObj instanceof Short) {
				setShort(parameterIndex, ((Short) parameterObj).shortValue());
			} else if (parameterObj instanceof Integer) {
				setInt(parameterIndex, ((Integer) parameterObj).intValue());
			} else if (parameterObj instanceof Long) {
				setLong(parameterIndex, ((Long) parameterObj).longValue());
			} else if (parameterObj instanceof Float) {
				setFloat(parameterIndex, ((Float) parameterObj).floatValue());
			} else if (parameterObj instanceof Double) {
				setDouble(parameterIndex, ((Double) parameterObj).doubleValue());
			} else if (parameterObj instanceof byte[]) {
				setBytes(parameterIndex, (byte[]) parameterObj);
			} else if (parameterObj instanceof java.sql.Date) {
				setDate(parameterIndex, (java.sql.Date) parameterObj);
			} else if (parameterObj instanceof Time) {
				setTime(parameterIndex, (Time) parameterObj);
			} else if (parameterObj instanceof Timestamp) {
				setTimestamp(parameterIndex, (Timestamp) parameterObj);
			} else if (parameterObj instanceof Boolean) {
				setBoolean(parameterIndex, ((Boolean) parameterObj)
						.booleanValue());
			} else if (parameterObj instanceof InputStream) {
				setBinaryStream(parameterIndex, (InputStream) parameterObj, -1);
			} else if (parameterObj instanceof java.sql.Blob) {
				setBlob(parameterIndex, (java.sql.Blob) parameterObj);
			} else if (parameterObj instanceof java.sql.Clob) {
				setClob(parameterIndex, (java.sql.Clob) parameterObj);
			} else if (parameterObj instanceof java.util.Date) {
				setTimestamp(parameterIndex, new Timestamp(
						((java.util.Date) parameterObj).getTime()));
			} else if (parameterObj instanceof BigInteger) {
				setString(parameterIndex, parameterObj.toString());
			} else {
				setSerializableObject(parameterIndex, parameterObj);
			}
		}
	}


所以大家不要为了省事,而使用不带targetSqlType参数的setObject()方法。

Statement是PreparedStatement的父接口,
主要特点是:
1、易于调试;
2、不进行预编译操作,减少了进行预编译的开销。单次运行PreparedStatement要比Statement要慢一些
这里有个对比:http://www.onjava.com/lpt/a/1480

 

Table 19-3: OCI driver timings (in milliseconds)

Inserts

Statement

PreparedStatement

1

10

113

1,000

2,804

1,412

 

The important thing to notice about the graph is that it's not until about 65 inserts that the PreparedStatement object outperforms the Statement object. 65 inserts

 

综上:

Statement和PreparedStatement,都有其优缺点,但总体而言,强烈建议使用Statement的同学改为使用PreparedStatement,如果希望调试方便,再加个p6spy等包做辅助,看到的sql语句效果更好。毕竟许多应用中,都要考安全性、大用户量时候的性能问题。像hibernate、toplink这种jpa在使用jdbc的时候,如果数据库端支持,都很统一的使用了PreparedStatement。

如:oracle.toplink.essentials.internal.databaseaccess.DatabasePlatform类。

 

 

顺便再讲一下,程序员写出来的sql语句是最值得去关注的,一条效率差的sql语句,足以毁掉整个应用。

1
1
分享到:
评论
1 楼 metadmin 2009-03-30  
建议使用PreparedStatment。 SQL可以做为类常量定义在类里面,而不是方法里面。

这样,可以在类的常量定义部分,直接看到SQL语句,直接审查、直接修改。而不用到各个方法里面找。

比如:
public class Test {
public static final String SELECT_SQL="select * from tablea";

public Collection getAll() {
      pstmt=conn.prepareStatement( SELECT-SQL );
}
}

------------------
权限管理圈子欢迎您:
http://accessmanager.group.iteye.com/

相关推荐

    java中PreparedStatement和Statement的区别

    Java 中 PreparedStatement 和 Statement 的区别 Java 中的 PreparedStatement 和 Statement 都是用于执行 SQL 语句的接口,但是它们之间存在一些关键的区别。 首先,从数据库执行 SQL 语句的角度来看,使用 ...

    Statement和PreparedStatement之间的区别

    Statement和PreparedStatement之间的区别 Statement和PreparedStatement是JDBC中的两种不同的语句对象,用于执行数据库操作。虽然它们都可以执行SQL语句,但是它们之间存在着很大的区别。 首先, Statement对象...

    34.jdbc中preparedStatement比Statement的好处.avi

    jdbc中preparedStatement比Statement的好处

    PreparedStatement和Statement

    这个项目可能包含了使用`PreparedStatement`和`Statement`的例子,通过分析这些代码,你可以更好地理解两者的应用和区别。 总结,`PreparedStatement`和`Statement`在Java数据库操作中各有优势。在追求性能、安全性...

    Java面试题34.jdbc中preparedStatement比Statement的好处.mp4

    Java面试题34.jdbc中preparedStatement比Statement的好处.mp4

    prepareStatement和Statement的区别

    首先,从创建时的区别开始,Statement 需要通过 Connection 对象的 createStatement() 方法创建,而 PreparedStatement 需要通过 Connection 对象的 prepareStatement() 方法创建,并且需要带有 SQL 语句。...

    PreparedStatement接口

    NULL 博文链接:https://chaoyi.iteye.com/blog/2088080

    statement和prepared区别

    在使用Java语言进行数据库交互时,JDBC(Java Database Connectivity)是实现...总之,理解Statement和PreparedStatement之间的区别,能够帮助我们更好地使用JDBC进行数据库操作,从而编写出更加高效、安全的Java程序。

    关于PreparedStatement插入Date类型值的方法.txt

    `PreparedStatement`是`Statement`接口的子接口,用于预编译SQL语句,并可以重复执行这些预编译过的SQL语句。这不仅能够提高应用程序的性能,还能提高安全性,因为它支持参数化查询,避免了SQL注入的风险。 #### 二...

    jdbc连接各数据库及事务处理

    2. 批量处理:使用`Statement`或`PreparedStatement`的`addBatch()`和`executeBatch()`方法进行批量SQL操作,减少网络通信次数。 3. 数据库连接池:通过连接池管理数据库连接,避免频繁创建和关闭连接,提高系统效率...

    如何获得PreparedStatement最终执行的sql语句

    一种可能的方法是通过日志配置,例如,启用MySQL的`Statement`和`PreparedStatement`日志,这样在执行时会打印出详细的SQL语句。 另外,开发工具如IntelliJ IDEA、Eclipse等,或者数据库管理工具如MySQL Workbench...

    PreparedStatement详细用法

    ### PreparedStatement的详细...综上所述,无论从性能、安全性还是数据库无关性的角度,`PreparedStatement`都是比`Statement`更为优秀的选择,因此,在实际开发中,应尽可能地采用`PreparedStatement`来执行SQL语句。

    connection 和 preparedstatement 的关闭问题

    - **作用**:提供了与数据库交互的基本手段,如创建`Statement`、`PreparedStatement`或`CallableStatement`等对象。 - **生命周期管理**: - **获取连接**:通常通过`DataSource`或直接使用`DriverManager`来获取...

    JDBC基础教程之PreparedStatement.doc

    #### 二、`PreparedStatement`与`Statement`的区别 1. **预编译的SQL语句**: - `PreparedStatement`实例包含已编译的SQL语句,这意味着当创建此类对象时,SQL语句会被解析和编译,而不是在每次执行时都进行解析。...

    练习3:使用PreparedStatement插入宠物信息.zip

    在Java编程中,PreparedStatement是Java SQL API中的一个接口,它是Statement接口的子接口。这个练习主要涉及如何使用PreparedStatement来插入宠物信息到数据库中。PreparedStatement的主要优势在于它的预编译能力和...

    详解Java的JDBC中Statement与PreparedStatement对象

    在Java的JDBC(Java Database Connectivity)中,与数据库交互的核心接口是Statement和PreparedStatement。这两个接口都是用于执行SQL语句的,但它们在特性和效率上有所不同。 Statement接口是最基本的SQL执行方式...

    PreparedStatement 详细用法

    在Java编程语言中,`PreparedStatement`是`java.sql`包中的一个接口,它继承自`Statement`类,并提供了预编译SQL语句的功能。预编译SQL语句的主要优势在于提高了执行效率和安全性。尤其在处理动态查询或频繁执行相同...

    JDBC(用PrepareStatement实现)

    在实际开发中,为了提高效率和安全性,我们通常会使用PreparedStatement接口来代替Statement接口。 1. **PreparedStatement简介** PreparedStatement是Statement的一个子接口,它的主要优势在于预编译。预编译的...

    JDBC中PreparedStatement接口提供的execute、executeQuery和executeUpdate之间的区别及用法

    JDBC 中 PreparedStatement 接口提供的 execute、executeQuery 和 executeUpdate 之间的区别及用法 JDBC 中的 PreparedStatement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。...

Global site tag (gtag.js) - Google Analytics