程序 : 写一个 JDBC 程序, 要求能对数据库信息进行读取: :
一: 最差实战: 从 yuqing 数据库的 pet 表中读取两条信息.:
1. 思路:
要读去数据库的信息,我们必须让我们的程序先与数据库建立连接, 所以
(1). 创建一个Connection 对象,该对象负责去与数据库建立连接,在这里我们用的是Mysql,呢我们就查看 MySql-的JDBC Reference: Mysql的url格式如下:
jdbc:mysql://[host][,failoverhost...][:port]/[database][?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]
看的眼是不是有点花啊,呵呵,我们不需要呢么麻烦: 我们可以这样来:
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/yuqing","root","");
这里解释一下本人为什么把上面写成 127.0.0.1 而不写 localhost, 本人认为这样是一个不错的习惯, 因为在做 WEB 开发的时候如果你的浏览器设置了代理,一定要小心: 要用 127.0.0.1 ,而不要用 localhost ! 因为你使用localhost 的话,访问localhost 将不再是访问本机了.
(2) 取得一个连接后,我们是不是该让这个连接和我们的程序之间架一个桥了 ?
:我们知道了上面有了一个 Connection 对象了,我们查看 API 中Collection 类:
它有一个这样的方法:
createStatement
()
: 范围类型 : Statement
Creates a Statement
object for sending SQL statements to the database.
所以我们就知道这就是我们要架的桥,我们的程序靠它来给我们向数据库发送 SQL 语句了.所以:
Statement stmt = conn.createStatement();
(3).桥也架好了,接下来就要我们通过这个桥发送 SQL 语句了,查看 API 文档Statement 类:
executeQuery
(String sql)
返回类型:ResultSet
Executes the given SQL statement, which returns a single ResultSet
object
我们知道这就是我们要的家伙了:---( 我们这里指的是查询 )
所以:
ResultSet rs= stmt.executeQuery("SELECT * FROM pet");
我们这里只是查询,所以是executeQuery
(String sql)
,要是更新可以用executeUpdate(String sql).但是它的返回类型是 int !
(4). 我们在上面又得到了一个结果集.当然想看看自己的查询结果吧.有什么好的方法呢?这里我们又查看 API 的 ResultSet 接口:
next
()
Moves the cursor down one row from its current position.
呵呵,看到了吧,可以 while( rs.next() ) 让它一直都移动我们的游标,来显示我们的结果.这里我们只选择两条记录所以:
while(rt.next())
{
System.out.printf("%s:%s/n",rt.getString(1),rt.getString(2));
}
(5). OK,搞定了 !
搞定了吗 ? 当然不是,我们在前面建立了Connection 连接,架了桥.这里当然要 close 掉啊 !所以:
rt.close();
stmt.close();
conn.close();
这里,顺序一定不要反啊,想想如果没了连接,去哪架桥去,没了桥,通过什么查询结果去 ?
2. 思路有了,呢就开始 coding 吧 !
package cn.pqcc2000;
import java.sql.*;
public class JdbcDemo
{
public static void main(String args[])throws Exception
{
// Class.forName(---) 是在运行的时候加载 Driver 类,这样我们就不需要在运行的时候 //java –Djdbc.derivers = com.mysql.jdbc.Driver
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/yuqing","root","");
Statement stmt = conn.createStatement();
ResultSet rt= stmt.executeQuery("SELECT * FROM pet");
while(rt.next())
{
System.out.printf("%s:%s/n",rt.getString(1),rt.getString(2));
}
rt.close();
stmt.close();
conn.close();
}
}
哈哈,这样的程序出来是不是自己觉得比较满意啊 ? 但是想想有没有什么问题呢 ?
思考:
1. 如果将来我的程序查询的数据库变了,主机变了,用户名变了,该怎么办 ?
2. 我们的异常这样处理合适吗?如果我们呢的程序在 Statement stmt = conn.createStatement(); 的时候出现异常了,也就是说我们的桥没有架设好,呢么 Result rt == null ,如果我再 rt.close( ), 呢么就会有空指针异常,我们的程序提前退出,我们的 conn.close() 就没有调用 ..所以,我们这里要捕捉异常.并在 close()的时候判断 != null .而且无论如何我们都要 close 掉这些资源.所以应放到 finally中.
有了上面的问题,我们考虑用一个properties 文件来存放我们的资源文件:
JDBC.properties 文件:
jdbc.driver =com.mysql.jdbc.Driver
jdbc.driverType =jdbc:mysql
jdbc.host =127.0.0.1
jdbc.database =yuqing
jdbc.user =root
jdbc.password =
jdbc.sql =SELECT * FROM pet
有了这样的一个文件我们该如何把它读取到我们的程序中呢 ? 还是查看 API
load
(InputStream inStream)
无返回类型
Reads a property list (key and element pairs) from the input stream
getProperty
(String key)
返回类型: String
Searches for the property with the specified key in this property list.
呵呵,这个就是我们要的.
呢么我们就开始修改我们上面的程序:
我们要做的两件事情:
(1).读取properties文件:要先 load(InputStream inStream),然后再逐一getProperty(--).
(2) 处理我们的异常
修改我们的程序:
package cn.pqcc2000;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import java.sql.*;
public class JdbcDemo
{
public static void main(String args[]) throws Exception
{
String KEY_DRIVER = "jdbc.run";
String KEY_DRIVER_TYPE = "jdbc.driverType";
String KEY_HOST = "jdbc.host" ;
String KEY_DATABASE = "jdbc.database" ;
String KEY_USER = "jdbc.user" ;
String KEY_PASSWORD ="jdbc.password" ;
String KEY_SQL = "jdbc.sql" ;
Properties prop = new Properties();
InputStream ips = new FileInputStream("a.properties");
if(ips == null)
{
throw new IllegalArgumentException("file not find");
}
prop.load(ips);
ips.close();
String driverType=prop.getProperty(KEY_DRIVER_TYPE);
String host=prop.getProperty(KEY_HOST);
String database=prop.getProperty(KEY_DATABASE);
String user=prop.getProperty(KEY_USER);
String password=prop.getProperty(KEY_PASSWORD);
String sql=prop.getProperty(KEY_SQL);
String run =prop.getProperty(KEY_RUN);
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try
{
Class.forName(run);
conn = DriverManager.getConnection(driverType+":"+"//"+host+"/" +database,user,password);
stmt = conn.createStatement();
rs= stmt.executeQuery(sql);
while(rs.next())
{
System.out.printf("%s:%s/n",rs.getString(1),rs.getString(2));
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(rs != null)
try{rs.close();}catch(Exception ex1){ex1.printStackTrace();}
if(stmt != null)
try{stmt.close();}catch(Exception ex){ex2.printStackTrace();}
if(conn != null)
try{conn.close();}catch(Exception ex3){ex3.printStackTrace();}
}
}
}
再思考这样代码好吗 ?如果以后我们要写 JDBC 的程序都要这样在每个程序里面加上这么多的 Connection , finally( try , catch ) 吗?想想就让人很不爽,这些重复代码我们不希望每次都重复的出现在我们的代码里面,呢么怎么办呢 ? 做网页的时候我们都知道有模板会有很大的方便,呢么我们是不是也可以尝试用模板方法呢?我们先写一个模板,然后我们需要用到同样的程序的时候,我们就继承"模板",然后我们在模板里面只需要添加一些我们 "个性"的代码就 OK 了.
修改我们的代码:( 阿门,请宽恕 !时间关系,我在这里没有使用Properties文件)
先写一个模板:它在这里给我们做一些通用的方法,具体的"个性"代码我们到它的子类里面有不同实现.
package cn.pqcc2000;
import java.sql.*;
abstract class JdbcDemo_Parent
{
static Statement stmt;
ResultSet rs = null;
public abstract void doExecute(Statement stmt)throws Exception;
public void execute(Statement stmt)
{
Connection conn = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/yuqing", "root", "");
stmt = conn.createStatement(); doExecute(stmt);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(rs != null)
try{rs.close();}catch(Exception ex){}
if(stmt != null)
try{stmt.close();}catch(Exception ex){}
if(conn != null)
try{conn.close();}catch(Exception ex){}
}
}
现在编写我们的主类,这个类要继承"模板"类,并且要重写父类里面doExecute(Statement stmt).开始我们自己"个性"的代码 :
package cn.pqcc2000;
import java.sql.*;
public class JdbcDemo_Child extends JdbcDemo_Parent
{
public static void main(String args[])
{
JdbcDemo_Parent parent = new JdbcDemo_Child();
parent.execute(stmt);
}
public void doExecute(Statement stmt)throws Exception
{
try
{
rs = stmt.executeQuery("SELECT * FROM pet");
while(rs.next())
{
System.out.print(rs.toString());
//System.out.printf("%s:%s/n",rs.getString(1),rs.getString(2));
}
rs.close();
rs = null; // 最好加上这一句话,防止以后再对 rs 进行引用.
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
看看我们的程序是怎么运做的 :
1. 首先new 一个对象,然后调用父类的 exexute( )方法,该方法去创建Connection.
2. execute()然后调用子类的doExecute(Statement stmt).来执行"个性化"代码
3. 继续回到execute(),处理呢些通用的,异常代码吧!
OK 符合要求 !
呵呵,我们的"模板"的作用是不是显而易见的.以后我们在写 JDBC 程序,就可以这样子,继承"模板".然后只写一些类似:
rs = stmt.executeQuery("SELECT * FROM pet"); 这样的语句就可以了呢 ?
呵呵 !时间关系,没有使用 properties.
不过,模板方法使用的是继承,不如将来改成策略模式,这样的话,在一定程度上减少了我们程序的耦合性!像大师说的 :"要多用组合,而不是继承" !
呵呵!
继续努力 ing !