DriverManager,管理JDBC驱动的服务类,主要通过它获取Connection数据库链接,常用方法如下:
static synchronized Connection getConnection(String url, String user, String passWord) throws Exception;该方法获得url对应的数据库的连接。Connection常用数据库操作方法:Statement createStatement throws SQLException: 该方法返回一个Statement对象。PReparedStatement prepareStatement(String sql) throws SQLException;该方法返回预编译的Statement对象,即将SQL语句提交到数据库进行预编译。CallableStatement prepareCall(String sql) throws SQLException:该方法返回CallableStatement对象,该对象用于存储过程的调用。上面的三个方法都是返回执行SQL语句的Statement对象,PreparedStatement、CallableStatement的对象是Statement的子类,只有获得Statement之后才可以执行SQL语句。 Connection控制事务的方法:Savepoint setSavepoint(): 创建一个保存点Savepoint setSavepoint(String name):创建一个带有名称的保存点void setTransactionIsolation(int level):设置事务隔离级别void rollback():回滚事务void rollback(Savepoint savepoint):回滚到指定保存点void setAutoCommit(boolean autoCommit): 关闭自动提交,打开事务void commit():提交事务 Statement,用于执行SQL语句的API接口,该对象可以执行DDL、DCL语句,也可以执行DML语句,还可以执行SQL查询语句,当执行查询语句是返回结果集,常用方法如下:ResultSet executeQuery(String sql) throws SQLException:该方法用于执行查询语句,并返回查询结果对应的ResultSet对象,该方法只用于查询语句。int executeUpdate(String sql) throws SQLException:该方法用于执行DML语句,并返回受影响的行数;该方法也可以执行DDL,执行DDL返回0;boolean execute(String sql) throws SQLException:该方法可以执行任何SQL语句,如果执行后第一个结果是ResultSet对象,则返回true;如果执行后第一个结果为受影响的行数或没有任何结果,则返回false;PreparedStatement,预编译的statement对象,PreparedStatement是Statement的子接口,它允许数据库预编译SQL(通常指带参数SQL)语句,以后每次只改变SQL命令参数,避免数据库每次都编译SQL语句,这样性能就比较好。而相对于Statement而言,使用PreparedStatement执行SQL语句时,无需重新传入SQL语句,因为它已经预编译了SQL语句。但是PreparedStatement需要为编译的SQL语句传入参数值,所以它比了如下方法:void setXxx(int index, value)根据该方法传入的参数值的类型不同,需要使用不同的方法。传入的值的类型根据传入的SQL语句参数而定。 ResultSetvoid close() throws SQLException:释放、关闭ResultSet对象boolean absolute(int row):将结果集移动到第几行,如果row是负数,则移动到倒数第几行。如果移动到的记录指针指向一条有效记录,则该方法返回true;void beforeFisrt(): 将ResultSet的记录指针定位到首行之前,这是ResultSet结果集记录指针的初始状态:记录指针的起始位置位于第一行之前。boolean first():将ResultSet的记录指针定位到首行。如果移动后的记录指针指向一条有效记录,则该方法返回true。boolean previous():将ResultSet的记录指针定位到上一行,如果移动后的记录指针指向一条有效记录,则该方法返回true。boolean next():将ResultSet的记录指针定位到下一行。如果移动后的记录指针指向一条有效记录,则返回true。boolean last():将ResultSet的记录指针定位到最后一行。如果移动后的记录指针指向一条有效记录,则返回true。void afterLast():将ResultSet的记录指针定位到最后一行之后。
2、JDBC驱动JDBC驱动是JDBC API接口的具体实现,不同数据库的实现细节不同。驱动类型(四种类型),一般优先使用纯Java的驱动,已获得更好的效率。 3、JDBC操作数据库的一般步骤注册驱动 (只做一次)建立连接(Connection)创建执行SQL的语句(Statement)执行语句处理执行结果(ResultSet)释放资源 4、注册JDBC驱动有三种方式:Class.forName(“com.MySQL.jdbc.Driver”); 推荐这种方式,不会对具体的驱动类产生依赖。DriverManager.registerDriver(com.mysql.jdbc.Driver); 会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。System.setProperty(“jdbc.drivers”, “driver1:driver2”); 虽然不会对具体的驱动类产生依赖;但注册不太方便,所以很少使用。 DriverManager是一个驱动管理器,内部有一个驱动注册表(Map结构),可以向其注册多个JDBC驱动。 5、建立ConnectionConnection conn = DriverManager.getConnection(url, user, password);url格式:JDBC:子协议:子名称//主机名:端口/数据库名?属性名=属性值&…User,password可以用“属性名=属性值”方式告诉数据库;其他参数如:useUnicode=true&characterEncoding=GBK。 6、建立Statement、PreparedStatementStatement是一个SQL执行器,可以用来执行一个静态的SQL语句。Statement st = conn.createStatement();st.executeQuery(sql); PreparedStatement是一个与定义的SQL执行器,一般较Statement有防止SQL注入的功能,还有较好的执行效率。String sql = "select * from table_name where col_name=?";PreparedStatement ps = conn.preparedStatement(sql);ps.setString(1, "col_value");ps.executeQuery(); 在数据库连接没有关闭的情况下,数据库和驱动可以对PreperedStatement进行优化,PreperedStatement对象可以被重用,从而避免频繁编译SQL。 7、处理ResultSetResultSet表示一个查询结果集。ResultSet rs = statement.executeQuery(sql);While(rs.next()){ rs.getString(“col_name”); rs.getInt(“col_name”); //…} 8、释放资源释放资源的顺序是ResultSet, Statement,Connection;Connection在使用完成后,必须关闭,ResultSet, Statement无所谓,只要Connection关闭了,它们也会被自动关闭(但资源不是立即被释放)。Connection的使用原则是尽量晚创建,尽量早的释放。在关闭资源异常的情况下,应该将资源赋null值,以确保资源最大可能的被释放掉。二、JDBC编程步骤进行jdbc编程步骤大致如下:1、加载数据库驱动Class.forName(driverClass)上面的dirverClass就是数据库驱动类所对应的类路径字符串,根据不同数据库厂商提供的驱动也不同。2、通过DriverManager获取数据库的链接DriverManager.getConnection(String url, Stirng user, String pass)当使用DriverManager来获取链接,需要传入三个参数:分别是数据量的url、用户名、密码。3、通过Connection对象创建Statement对象,Connection创建Statement的方法如下三个:createStatement()创建基本的Statement对象。prepareStatement(String sql):根据传入的sql语句创建预编译的Statement对象。prepareCall(String sql):根据传入的sql语句创建CallableStatement对象4、Statement执行SQL语句,Statement有三大方法来执行SQL语句:execute:可以执行任何SQL语句,单比较麻烦executeUpdate:可以执行DML、DDL语句。执行DML返回受影响的SQL语句行数,执行DDL返回0;executeQuery:只能执行查询语句,执行后返回代表查询结果的ResultSet对象。 5、操作结果集,针对ResultSet主要移动指针和获得值next、previous、first、last、beforeFrist、afterLast、absolute等移动指针的方法。getXxx获得移动指针指向行,特定列、索引的值。使用列名作为获取值的参数可读性好、使用索引作为获取参数性能好。
6、关闭数据库连接资源
例子
public class testJdbc { public static void main(String[] args) { Connection con = null; Statement st = null; ResultSet rs = null; try { // 获得MySQL驱动的实例 Class.forName("com.mysql.jdbc.Driver").newInstance(); // 获得连接对象(提供:地址,用户名,密码) con = DriverManager.getConnection("jdbc:mysql://127.0.0.1/Weather","root", "root"); if (!con.isClosed()) System.out.println("Successfully connected "); else System.out.println("failed connected"); //建立一个Statement,数据库对象 st = con.createStatement(); // 运行SQL查询语句 rs = st.executeQuery("select * from Weather.question_type_1;"); // 读取结果集 while (rs.next()) { System.out.println("column1:"+rs.getInt(1)); System.out.println("column2:"+rs.getString(2)); System.out.println("column3:"+rs.getString(3)); System.out.println("column4:"+rs.getString(4)); } // 关闭链接 con.close(); } catch(Exception e) { System.err.println("Exception: " + e.getMessage()); } } }三、 使用PreparedStatement执行SQL语句
使用PreparedStatement的好处在于他可以预编译SQL语句,提高sql的执行效率,并且,在其中可以使用带占位符(?)参数的SQL语句来代替它:insert into student_table values(null,?,?)
实现方式: 创建PreparedStatement对象使用Connection的preparedStatement()方法,该方法传入一个字符串,该SQL字符串可以包含占位符。pstmt = conn.prepareStatement("insert into student_table values(null,?,1)");
示例:
[java] view plain copy print?package com.chen.yuan.jdbc; import java.io.FileInputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.util.Properties; public class PreparedStatementDemo { private String driver; private String url; private String user; private String pass; /** * 初始化属性参数 * * @param paramFile * @throws Exception */ public void initParam(String paramFile) throws Exception { Properties props = new Properties(); props.load(new FileInputStream(paramFile)); this.driver = props.getProperty("driver"); this.url = props.getProperty("url"); this.user = props.getProperty("user"); this.pass = props.getProperty("pass"); // 加载数据库驱动 Class.forName(driver); } /** * 使用PreparedStatement添加数据 * * @throws Exception */ public void insertUsePrepare() throws Exception { long start = System.currentTimeMillis(); Connection conn = null; PreparedStatement pstmt = null; try { conn = DriverManager.getConnection(url, user, pass); pstmt = conn .prepareStatement("insert into student_table values(null,?,1)"); // 向其中插入100条数据 for (int i = 0; i < 100; i++) { pstmt.setString(1, "姓名" + i); pstmt.executeUpdate(); } System.out.println("使用PreparedStatement费时:" + (System.currentTimeMillis() - start)); } catch (Exception e) { e.printStackTrace(); } finally { if (pstmt != null) { pstmt.close(); } if (conn != null) { conn.close(); } } } public static void main(String[] args) throws Exception { PreparedStatementDemo pstmtdemo = new PreparedStatementDemo(); pstmtdemo.initParam("mysql.ini"); pstmtdemo.insertUsePrepare(); } } 使用PreparedStatement除了可以提供sql的执行效率外,还防止SQL注入。我们假设,有如下一段程序,直接使用Statement执行sql,这段程序主要是验证用户名和密码,通过之后,可登陆。
[java] view plain copy print?private boolean validate(String userName, String userPass) { // 执行查询的SQL语句 String sql = "select * from jdbc_test " + "where jdbc_name='" + userName + "' and jdbc_desc='" + userPass + "'"; System.out.println(sql); try{ Connection conn = DriverManager.getConnection(url , user ,pass); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); // 如果查询的ResultSet里有超过一条的记录,则登录成功 if (rs.next()) { return true; } }catch(Exception e) { e.printStackTrace(); } return false; } 如果,我们而已传入userName参数,注入sql语句:[sql] view plain copy print?# 利用sql注入后生成的sql语句 select * from jdbc_test where jdbc_name='' or true or '' and jdbc_desc=''; 看到这条语句我们可以发现,该语句总是可以执行通过的,所以用户可以通过这种sql注入方式侵入一般的系统。那我们现在看一下PreparedStatement如何来处理这种登录呢: [java] view plain copy print?private boolean validate(String userName, String userPass) { try{ Connection conn = DriverManager.getConnection(url , user ,pass); PreparedStatement pstmt = conn.prepareStatement( "select * from jdbc_test where jdbc_name=? and jdbc_desc=?"); pstmt.setString(1, userName); pstmt.setString(2, userPass); ResultSet rs = pstmt.executeQuery()) //如果查询的ResultSet里有超过一条的记录,则登录成功 if (rs.next()) { return true; } } catch(Exception e) { e.printStackTrace(); } return false; } 总体看来,PreparedStatement预编译SQL语句,性能更好; 无需拼接sql语句,编程更简单; PreparedStatement可以防止依赖注入,安全性好。四、 使用CallableStatement调用存储过程
1) 我们首先需要在MySQL或Oracle数据库中建立存储过程。下面以mysql为例:
[sql] view plain copy print?delimiter // create procedure add_pro(a int,b int, out sum int) begin set sum = a+b; end; // 关于如何创建存储过程,请参看相关的书籍。2) jdbc调用存储过程,需要使用CallableStatement,可以使用Connection的prepareCall()方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的sql语句。调用存储过程的格式:{call 过程名(?,?,?.....)},其中?作为存储过程的占位符。例如,下面创建一个调用上述存储过程的CallableStatement对象。
cstmt = conn.prepareCall("{call add_pro(?,?,?)}");
存储过程有传入参数和传出参数,所谓的传入参数就是Java程序必须为这些参数传入值,可以通过CallableStatement的setXxx()方法为之传入值;所谓传出参数就是Java程序可以通过该参数获取存储过程里值,CallableStatement需要调用registerOutParameter()方法来注册该参数。
cstmt.registerOutParameter(3,Types.INTEGER);
示例;
[java] view plain copy print?public class CallableStatementTest { private String driver; private String url; private String user; private String pass; public void initParam(String paramFile)throws Exception { // 使用Properties类来加载属性文件 Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("url"); user = props.getProperty("user"); pass = props.getProperty("pass"); } public void callProcedure()throws Exception { // 加载驱动 Class.forName(driver); try( // 获取数据库连接 Connection conn = DriverManager.getConnection(url , user , pass); // 使用Connection来创建一个CallableStatment对象 CallableStatement cstmt = conn.prepareCall( "{call add_pro(?,?,?)}")) { cstmt.setInt(1, 4); cstmt.setInt(2, 5); // 注册CallableStatement的第三个参数是int类型 cstmt.registerOutParameter(3, Types.INTEGER); // 执行存储过程 cstmt.execute(); // 获取,并输出存储过程传出参数的值。 System.out.println("执行结果是: " + cstmt.getInt(3)); } } public static void main(String[] args) throws Exception { CallableStatementTest ct = new CallableStatementTest(); ct.initParam("mysql.ini"); ct.callProcedure(); } }总结:(节摘自http://www.cnblogs.com/hoojo/archive/2011/06/10/2077643.html)
1、 executeUpdate执行DDL、DML语句
Statement提供了execute、executeUpdate、executeQuery三种方法执行,下面用executeUpdate来执行DDL、DML语句,executeUpdate执行DDL返回值是0,执行了DML是返回影响后的记录条数。
2、 execute执行SQL语句
当我们知道SQL语句是完成修改语句时,我们就知道使用executeUpdate语句来完成操作;如果SQL语句是完成查询操作的时候,我们就使用executeQuery来完成。如果我们不知道SQL语句完成什么操作的时候,就可以使用execute方法来完成。当我们使用Statement对象的execute方法执行SQL语句后返回的是boolean值,这就说明该语句能否返回ResultSet对象。那么,如何判断是否是ResultSet对象?方法如下:getResultSet():获取该Statement执行查询语句返回的ResultSet对象getUpdateCount():获取该Statement执行修改语句影响的行数
3、 PrepareStatement执行SQL语句
对于我们操作数据库的时候,执行某一条SQL语句的时候。只有它的参数不同,而SQL语句相同。我们可以使用占位符来设置我们的参数信息,PrepareStatement中的占位符是?,用?代替参数的位置。insert into table values(?, ‘abc’, ?);占位符仅仅支持PrepareStatement,而Statement不支持占位符。PrepareStatement是预编译SQL语句的,然后将占位符替换成参数。而Statement就不能做到。PrepareStatement对象也有execute、executeUpdate、executeQuery这三个方法,但这三个方法都无需传递参数。只需用PrepareStatement来设置占位符的参数,通过用setXxxx(index, value)来完成设置参数信息即可。PrepareStatement的效率要比Statement的效率高。PrepareStatement设置参数可以不拼接字符串,而Statement设置参数信息的时候需要手动拼接字符串。拼接字符串容易操作程序错误、可读性降低、维护性升高、程序性能下降。而PrepareStatement直接设置参数信息就降低了编程的复杂度。并且它可以放在SQL注入。因为它是通过setXxx方法进行设置参数信息,而Statement是通过拼接字符串,很容易就造成SQL注入。综上所述,PrepareStatement比Statement有以下优点:预编译SQL语句,性能更好无需拼接SQL语句,编程更简单可以防止SQL语句注入,安全性更好
4、 CallableStatement调用存储过程
存储过程的调用可以通过CallableStatement,通过Connection对象的prepareCall方法来创建CallableStatement对象。然后传入存储过程的SQL语句,即可调用存储过程,格式如下:{call proc_name(?, ?, ?)}上面的?是占位符,表示传递的参数。存储过程有传入参数、传出参数。传入参数是程程序必须传入的参数,可以 通过setXxx方法进行设置参数值。而传出参数则需要通过程序进行设置,可以用CallableStatement对象的registerOutParameter方法来注册输出参数,cs.registerOutParameter(3, Types.STRING);设置完毕后,当调用存储过程后要获取输出参数值,可以通过getXxx方法来完成。JDBC是Java操作数据库的技术规范。他实际上定义了一组标准的操作数据库的接口。为了能让Java操作数据库,必须要有实现了JDBC这些接口的类,不同的数据库厂商为了让Java语言能操作自己的数据库,都提供了对JDBC接口的实现--这些实现了JDBC接口的类打成一个jar包,就是我们平时看到的数据库驱动。由于不同的数据库操作数据的机制不一样,因此JDBC的具体实现也就千差万别,但是你作为java程序员,你只和Java JDBC的接口打交到,才不用理会他们怎么实现的!呵呵,现在知道JDBC驱动是怎么回事了。当然,这些类可以自己去写--如果你很牛! 1、JDBCJDBC(Java Data Base Connectivity,java数据库连接),由一些接口和类构成的API。J2SE的一部分,由java.sql,javax.sql包组成。
新闻热点
疑难解答