1、JDBC概述
JDBC是一种可以执行SQL语句并可返回结果的Java API,其全称是Java DataBase Connectivity,也是一套面向对象的应用程序接口API,它由一组用Java编程语言编写的类和接口组成,制定了统一的访问各类关系数据库的标准接口,为各种常用数据库提供了标准接口的实现,通过它可访问各类关系数据库,使开发者能够用纯Java API来编写数据库应用程序。JDBC API中定义了一些Java类,分别用来表示与数据库的连接(Connections)、SQL语句(SQL Statements)、结果集(Result Set)以及其他的数据库对象,使得Java程序能方便地与数据库交互并处理所得的结果。
2、JDBC数据类型
JDBC类型 | Java类型 |
CAHR | String |
VARCHAR | String |
LONGVARCHAR | String |
NUMERIC | java.math.BigDecimal |
DECIMAL | java.math.BigDecimal |
BIT | Boolean |
BOOLEAN | Boolean |
TINYINT | byte |
SMALLINT | short |
INTEGET | int |
BIGINT | long |
REAL | float |
FLOAT | double |
BOUBLE | double |
BINARY | byte[] |
VARBONARY | byte[] |
LONGVARBINARY | byte[] |
DATE | java.sql.Date |
TIME | java.sql.Time |
TIMESTAMP | java.sql.Timestamp |
CLOB | Clob |
BLOB | Blob |
ARRAY | Array |
DISTINCT | mapping of underlying type |
STRUCT | struct |
REF | Ref |
DATALINK | java.net.URL |
JAVA_OBJECT | underlying Java class |
3、JDBC连接数据库
1)加载JDBC驱动程序
通过java.lang.Class类的静态方法forName(String className)实现。
try{ Class.forName("com.mysql.jdbc.Driver"); }catch(ClassNotFoundException e){ System.out.println("找不到驱动程序类"); e.printStackTrace(); }
当成功加载后,会将Driver类的实例注册到DriverManager类中。
2)提供JDBC连接的URL
连接URL定义了连接数据库时的协议、子协议、数据源标识。协议在JDBC中总是以jdbc开始;子协议是连接的驱动程序或是数据库管理系统的名称,例如MYSQL就是mysql;数据源标识就是找出数据库来源的地址和连接端口。
jdbc:mysql://localhost:3306/test?userUnicode=true&characterEncoding=gbk.
useUnicode=true表示使用Unicode字符集,如果参数characterEncoding设置为gb2312或GBK,本参数必须设置为true。
3)创建数据库的连接
要连接数据库,可以向java.sql.DriverManager 请求并获得 Connection对象,该对象就代表一个数据库连接,可以使用DriverManger的getConnection(String url,String userName, String password)方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。
String url = "jdbc:mysql://localhost:3306/test?userUnicode=true&characterEncoding=gbk"; String userName = "root"; String password = "123456"; try{ Connection conn = DriverManager.getConnection(url,userName,password); }catch(SQLException e){ System.out.println("Failed to get connection: "+e.getMessage()); e.printStackTrace(); }
4)创建一个Statement
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例又可以分为以下3种类型:
· 执行静态SQL语句,通常通过Statement实例实现;
· 执行动态SQL语句,通常通过PreparedStatement实例实现;
· 执行数据库存储过程,通常通过CallableStatement实例实现。
Statement stmt = conn.createStatement(); PreparedStatement pstmt = conn.preparedStatement(sql); CallableStatement cstmt = conn.prepareCall("{CALL demoSp(?,?)}");
5)执行SQL语句
Statement接口提供了三种执行SQL语句的方法:executeQuery、executeUpdate和execute,具体事宜哪一个,由SQL语句所产生的内容来决定。
1)ResultSet executeQuery(String sqlString):执行查询数据库的SQL,如SELECT语句,返回一个结果集(ResultSet)对象。
2)int executeUpdate(String sqlString):用于执行INSET、UPDATE或DELETE语句以及SQL DDL(数据定义语言)语句,例如CREATE TABLE和DROP TABLE。INSET、UPDATE或DELETE的效果是修改表中零行或多行中的一列或多列,所以executeUpdate的返回值是一个整数,表示受影响的行数(即更新及数)。对于CREATE TABLE或DROP TABLE等不操作行的语句,executeUpdate的返回值总为零。
3)execute(sqlString):用于执行返回多个结果集、多个更新技术或二者组合的语句。
ResultSet rs = stmt.executeQuery("SELECT * FROM ..."); int rows = stmt.executeUpdate("INSERT INTO ..."); boolean flag = stmt.execute(String sqlString);
6)处理结果
执行的结果可能会出现如下两种情况:
· 执行更新返回的是本次操作影响到的记录数;
· 执行查询返回的结果是一个ResultSet对象。
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些行中数据的访问。
(1)使用结果集(ResultSet)对象的访问方法获取数据。
· next():用于移动到ResultSet中的下一行,使下一行成为当前行;
· first():将光标移动到此ResultSet对象的第一行;
· last():将光标移到到此ResultSet对象的最后一行;
· previous():将光标移动到此ResultSet对象的上一行。
(2)通过字段名或列索引取得数据:
String name = rs.getString("name");
String pass = rs.getString(1);
(3)使用行和光标。ResultSet维护指向当前数据行的光标。每调用一次next()方法,光标向下移动一行,初始化位置为第一行记录之前,因此第一次应先调用next()将光标置于第一行上,使它成为当前行。随着每次调用next(),导致光标向下移动一行,按照从上到下的顺序获得ResultSet行。在ResultSet对象或Statement对象关闭之前,光标一直保持有效。
7)关闭JDBC对象
在操作完成之后,要把所使用的JDBC对象全部关闭,以释放JDBC资源,关闭的顺序是声明顺序的反序。
1)关闭记录集;
2)关闭声明;
3)关闭连接对象。
finally{ //关闭记录集 if (null != rs){ try{ rs.close(); }catch (SQLException e){ e.printStackTrace(); } } //关闭声明 if (null != stmt){ try { stmt.close(); }catch (SQLException e){ e.printStackTrace(); } } //关闭连接对象 if (null != conn){ try{ conn.close(); }catch (SQLException e){ e.printStackTrace(); } } }
4、JDBC事务控制
所谓事务,是指一组原子操作(一组SQL语句的执行)的工作单元。这个工作单元中的所有原子操作在进行期间,与其他事务隔离,免于因数据来源的交相更新而发生混乱,事务中的所有原子操作要么全部执行成功,要么全部失败。
1)设置事务的提交方式为非自动提交:
conn.setAutoCommit(false);
2)将需要添加事务的代码放在try、catch块中:
try{ //需要添加事务的业务代码 ... }catch(SQLException e){ ... }
3)在try块内添加提交操作,表示操作无异常,提交事务:
conn.commit();
4)在catch块内添加回滚事务,表示操作出现异常,撤销事务:
conn.rollback();
5)设置事务提交方式为自动提交:
conn.setAutoCommit(true);
在JDBC处理事务的过程中,也可以设置事务的回滚点,当事务回滚的时候,自动回滚到保存点。
Savepoint savepoint = conn.setSavepoint();
conn.rollback(savepoint);
stmt.releaseSavepoint(savepoint);
注意:如要数据表支持事务,则在MySQL中建立的表类型为InnoDB。
package com.yyq; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; /** * Created by gao on 16-4-12. */ public class Transaction { public static final String Driver = "com.mysql.jdbc.Driver"; public static final String URL = "jdbc:mysql://localhost:3306/test"; public static final String USER_NAME = "root"; public static final String PASSWORD = "123456"; public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt = null; String sql = "INSERT INTO student(name,score,class) values(?,null,null)"; String sql2 = "delete from student where id = 69"; try { Class.forName(Driver); conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD); conn.setAutoCommit(false); pstmt = conn.prepareStatement(sql); pstmt.setString(1,"testing"); System.out.println("第一条语句执行...."); pstmt.executeUpdate(); pstmt = conn.prepareStatement(sql2); System.out.println("第二条语句执行...."); pstmt.executeQuery(); conn.commit(); System.out.println("提交事务"); }catch (ClassNotFoundException e){ System.out.println("找不到驱动程序类"); e.printStackTrace(); }catch (SQLException e){ try{ conn.rollback(); System.out.println("回退事务...."); e.printStackTrace(); }catch (SQLException e1){ e1.printStackTrace(); } }finally { try{ conn.setAutoCommit(true); }catch (SQLException e){ e.printStackTrace(); } if (null != pstmt){ try{ pstmt.close(); }catch (SQLException e){ e.printStackTrace(); } } if (null != conn){ try { conn.close(); }catch (SQLException e){ e.printStackTrace(); } } } } }
5、JDBC批量处理
Statement的execute()等方法一次只能执行一条SQL语句,如果同时有多条SQL语句要执行的话,可以实现addBatch()方法将要执行的SQL语句加入进来,然后执行executeBatch()方法,这样就可以在一次方法调用中执行多条SQL语句,以提高执行效率。但是批处理中执行的语句只能是更新语句(inset、delete、update),否则会抛出异常。
try { conn.setAutoCommit(false); Statement stmt = conn.createStatement(); stmt.addBatch("...."); stmt.addBatch("...."); ..... stmt.executeBatch(); conn.commit(); }catch (SQLException e){ try { conn.rollback(); }catch (SQLException e1){ e1.printStackTrace(); } e.printStackTrace(); }finally { try { conn.setAutoCommit(true); }catch (SQLException e){ e.printStackTrace(); } //关闭资源 }