package com.qingyuan.server;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.Test;
/**
* blog reference: <[http://www.blogjava.net/jiangpingcmt1/archive/2011/11/24/364741.html]>
*
* $闭包的概念$: <[ 一个代码段被用来作为方法的参数]>
*
* 1) <[:理解:]> java中没有直接使用某个方法作为另外一个方法的参数,java使用匿名内部类来模拟这种情况
* 匿名内部类往往是作为内部类<interface定义的>的具体实现
*
* 2) <[:场景:]> 在一些平台类<plateform class> 中有些模板方法,其中某些步骤是调用了内部类<interface定义的>
* 中的某些方法,但是平台类将这些方法的具体实现延迟到了业务类中。业务类调用平台类的模板方法,但是传入
* 匿名内部类的实现做为模板方法的参数
*
* 3) <[:知识点:]> 为什么匿名内部类和局部内部类只能访问final变量 .
* blog reference: <[http://blog.csdn.net/zhaoyw2008/article/details/9565219]>
*
* 4) <[:语法:]> 详解内部类
* blog reference: <[http://www.cnblogs.com/chenssy/p/3388487.html]>
*
* 其实在这个应用程序中我们还看到了如何来引用内部类:引用内部类我们需要指明这个对象的类型:
* OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部
* 类的对象通过.new来创建内部类:
* OuterClass.InnerClass innerClass = outerClass.new InnerClass();
*
* 对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,
* 会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。
*
* 在Java中内部类主要分为: <[ 成员内部类、局部内部类、匿名内部类、静态内部类]>
*/
public class ElegantInnerClass
{
// DBCP,CP30,proxool连接池在spring hibernate中的配置 [DHCP]
// reference <[http://zz563143188.iteye.com/blog/1833057]>
// reference <[http://commons.apache.org/proper/commons-dbcp/configuration.html]>
/*
1、 PreparedStatement接口继承Statement, PreparedStatement 实例包含已编译的 SQL 语句,所以其执行速度要快于 Statement 对象。
2、作为 Statement 的子类,PreparedStatement 继承了 Statement 的所有功能。三种方法
execute、 executeQuery 和 executeUpdate 已被更改以使之不再需要参数
3、在JDBC应用中,如果你已经是稍有水平开发者,你就应该始终以PreparedStatement代替
Statement.也就是说,在任何时候都不要使用Statement.
基于以下的原因:
一.代码的可读性和可维护性.
虽然用PreparedStatement来代替Statement会使代码多出几行,但这样的代码无论从可读性还是可维护性上来说.都比直接用Statement的代码高很多档次:
stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");//stmt是Statement对象实例
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(); //prestmt是 PreparedStatement 对象实例
不用我多说,对于第一种方法.别说其他人去读你的代码,就是你自己过一段时间再去读,都会觉得伤心.
二.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吗?
*/
/* 创建一个Statement
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下3种类型:
1、执行静态SQL语句。通常通过Statement实例实现。
2、执行动态SQL语句。通常通过PreparedStatement实例实现。
3、执行数据库存储过程。通常通过CallableStatement实例实现。
具体的实现方式:
Statement stmt = con.createStatement() ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
CallableStatement cstmt = con.prepareCall("{CALL demoSp(? , ?)}");
*/
// <[http://hzw2312.blog.51cto.com/2590340/748307]>
Connection conn = null;
ResultSet rs = null;
Statement stmt = null;
// 内部接口也是回调接口,只定义抽象方法。
private interface Callback
{
Object doIt(Connection conn) throws SQLException;
}
// 模板方法(抽象)
private Object execute(Callback callback) throws SQLException
{
conn = openConnection();
return callback.doIt(conn);
}
// 业务方法(具体)
public Object sqlQuery(final String sql) throws SQLException
{
//匿名内部类做为模板方法的参数来模拟闭包
return execute (new Callback()
{
public Object doIt(Connection conn) throws SQLException
{
stmt = conn.createStatement();
return stmt.executeQuery(sql);
}
});
}
public Connection openConnection() throws SQLException
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url = "jdbc:oracle:thin:@127.0.0.1:1521:ora11g";
String user = "scott";
String password = "tiger";
return DriverManager.getConnection(url, user, password);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public void closeStatement(Statement stmt) throws SQLException
{
if (stmt != null )
{
stmt.close();
}
}
public void closeConnection(Connection conn) throws SQLException
{
if (conn != null && !conn.isClosed())
{
conn.close();
}
}
public void closeResultSet(ResultSet rs) throws SQLException
{
if (rs != null )
{
rs.close();
}
}
@Test
public void runSql() throws SQLException
{
rs = (ResultSet) sqlQuery(" select t.*, t.rowid from emp t");
while (rs.next())
{
System.out.println(rs.getString("ename"));
}
// 关闭资源:
closeConnection(conn);
closeStatement(stmt);
closeResultSet(rs);
}
}