一、安装配置JDBC
1、安装mysql-connector包
sudo apt-cache search all | grep mysql-connect sudo apt-get install libreoffice-mysql-connector
2、如果使用eclipse或其他ide则需要继续配置
二、小试牛刀
1、创建数据库表
create table students(id int not null, age int not null, name varchar(255), primary key(id)); insert into students values(1,19,'Tom'),(2,20,'God'),(5,23,'ZJX'),(9,28,'CX');
2、执行JDBC代码
package cst.zju.syljdbc; import java.sql.*; public class Jdbctest{ public static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; public static final String DB_URL = "jdbc:mysql://localhost/syltest"; public static final String USER = "root"; public static final String PWD = "1987"; public Connection conn = null; public PreparedStatement ps = null; public Jdbctest(){ } public void getData() throws Exception{ this.connectDatabase(); this.method1(); this.method2(); this.method3(); conn.close(); } public void connectDatabase() throws ClassNotFoundException{ try{ Class.forName(JDBC_DRIVER); System.out.println("Connecting to database......"); this.conn = DriverManager.getConnection(DB_URL, USER, PWD); }catch(SQLException e){ e.printStackTrace(); }catch(ClassNotFoundException e){ e.printStackTrace(); }catch(Exception e){ e.printStackTrace(); } } public void method1() throws SQLException{ System.out.println("select * from students "); Statement stmt = this.conn.createStatement(); //执行查询 String sql = "select id, name, age from students"; // StringBuilder sqlsb = new StringBuilder(sql); ResultSet rs = stmt.executeQuery(sql); //得到和处理结果集 while(rs.next()){ int id = rs.getInt(1); // int id = rs.getInt("id"); int age = rs.getInt("age"); String name = rs.getString("name"); System.out.println(id + " " + age + " " + name); } //关闭资源 stmt.close(); } public void method2() throws SQLException{ System.out.println("insert data into students"); String sql = "insert into students values(?,?,?)"; PreparedStatement ps = this.conn.prepareStatement(sql); ps.setInt(1, 20); ps.setInt(2, 40); ps.setString(3, "Hg"); int flag = ps.executeUpdate(); if(flag == 0) System.out.print("failed to insert data"); ps.close(); } public void method3() throws SQLException{ System.out.println("select * from students "); String sql = "select * from students"; PreparedStatement ps = this.conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while(rs.next()){ int id = rs.getInt(1); // int id = rs.getInt("id"); int age = rs.getInt("age"); String name = rs.getString("name"); System.out.println(id + " " + age + " " + name); } ps.close(); } public static void main(String[] args)throws Exception{ Jdbctest jt = new Jdbctest(); jt.getData(); } }
执行结果
/× Connecting to database...... select * from students 1 19 Tom 2 20 God 5 23 ZJX 9 28 CX insert data into students select * from students 1 19 Tom 2 20 God 5 23 ZJX 9 28 CX 20 40 Hg ×/
三、JDBC基础入门
1、JDBC结构
JDBC 全称为Java Database Connectivity,是一种用于执行 SQL 语句的 Java API,它由一组用 Java 编程语言编写的类和接口组成。JDBC 为数据库开发人员提供了一个标准的 API,使他们能够用纯 Java API 来编写数据库应用程序。
JDBC API由三部分组成:
- JDBC驱动程序管理器:JDBC体系结构的支柱,其主要作用是把Java应用程序连接到正确的 JDBC 驱动程序上。
- JDBC驱动程序测试工具包:为JDBC驱动程序的运行提供了一定的可信度,只有通过JDCB驱动测试包的驱动程序才被认为符合JDBC标准的。
- JDBC-ODBC桥:使ODBC驱动程序可被用作JDBC驱动程序。其目标为方便实现访问某些不常见的DBMS(数据库管理系统)。
JDBC既支持数据库访问的两层模型,也支持三层模型。
- 数据库访问的两层模型
- 数据库访问的三层模型
2、JDBC驱动类型
JDBC驱动程序实现了JDBC API中定义的接口,用于与数据库服务器进行交互。JDBC驱动程序可以打开数据库链接,并通过发送SQL或数据库命令,然后在收到结果与JAVA进行交互。
JDBC驱动程序实现因操作系统和java运行的硬件平台不同而不同。主要可分为以下几类:
- JDBC-ODBC桥接ODBC驱动程序,它将JDBC转译为ODBC,然后使用一个ODBC驱动程序与数据库进行通信。
- 本地API用Java来编写的驱动程序:这种类型那个的驱动程序把客户机API上的JDBC调用转换为Orcale、Sybase、Informix、DB2或其他DBMS的调用。
- JDBC 网络纯 Java 驱动程序:这种驱动程序将 JDBC 转换为与 DBMS 无关的网络协议,这是最为灵活的 JDBC 驱动程序。它是一个三层的方法来访问数据库,在 JDBC 客户端使用标准的网络套接字与中间件应用服务器进行通信。然后由中间件应用服务器进入由 DBMS 所需要的的调用格式转换,并转发到数据库服务器。
- 本地协议纯 Java 驱动程序:这种类型的驱动程序将 JDBC 调用直接转换为 DBMS 所使用的专用网络协议。是 Intranet 访问的一个很实用的解决方法。它是直接与供应商的数据库进行通信,通过 socket 连接一个纯粹的基于 Java 的驱动程序。这是可用于数据库的最高性能的驱动程序,并且通常由供应商本身提供。
通常情况下,如果正访问一个类型的数据库,如Orcle、Sybase,首选驱动程序为类型4。如果Java程序同时访问多个类型的数据库,首选类型是3。如果类型3与4都没有提供数据库非常好用,则考虑类型2。
3、JDBC链接数据库
建立一个JDBC连接的编程主要有四个步骤:
(1)导入JDBC驱动:只有拥有了驱动程序才能注册驱动程序完成连接其他步骤。
(2)注册JDBC驱动程序:这一步导致JVM加载所需的驱动程序到内存中,即实现JDBC请求。实现方法有两种:
//1 Class.forName("com.mysql.jdbc.Driver"); //2 Driver driver = new com.mysql.jdb.Driver(); DriverManager.registerDriver(driver);
(3)数据库URL制定:创建格式正确的地址指向要连接的数据库。加载驱动程序就可使用Class.forName(JDBC_DRIVER)连接到数据库,有三种重载方法:
getConnection(String url)
getConnection(String url, Properties prop)
getConnection(String url, String user, String password)
不同类型的数据有不同的url,下表为当前流行的JDBC驱动程序名和数据库URL。
RDBMS | JDBC驱动程序的名称 | URL |
Mysql | com.mysql.jdbc.Driver | jdbc:mysql://hostname/databseName |
Oracle | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@hostname:portNumber:databaseName |
DB2 | com.ibm.db2.jdbc.net.DB2Driver | jdbc:db2:hostname:port Number/databaseName |
Sybase | com.sybase.jdbc.SybDriver | jdbc:sybase:Tds:hostname: port Number/databaseName |
(4)创建连接对象:最后,代码调用DriverManager对象的getConnection()方法来建立实际的数据库连接。主要有三种形式DriverManager.getConnection()方法来创建一个连接对象。getConnection()最常见形式要求传递一个数据库URL,用户名username,密码pwd。
//1 String URL = "jdbc:mysql://localhost/EXAMPLE"; String USER = "username"; String PASS = "password" Connection conn = DriverManager.getConnection(URL, USER, PASS); //2 String URL = "jdbc:mysql://localhost/EXAMPLE?user=root&password=0909"; Connection conn = DriverManager.getConnection(URL); //3 import java.util.*; String URL = "jdbc:mysql://localhost/EXAMPLE"; Properties pro = new Properties( ); pro.put( "user", "root" ); pro.put( "password", "0909" ); Connection conn = DriverManager.getConnection(URL, pro);
四、JDBC接口
JDBC的接口有三种:
Statement,应用场景:当在运时使用静态SQL语句时,使用Statement。(不接受参数)
CallableStatement,应用场景:当要访问数据库中的存储过程时,该对象可以接受运行时输入参数。
PreparedStatement,应用厂家:当计划多次使用SQL语句时,该对象接受在运行时输入参数。
1、Statement
使用Statement接口首先创建一个Statement对象,需使用Connection对象的createStatement()方法进行创建。其方法主要有:
方法 | 说明 |
boolean execute(String SQL) | 如果ResultSet对象可以被检索返回布尔值true,否则返回false。使用这个方法来执行那个SQL DLL语句,或当需要使用真正的动态SQL |
int execueUpdate(String SQL) | 用于执行INSERT、UPDATE或DELETE语句以及SQLDLL(数据定义语言)语句。返回值是一个整数,代表更新行数 |
ResultSet executeQuery(String SQL) | 返回ResultSet对象。用于产生单个结果集的预计,如SELECT语句 |
2、PreparedStatement
PreparedStatement接口扩展了Statement接口,有利于执行多次使用的SQL预计。同时也能实现防注入。具体使用如下面实例代码
//.......... System.out.println("insert data into students"); String sql = "insert into students values(?,?,?)"; PreparedStatement ps = this.conn.prepareStatement(sql); ps.setInt(1, 20); ps.setInt(2, 40); ps.setString(3, "Hg"); int flag = ps.executeUpdate(); if(flag == 0) System.out.print("failed to insert data"); ps.close(); //............
3、CallableStatement
CallableStatement对象为所有的DBMS提供了一种以标准形式调用已存储过程的方法。对已存储过程的调用是CallableStatement对象所包含的内容。参数有三种类型:INT,OUT,INOUT。PreparedStatement对象使用IN参数。CallableStatement则可是全部使用。
(1)创建CallableStatement对象
一般用Connection的prepareCall方法创建
CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}");
其中?占位符为IN、OUT还是INOUT参数,取决于已储存过程getTestData。
2、IN,OUT参数
将IN参数传给 CallableStatement 对象是通过 setXXX 方法完成的。该方法继承自 PreparedStatement。所传入参数的类型决定了所用的setXXX方法(例如,用 setFloat 来传入 float 值等)。
若已存储过程返回OUT参数,则执行CallableStatement对象以前必须先注册每个OUT参数的JDBC类型(考虑某些DBMS要求JDBC类型)。注册JDBC类型是用registerOutParameter方法来完成的。之后getXXX方法取回参数值。registerOutParameter使用的是JDBC类型,而getXXX则将之转换为Java类型。
其他详细部门参考http://www.it165.net/pro/html/201406/15754.html(转),原作者写的很好。
五、JDBC结果集
ResultSet对象默认是不可更新,仅有一个向前移动的指针。因此只能迭代一次,并且只能按从第一行到最后一行的顺序进行。方法可以分为三类:导航方法(用于移动光标)、获取方法(用于查看当前行的光标所指向的列中的数据)、更新方法(用于更新当前行的列中的数据)。
createStatement(int RSType, int RSConcurrency); prepareStatement(String SQL, int RSType, int RSConcurrency); prepareCall(String sql, int RSType, int RSConcurrency);
RSType表示ResultSet对象的类型,RSConcurrency是ResultSet常量,用于指定一个结果集是否为只读或可更新。
如果不指定ResultSet的类型,则将自动获取为TYPE_FORWARD_ONLY。ResultSet的类型表如下所示:
类型 | 描述 |
ResultSet.TYPE_FORWARD_ONLY | 游标只能向前移动的结果集 |
ResultSet.TYPE_SCROLL_INSENSITIVE | 游标可以向前和向后滚动,但不及时更新,就是如果数据库里的数据修改过,但不会在ResultSet中反映出来 |
ResultSet.TYPE_SCROLL_SENSITIVE | 游标可以向前和向后滚动,并及时跟踪数据库的更新,以便更改ResultSet中的数据 |
并发性的ResultSet如果不指定任何并发类型,将自动获取为CONCUR_READ_ONLY(结果为只读),还有一个类型是ResultSet.CONCUR_UPDATABLE(可更新结果集)。
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet接口中光标移动的方法有很多,如beforeFirst()、afterLast()、first()、last()等等
其过去结果的方法主要有两种:
getInt(String columnName)、getInt(int columnIndex) 当然还有获取其他类型数据的对应方法。
数据集更新方法有
方法 | 说明 |
---|---|
public void updateRow() | 通过更新数据库中相应的行更新当前行 |
public void deleteRow() | 从数据库中删除当前行 |
public void refreshRow() | 刷新在结果集的数据,以反映最新变化在数据库中 |
public void cancelRowUpdates() | 取消所做的当前行的任何更新 |
public void insertRow() | 插入一行到数据库中。当光标指向插入行此方法只能被调用 |
示例代码如下:
public void method4() throws Exception{ Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("select * from students"); rs.moveToInsertRow(); rs.updateInt("id", 60); rs.updateInt(2, 30); rs.updateString(3, "Jack"); rs.insertRow(); while(rs.next()){ System.out.println(rs.getInt(1) + " " + rs.getInt(2) + " " + rs.getString(3)); } }
六、JDBC数据类型与事务
1、数据类型部分略
2、JDBC事务
默认情况下,JDBC连接是在自动提交模式下,即每条SQL语句都在其完成时提交到数据库。但有时候我们需要为了提升程序性能或者保持业务流程的完整性,以及使用了分布式事物管理方式,就需要关闭自动提交而选择主动管理和控制事务。关闭自动提交的方法为:
//false表示不自动提交,反之则自动提交 conn.setAutoCommit(false)
关闭自动提交之后就要主动使用提交方法,当然对应还有回滚方法。
conn.commit();
conn.rollback();
七、JDBC处理
1、JDBC的异常处理
JDBC的异常处理类似于Java Exception处理,最常见的异常为java.sql.SQLException。下表为SQLException的方法。
方法 | 描述 |
---|---|
getError() | 获取与异常关联的错误号 |
getMessage() | 获取 JDBC 驱动程序的错误消息由驱动程序处理错误或获取数据库错误号和消息 |
getSQLState() | 获取 XOPEN SQLSTATE 字符串。对于 JDBC 驱动程序的错误,没有有用的信息从该方法返回。对于一个数据库错误,则返回五位 XOPEN SQLSTATE 代码。这种方法可以返回 null |
getNextException() | 获取异常链的下一个Exception 对象 |
printStackTrace(PrintStream s) | 打印此抛出,回溯到指定的打印流 |
printStackTrace(PrintWriter w) | 打印次抛出,其回溯到指定的打印写入 |
2、JDBC批量处理
批量处理即允许将相关的SQL语句组合成一个批处理和一个调用数据库提交。其实质跟事物是一致的。
一次发送多个SQL语句到数据库可以减少通信开销,从而提高性能。不过 JDBC 驱动程序不需要支持此功能。应该使用 DatabaseMetaData.supportsBatchUpdates() 方法来确定目标数据库支持批量更新处理。如果你的 JDBC 驱动程序支持此功能的方法返回 true。
其实例代码如下:
public void method5() throws SQLException{ //创建Statement对象 Statement stmt = this.conn.createStatement(); //关闭自动提交 conn.setAutoCommit(false); String sql = null; sql = "insert into students(id,age,name) values(43,30,'koko')"; //将sql语句添加到批处理中 stmt.addBatch(sql); sql = "insert into students(id,age,name) values(44,31,'jick')"; stmt.addBatch(sql); sql = "insert into students(id,age,name) values(45,32,'lucy')"; stmt.addBatch(sql); //创建整数数组记录更新情况 int[] count = stmt.executeBatch(); //提交更新 conn.commit(); } //用PreparedStatement完成 public void method6() throws SQLException{ String sql = "insert into students(id, age, name) values(?,?,?)"; PreparedStatement pst = this.conn.prepareStatement(sql); conn.setAutoCommit(false); pst.setInt(1, 46); pst.setInt(2, 33); pst.setString(3, "ndk"); pst.addBatch(); pst.setInt(1, 47); pst.setInt(2, 34); pst.setString(3, "qick"); pst.addBatch(); pst.setInt(1, 48); pst.setInt(2, 35); pst.setString(3, "fire"); pst.addBatch(); int[] count = pst.executeBatch(); conn.commit(); }