JDBC 全程是 Java Database Connectivity,是一种用于执行 SQL 语句的 Java API,它由一组用 Java 编写的类和接口组成,属于 Java EE 的一部分。
图:JDBC 处于数据库驱动和应用程序之间,为多种关系型数据库提供统一的访问
JDBC 使用分为 7 步:
0. 导入 JDBC 的驱动程序,在 java project 的 built-in path 中加入 mysql-connector-5.1.8.jar
1. 注册 JDBC 驱动程序,最常使用 Class.forName(“…”)
2. 创建 Connection 对象,依据数据库的 URL,调用 DriverManager.getConnection( ) 方法
3. 创建 Statement 对象,connection.createStatement()
4. 执行 SQL 操作,返回 ResultSet
5. 对 ResultSet 进行处理
6. 清理环境,释放资源
图:本博客使用的 Students 表是这样的。
我被一个小 BUG 折腾了一个小时:mysql 安装在我的虚拟机的 linux里面,我的 java 代码在 windows 的 eclipse 里面。我的步骤 2,创建 connection 部分一直失败。最后终于发现,我的linux 里面的 mysql 不允许远程访问。。。最后通过百度,更改 mysql 配置解决了。
show me the code
Statement
package jdbc_test;
import java.sql.*;
public class mysql_jdbc_test
{
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; // JDBC 驱动名称
static final String DB_URL = "jdbc:mysql://192.168.1.108:3306/EXAMPLE?"; // URL,IP地址:mysql端口/数据库名
static final String USER = "...";
static final String PASSWORD = "...";
public static void main(String[] args)
{
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try
{
Class.forName(JDBC_DRIVER); // 步骤 1
connection = DriverManager.getConnection(DB_URL, USER, PASSWORD); // 步骤 2
statement = connection.createStatement(); // 步骤 3
String sql = "SELECT id, name, age FROM Students";
resultSet = statement.executeQuery(sql); // 步骤 4
while (resultSet.next()) // 步骤 5
{
int id = resultSet.getInt("id");
int age = resultSet.getInt("age");
String name = resultSet.getString("name");
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
System.out.println();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally // 步骤 6
{
try
{
if (resultSet != null)
{
resultSet.close();
resultSet = null;
}
if (statement != null)
{
statement.close();
statement = null;
}
if (connection != null)
{
connection.close();
connection = null;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
PreparedStatement
PreparedStatement 比单纯的 Statement 更好用,也用的更多,前者接口是后者接口的扩展。有利于执行多次使用的 SQL 语句,节省 String sql 的个数,可以灵活指定 SQL 语句中的变量。SQL语句中,用 ’ ? ’ 代表变量,占个位置。然后使用 setInt( ),setString( ) 设置参数。
PreparedStatement 和 Statement 两者相差的“prepared”,从代码层面可以看出来:connection 返回 PreparedStatement 对象的方法需要参数“带?的sql 语句”,connection 返回 Statement 对象的方法不需要参数。
package jdbc_test;
import java.sql.*;
public class PreparedStmt
{
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://192.168.1.108:3306/EXAMPLE";
static final String USER = "...";
static final String PASSWORD = "...";
public static void main(String[] args)
{
Connection connection = null;
PreparedStatement pStatement = null;
ResultSet rSet = null;
try
{
Class.forName(JDBC_DRIVER);
connection = DriverManager.getConnection(DB_URL, USER, PASSWORD);
String sql = "UPDATE Students set age = ? WHERE id = ?";
pStatement = connection.prepareStatement(sql);
pStatement.setInt(1, 20);
pStatement.setInt(2, 1);
sql = "SELECT id, name, age FROM Students";
rSet = pStatement.executeQuery(sql);
while (rSet.next())
{
int id = rSet.getInt("id");
int age = rSet.getInt("age");
String name = rSet.getString("name");
System.out.print("ID: " + id);
System.out.print(", Age: " + age);
System.out.print(", Name: " + name);
System.out.println();
}
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (SQLException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if (rSet != null)
{
rSet.close();
rSet = null;
}
if (pStatement != null)
{
pStatement.close();
pStatement = null;
}
if (connection != null)
{
connection.close();
connection = null;
}
}
catch (Exception e2)
{
e2.printStackTrace();
}
}
}
}
进阶
DML:Database Manipulate Language,数据库操纵语言,就是 update, insert, delete。JDBC 中用 connection.executeUpdate( ) 一个方法统一了三种操纵方式。
CallableStatement:对存储过程进行调用。参数类型有三种:IN, OUT, INOUT。
IN
:setXXX( … )
OUT
:getXXX( … )
INOUT:同时提供输入和输出参数,setXXX( … ) + getXXX( .. )
ResultSet:由查询语句生成,表示数据库查询结果的数据表。ResultSet默认不可更新,仅有一个向前移动的指针,该指针初始位置在第一行之前。如果不默认的话,可以有很多设置,比如:游标指针可以前后移动,结果集是否可以即时更新,是否可以更新。是的注意的是:JDBC 提供了这些接口,但是数据库厂商(MySql,Oracle 等)不一定都去实现。
创建 ResultSet 的参数设置细节,实验楼网站课程
Transaction:运用事物处理。默认情况下,JDBC 连接是在自动提交模式下的。一个 Transaction 把一个SQL 或者多个 SQL 作为一个逻辑单元,保证这个逻辑单元里面的所有 SQL 语句在同一时间共同执行。要么一起成功,要么一起失败。如果失败,则整个事物回滚。好处是:提高程序运行的性能,保持业务流程的完整性,使用分布式业务管理方式。
connection.setAutoCommit(false);
connection.commit( );
connection.rollback(); ( catch 语句里面,出现异常,撤销事务 )
Batch:批处理。把相关的 SQL 语句组合成一个批处理和一个调用数据库提交。当一次发送多个 SQL 语句到数据库,可以减少通信开销。
addBatch( … )
executeBatch( … )
commit( )
批处理和事务代码样例
RowSet:默认是一个可滚动,可更新,可序列化的结果集。RowSet 的离线操作能有效的利用计算机的内存,减轻数据库服务器的负担。数据操作在内存中操作,然后批量提交到数据源,灵活性和性能都得到了很大的提高。RowSet 从 ResultSet 继承,支持断开结果集,支持 JavaBean
DataSource: DriverManager 的代替,在内部通过一个池的机制来复用数据库连接,这样大大的减少了创建数据库连接的次数,提高了系统性能。连接池实现,分布式实现,DataSource 属性可以动态改变