JAVA编程语言和JDBC
正确编写,遵守规范Java程序可以在任何启用中重新编译Java在技术平台上运行。Java编程语言已经完全规定。根据定义,启用Java已知的核心库必须支持技术平台。java.sql包或javax.sql包或者JDBC就是这样一个库,它们可以视为ODBC可移植版本,本身就是一个重要的标准。JAVA编程语言和JDBC一起使用可以为编写数据库应用程序提供正确的可移植解决方案。注:虽然可移植的应用程序和标准数据库界面是重大结果,但不要忘记,历史和竞争有时是无聊的,各种数据库都没有完全标准化。这可能意味着必须根据特定数据库的性能或内部调整(甚至在同一平台上)找到"最低公分母"。无论采用标准SQL,ODBC,JDBC,或者其他解决方案于其他解决方案中。最后需要指出的是,JDBC驱动程序是JAVA类,它实现JDBC驱动程序接口可以是特殊的数据库转换程序(通常是SQL)请求。毫无疑问,驱动程序在这里起着重要的作用。大多数数据库供应商现在提供驱动程序来实现特定的系统JDBC API。这些通常是免费的。也可以获得第三方驱动程序,成本从免费到巨大。
JDBC编程的核心包是java.sql其结构如下图所示:
JDBC编程的步骤
第一:加载驱动程序
与特定数据库相连,JDBC必须加载相应的驱动程序。
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 加载Oracle的驱动程序
Class.forName("oracle.jdbc.driver.OracleDriver");
// 加载Microsoft SQL Server的驱动程序 Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
第二:要将"驱动程序"传递到DriverManager,然后获得"连接"。
DriverManager类的getConnection(String url,String user, String password)该方法用于与数据库建立连接。JDBC使用特殊驱动程序的驱动程序JDBC URL作为一种自我识别方法。
JDBC URL的格式为:jdbc : <子协议名> : <子名称>
子协议(sub-protocol)与JDBC驱动程序可以是相关的odbc,oracle,db2,mysql,microsoft等等,根据实际的JDBC驱动程序厂商而不同。数据库定位器(database locator)是与驱动程序有关的指示器,用于唯一指定应用程序要和哪个数据库进行交互。根据驱动程序的类型,该定位器可能包括主机名,端口和数据库系统名。
try{
String url="jdbc:odbc:myodbc";
Connection con=DriverManager.getConnection(url);
// 或者
Connection con=
DriverManager.getConnection(url,user,password);
}catch(SQLException e){
e.printStackTrace();
}
// 1.Microsoft SQL Server的URL
url="jdbc:Microsoft:sqlserver://192.168.0.1:1433;databasename=mydb";
127.0.0.1 也可以用字符串 "localhost"代替
// 2.Oracle 的URL
url="jdbc:oracle:thin:@192.168.0.1:1521:goudan";
第三:创建语句,Statement ,PreparedStatement,或CallableStatement,并将它们用于更新数据库或执行查询。
Statement 对象用于将 SQL 语句发送到数据库中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL语句的对象:Statement、PreparedStatement( 继承Statement )和 CallableStatement(继承PreparedStatement)。它们都专用于发送特定类型的 SQL 语句: Statement 对象用于执行不带参数的简单 SQL语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement对象用于执行对数据库已存储过程的调用。
第四:查询返回包含有已请求数据的ResultSet,该ResultSet是按类型检索的。
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法(这些get方法可以访问当前行中的不同列)提供了对这些行中数据的访问。
第五:DatabaseMetaData和ResultSetMetaData接口可以用来提供有关数据库或ResultSet的信息。
实例分析
例1:通过ODBC建立连接
? 配置WINDOWS下ODBC详细步骤参考 <<ODBC连接步骤.doc>>
? 代码如下:
import java.sql.*;
public class ODBCTest {
public static void main(String[] args) {
Connection con = null;
try {
// 加载ODBC驱动
(1)Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// 通过驱动管理器(DriverManager)获得连接
(2)con = DriverManager.getConnection("jdbc:odbc:myodbc",
"pubuse","123");
// 如果连接不成功,就会出现异常,不会执行下面这个语句
System.out.println("connect success!");
} catch (Exception e) {// 如果出现异常,会打印堆栈里异常的信息
e.printStackTrace();
} finally {// 用完后,关闭连接,释放资源
try {
if (con != null) // 防止出现内存泄露
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
例2:通过SQLSERVER 提供的驱动程序获得连接
? 下面通过SQLSERVER提供的三个驱动获得连接。三个jar文件的名字分别为:msbase.jar,mssqlserver.jar,msutil.jar 然后设置classpath环境变量指向这三个路径。假如这三个文件放在d:\mssqldriver 目录下,如下图所示:
? 然后在系统环境变量classpath里面设置这三个jar文件,这样的话就可以在任何的dos命令窗口里面使用。
也可以在一个dos窗口里面设置。这样的话是只在该窗口下有效。
? 部分代码如下:
………
try {
// 加载SQLSERVER的驱动程序Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
// 通过驱动来获得一个连接
con = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://localhost:1433;"
+ "databasename=pubs", "sa", "");
System.out.println("connect success!");
} catch (Exception e) {
e.printStackTrace();
}
………
例3:通过ORACLE提供的驱动程序获得连接
? 下面介绍通过ORACLE提供的驱动程序获得连接。只有一个jar文件:classes12.jar 同上设置环境变量classpath 指向该jar文件。
部分代码如下
………
try {
// 加载ORACLE9i的驱动程序
Class.forName("oracle.jdbc.driver.OracleDriver");
// 获得连接 oracle数据库的端口号:1521 数据服务器的名字叫itjob
// 登陆的用户名为system,密码为:system (默认密码为manager)
con = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:itjob",
"system","system");
System.out.println("con ok");
} catch (Exception e) {
e.printStackTrace();
}
………
例4:通过数据源获得连接
使用JDBC API的一个主要好处就是独立于数据库的编程,因为大部分JDBC应用程序都可以被轻易地转换到不同的数据库。然而,仍然有两个主要的内容与特定的数据库有关,即JDBC Driver类和JDBC URL。
随着JDBC API的升级,数据源技术的引入,可以提高数据库访问的灵活性。本质上,DataSource对象表示一个特殊的数据源。除了将数据库和专门的JDBC驱动程序信息封装到一个单独的,标准化的对象中之外,数据源可以作为Connection工厂,并为设置和获取DataSource对象进行成功操作所需要的特定属性提供方法。DataSource对象可能需要的一些标准属性包括:
? databaseName
? serverName
? portNumber
? username
? password
使用数据源的另一个好处就是和安全有关的敏感信息,如用户名,密码甚至数据库服务器只在一处编码,这可以由系统管理员完成。虽然和DataSource对象的交互可以用图形应用程序完成,但真正看到运行的示例是有指导性的。虽然DataSource对象的概念很简单,但为了在Java应用程序中使用,DataSource对象是使用Java名称和目录接口(JNDI)来引用的。
下面首先介绍下JNDI的相关概念。JNDI是个JAVA API,它包括名称和目录服务器的概念,道理和JDBC与数据库进行通讯的概念差不多。如:硬盘通过与磁道和扇区打交道工作,但用户只关心文件名和目录,文件系统管理名称服务,该服务将给定的文件名和硬盘上特定的位置相关联。另一个简单的示例就是Web,多数用户只关心Web站点的名称,如www.5itjob.com,并不关心底层的IP地址。然而,TCP/IP通讯是通过使用IP地址,而不是人类能看懂的名称进行的。两个表示法之间的转换是通过DNS(域名系统,Domain Name System)完成的。虽然JNDI用自己的方式提供了一个丰富和有用的API,我们的需求却简单得多。简短地说,我们需要知道怎样做四件事:
? 创建名称并将其绑定到一个Java对象
? 查询名称以检索Java对象
? 删除一个名称
? 重新绑定名称到一个新的Java对象
首先要先加载数据源的驱动程序。让环境变量classpath指向下面几个jar文件
2,代码如下:
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
import java.sql.*;
import javax.sql.*;
import com.microsoft.jdbcx.sqlserver.SQLServerDataSource;
public class JNDIServer {
// First we define the relevant parameters for this datasource
private String serverName = "192.168.0.1";
private int portNumber = 1433;
private String login = "student";
private String password = "student";
private String databaseName = "mydb";
private String filePath = "jdbc/mydatasource";
public JNDIServer() {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
try {
// 创建初始化上下文环境
Context ctx = new InitialContext(env);
// 如果filePath已经绑定过了,那么先解除绑定
ctx.unbind(filePath);
// 创建SQLServerDataSource
SQLServerDataSource ds = new SQLServerDataSource();
// 设置数据源的参数
ds.setServerName(serverName);
ds.setPortNumber(portNumber);
ds.setDatabaseName(databaseName);
ds.setUser(login);
ds.setPassword(password);
ds.setDescription("JDBC DataSource Connection");
// 绑定 JDBC 数据源
ctx.bind(filePath, ds);
ctx.close();
System.out.println("DataSource Created Success!");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
new JNDIServer();
}
}
运行成功后,会在控制台打印:DataSource Created Success!
同时在运行该类所在的磁盘根目录下生成".bindings"文件,如下图:
数据源创建好之后,下面开始使用数据源。
代码如下:
import java.util.Hashtable;
import javax.naming.*;
import java.sql.*;
import javax.sql.*;
public class UseJNDI {
public static void main(String args[]) {
Connection con = null;
try {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
// 获得数据源对象
DataSource ds =
(DataSource) ctx.lookup("jdbc/mydatasource");
// 通过数据源对象获得一个连接
con = ds.getConnection();
// 如果连接不成功,就会出现异常,不会执行下面这个语句
System.out.println("connect success!");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null)// 用完连接后,要关闭释放
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
下面是删除JNDI的引用的代码:
import java.util.Hashtable;
import javax.naming.*;
import java.sql.*;
import javax.sql.*;
public class DeleteJNDI {
public static void main(String[] args) {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
try {
Context ctx = new InitialContext(env);
ctx.unbind("jdbc/pubs");
ctx.close();
System.out.println("delete succeed!");
} catch (Exception ex) {
System.err.println("ERROR: " + ex.getMessage());
}
}
}
例5:通过连接池获得连接
首先请根据我们在上面创建数据库连接的经验,来思考下列问题:
? 为什么需要连接池?
? 什么是PooledConnection?
? 初始化连接池
? 使用连接池
当使用DriverManager或者DataSource方法来获取数据库连接时,每个对新数据库连接的请求都会导致很大的开销。如果频繁地获取新的连接,将会影响性能问题。这在Web服务器端编程的时候尤为明显。请求一个新的Connection对象会带来大量的开销和很多潜在的错误。为了最小化开销,为什么在我们使用完数据库连接后不是重新使用它们,而是删除它们呢?JDBC设计者在创建接口ConnectionPoolDataSource时使用这种流行的设计模式,这允许您创建数据库连接池,其中的连接在关闭后可以重用,而不是删除。
PooledConnection是一个特殊类型的数据库连接,在关闭时不会被删除,不象常规的Connection对象(当常规的连接不再被使用时,垃圾收集器能删除它们)。相反,PooledConnection被缓存以备将来再次使用,从而可能带来大幅度的性能提升。使用数据库连接池几乎和使用DataSource对象一样。首先,不是创建一个实现DataSource接口的类的实例,而是创建了一个实现了ConnectionPoolDataSource接口的类的实例。可以像以前一样使用JNDI来绑定这个新的数据源到一个名称。要实际使用池化的数据源对象,调用ConnectionPooledDataSource(它接下来会建立数据库连接)上的getPooledConnection()得到一个PooledConnection对象。要创建将使用的Connection对象,调用PooledConnection对象(而不是以前的DriverManager或DataSource对象)上的getConnection().这种方法的一个额外的好处是,因为是自动处理,用ConnectionPool管理一定数量的数据库连接方便多了。如果你的客户机许可限制了能够同时连接到数据库的客户机的数目,这种自动化可能非常重要。
初始化连接池。下面的例子我们将使用SQLServer2000数据库和i-net软件的第三方驱动程序来创建PooledDataSource.所有与数据库相关的代码都包含在初始化或绑定过程中。
首先应该在classpath里面再指向名字为Merlia.jar的jar文件。
2,代码如下:
import com.inet.tds.PDataSource;
import java.util.Hashtable;
import javax.naming.*;
import com.microsoft.jdbcx.sqlserver.SQLServerDataSource;
public class JNDIofPooledDataSourceTest {
public static void main(String[] args) {
String serverName = "192.168.0.1";
String databaseName = "mydb";
String userName = "student";
String password = "student";
// 通过下面的名字可以获得一个池化的连接
String filePath = "jdbcPool/mydatasource";
int portNumber = 1433;
int poolSize = 10; // We want to create a pool with 10 connections.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
try {
Context ctx = new InitialContext(env);
// 创建一个池化的数据源对象
PDataSource ds = new PDataSource();
ds.setServerName(serverName);
ds.setPortNumber(portNumber);
ds.setDatabaseName(databaseName);
ds.setUser(userName);
ds.setPassword(password);
ds.setDescription("i-Net PDataSource");
ds.setMaxPoolSize(poolSize);
// 绑定池化的数据源
ctx.bind(filePath, ds);
ctx.close();
System.out.println("PooledDataSource Created Success!");
} catch (Exception ex) {
System.err.println("ERROR: " + ex.getMessage());
}
}
}
一旦初始化了PooledDataSource,就能够在Java应用程序中使用它来创建数据库连接池。请看下面的例子:
import java.util.Hashtable;
import javax.naming.*;
import java.sql.*;
import javax.sql.*;
import java.io.*;
public class UseJNDIOfPooledDataSource {
public static void main(String[] args) {
Connection con = null;
try {
String filePath = "jdbcPool/mydatasource";
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
// 通过JNDI获得池化的数据源
ConnectionPoolDataSource ds =
(ConnectionPoolDataSource) ctx .lookup(filePath);
// 通过池化的数据源获得池化的连接
PooledConnection pcon = ds.getPooledConnection();
// 通过池化的连接获得连接
con = pcon.getConnection();
// 如果连接不成功,就会出现异常,不会执行下面这个语句
System.out.println("connect success!");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null)// 用完连接后,要关闭释放
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
例6:总结数据库连接的各种方式
下面通过综合的例子来说明各种数据库的连接。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
public class DBCon {
// 通过JDBC-ODBC桥获得连接
public static Connection getOdbcCon(String datasourcename, String name,String password)
throws ClassNotFoundException, SQLException {
String url = "jdbc:odbc:";
Connection con = null;
con = DriverManager.getConnection(url + datasourcename, name, password);
return con;
}
// 通过SQLSERVER的三个驱动,连接SQLSERVER2000数据库
public static Connection getSQLServerCon(String name, String password)
throws ClassNotFoundException, SQLException {
String url = "jdbc:microsoft:sqlserver://127.0.0.1:1433";
Connection con = null;
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
con = DriverManager.getConnection(url, name, password);
return con;
}
// 通过ORACLE的驱动,连接ORACLE数据库
public static Connection getOracleCon(String name, String password)
throws ClassNotFoundException, SQLException {
Connection con = null;
Class.forName("oracle.jdbc.driver.OracleDriver");
// 获得连接 oracle数据库的端口号为:1521 数据服务器的名字叫goudan(作者外号)
String url = "jdbc:oracle:thin:@127.0.0.1:1521:goudan";
con = DriverManager.getConnection(url, name, password);
return con;
}
// 通过数据源获得连接
public static Connection getConnectionFromDataSource(String filePath)
throws javax.naming.NamingException, SQLException {
Connection con = null;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
DataSource ds = (DataSource) ctx.lookup(filePath);
con = ds.getConnection();
return con;
}
// 通过连接池获得连接
public static Connection getConnectionFromPooledDataSource(String filePath)
throws javax.naming.NamingException, SQLException {
Connection con = null;
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
ConnectionPoolDataSource ds = (ConnectionPoolDataSource) ctx
.lookup(filePath);
PooledConnection pc = ds.getPooledConnection();
con = pc.getConnection();
return con;
}
}
内容总结
? JDBC(Java Database Connectivity)是Sun提供的一套数据库编程接口API,由Java语言编写的类、接口组成;通过这些类和接口JAVA可以方便的访问各种数据库中的数据。
? JDBC连接数据库的四种方式
? JDBC-ODBC桥,简单易用,只适用于WINDOW平台,适用于学习JDBC。
? 部分Java驱动程序(native-API partly-Java Driver),少用到。
? 网络驱动程序(net-protocol all-java driver(JDBC Proxy)),应用比较广。
? 纯Java驱动程序(native-protocal all-Java driver),它直接与数据库进行通讯,最好的一种连接。
? JDBC的编程步骤
? 加载驱动程序;
? 建立到数据库的连接对象Connection;
? 创建语句,Statement ,PreparedStatement,
或CallableStatement,并将它们用于更新数据库或执行查询;
? 查询返回包含有已请求数据的ResultSet;
? 通过SqlServer,Oracle的驱动程序连接数据库;
? JDBC数据源,连接池技术的实现原理及其优点
? 数据源技术的引入,可以提高数据库访问的灵活性
? 使用数据源,和安全有关的敏感信息,如用户名,密码甚至数据库服务器地址等信息只在一处编码。
? 使用连接池可以提高连接数据库的效率。
独立实践
1、 写一个SQLSERVER连接池的实现,访问pub数据库。
2、 写一个连接ORACLE数据库的实现,用scott用户登陆,操作emp表
3、 从控制台输入注册信息(用户名,密码,确认密码),写到数据库里面。
4、 从控制台输入用户名和密码,在数据库中并验证其有效性。(提示:需要编写的类有:User, Validation,DbUtil)。
5、 登陆成功后,从控制台输入一个表名,并从控制台打印该表里的数据。
第二十章:高级JDBC
学习目标
? 使用DDL,DML语言对数据库进行基本操作
? 预编译语句
? 使用事务
? 事务的级别控制
? 使用存储过程
? 操作元数据
? 可滚动的和可更新的结果集
? 批处理更新
? 字符大对象CLOB
? 二进制大对象BLOB
? RowSet 新特性
使用DDL,DML语言对数据库进行基本操作。
? 创建表并插入数据及修改数据:
import java.sql.Connection;
import java.sql.Statement;
public class CreateTable {
public static void main(String[] args) {
Connection con = null;
try {
// 通过连接池来获得一个连接
con = DBCon .getConnectionFromPooledDataSource("jdbcPool/mydatasource");
// 创建语句对象
Statement st = con.createStatement();
// 创建表的SQL语句
String sql = "create table student(id int,name char(30),age int)";
// 执行完SQL语句的结果
boolean b = st.execute(sql);
if (b) {
System.out.println("create success");
} else {
System.out.println("create fail");
}
// 插入数据到student表
sql = "insert into student values(1,'andy',47)"
+ "insert into student values(2,'jacky',53)"
+ "insert into student values(3,'周润发',51)"
+ "insert into student values(4,'谢贤',60)";
// 执行完SQL语句的结果
b = st.execute(sql);
if (b) {
System.out.println("insert success");
} else {
System.out.println("create fail");
}
// 更新表数据
sql = "update student set name='刘德华' where id=1";
int rows = st.executeUpdate(sql);
// 如果更新成功,rows肯定是大于1的值
if (rows > 0)
System.out.println("update success");
else
System.out.println("update fail");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
查询数据库里的数据
Statement对象的executeQuery()方法一般用于执行一个select语句,它只返回一个结果集,要想把查询结果最后显示给用户,必须对ResultSet对象进行处理。ResultSet对象包括一个由查询语句返回的一个表,这个表中包含所有的查询结果。对ResultSet对象的处理必须逐行进行。ResultSet对象维持一个指向当前行的指针(类似于Iterator的用法)。最初,这个指针指向第一行之前。ResultSet的next()方法使这个指针移向下一行。因此,第一次使用next()方法将指针指向结果集的第一行,这是可以对第一行的数据进行处理。处理完毕后,使用next()方法,将指针移向下一行,继续处理第二行数据。next()方法的返回值是一个boolean值,若为true,则说明指针成功地移向下一行,可以对该行进行处理。若返回值是false,则说明没有下一行,即结果集已经处理完毕。按从左至右的顺序对各列进行处理可以获得较高的执行效率。ResultSet接口的getXXX()方法可以从某列中获得结果,XXX表示JDBC的数据类型。
请看下例:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class ResultSetTest {
public static void main(String[] args) {
Connection con = null;
try {
con = DBCon
.getConnectionFromPooledDataSource("jdbcPool/mydatasource");
Statement st = con.createStatement();
String query = "select id,name from student";
// 获得一个结果集
ResultSet rs = st.executeQuery(query);
// 获得结果集的元数据(表及相关的信息)
ResultSetMetaData rsmt = rs.getMetaData();
// 得到结果集有几列
int num = rsmt.getColumnCount();
String[] columns = new String[num];
// 列的序号是从1开始的
for (int i = 0; i < num; i++)
columns[i] = rsmt.getColumnName(i + 1);
// 先输出列名
for (int i = 0; i < num; i++)
System.out.print(columns[i] + " ");
// 输出列名之后换行
System.out.println();
// 取出结果
while (rs.next()) {
// 输出每一行的值
for (int i = 1; i <= num; i++) {
String temp = rs.getString(i);
System.out.print(temp + " ");
}
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 用完后要关闭连接,释放资源
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
输出结果为:(Eclipse环境)
预编译语句(PreparedStatement)
Statement对象在每次执行SQL语句时都将该语句传给数据库,在多次执行同一语句时,这样做效率较低。这时可以使用PreparedStatement对象.如果数据库支持预编译,它可以将SQL语句传给数据库作预编译,以后每次执行这个SQL语句时,速度就可以提高很多。如果数据库不支持预编译,则在语句执行时,才将其传给数据库。这对用户来说是透明的。PreparedStatement对象的SQL语句还可以接受参数。在语句中指出需要接受哪些参数,然后进行预编译。在每一次执行时,可以给SQL语句传输不同的参数,这样就大大提高了灵活性。PreparedStatement接口是Statement接口派生的子接口,因此它可以使用Statement接口中的方法。
代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
public class PrepareStatementTest {
public static void main(String[] args) {
Connection con = null;
try {
con = DBCon
.getConnectionFromPooledDataSource("jdbcPool/mydatasource");
// 创建修改表的PrepareStatement SQL语句
String sql = "update student set name=? where id=?";
// 创建预编译语句对象
PreparedStatement st = con.prepareStatement(sql);
String[] names = new String[] { "梁朝伟", "贝壳汗母", "小罗", "霍元甲" };
for (int i = 0; i < names.length; i++) {
st.setString(1, names[i]);
st.setInt(2, i + 1);
st.executeUpdate();
}
st.close();
// 打印执行完SQL语句的结果
Statement stq = con.createStatement();
// 定义一个查询的SQL语句
String query = "select id,name from student";
// 获得一个结果集
ResultSet rs = stq.executeQuery(query);
// 获得结果集的元数据(表及的信息)
ResultSetMetaData rsmt = rs.getMetaData();
// 得到有几列,保存在num变量里
int num = rsmt.getColumnCount();
String[] columns = new String[num];
// 列的序号是从1开始的
for (int i = 0; i < num; i++)
columns[i] = rsmt.getColumnName(i + 1);
// 先输出列名
for (int i = 0; i < num; i++)
System.out.print(columns[i] + " ");
// 输出列名之后换行
System.out.println();
// 取出结果
while (rs.next()) {
// 输出每一行的值
for (int i = 1; i <= num; i++) {
String temp = rs.getString(i);
System.out.print(temp + " ");
}
System.out.println();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (con != null)
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
使用事务
下面介绍如何把一系列语句组织成一个事务?如果事务中所有命令都能正确执行,就可以提交这个事务;否则,如果事务中有一个命令出现错误,回滚这个事务,并返回到提交之前的状态,好像什么也没有发生。把命令组合成事务的主要原因是保证数据库的完整性。对于一个事务而言,要么事务中语句全部得到正确执行,事务就可被提交了,要么它中间出现错误。后一种情况,可以调用rollback()方法,数据库将自动放弃上一次提交事务以来的全部变化。一个数据库连接的缺省模式是autocommit模式,每个SQL命令一执行就会提交给数据库。一旦某个命令已提交,就不能把它回退。可以用Connection接口的getAutocommit()方法,检验数据库的目前自动提交模式设置。用命令con.setAutoCommit(false)方法关闭自动提交模式。用con.commit()命令提交事务。用con.rollback()回滚一个事务。
代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.naming.NamingException;
public class UseTran {
public static void main(String[] args) {
Connection con = null;// 方法里临时变量要手动初始化
PreparedStatement updateAge = null;
String updateString = "update student "
+ "set age = ? where name like ?";
String jndiname = "jdbcPool/mydatasource";
try {
con = DBCon.getConnectionFromPooledDataSource(jndiname);
updateAge = con.prepareStatement(updateString);
int[] age = { 45, 39, 25