JDBC全称是Java Database Connectivity, 即Java数据库连接,它是一种可执行SQL语句的Java API。程序可通过JDBC API连接到关系数据库,并使用结构化查询语言(SQL)来完成对数据库的增删改查等操作。
学习JDBC需要有数据库知识。
JDBC常用接口和类简介
- DriverManager: 用于管理JDBC驱动的服务类,程序中使用该类主要功能是获取Connection对象;
- Connection:代表数据库连接对象,每个Connection代表一个物理连接会话,想要访问数据库,必须获得数据库连接。该方法返回Statement对象;
- Statement: 用于执行SQL语句的工具接口,该对象既可以执行DDL语句,也可以执行DCL语句,也可以用来执行DML语句,还可以执行SQL查询,当执行SQL查询时,返回查询得到的结果集(ResultSet);
- PreparedStatement:预编译的Statement对象。是Statement的子接口,允许数据库预编译SQL语句,因此性能更好;
- ResultSet: 结果集对象。该对象包含访问查询结果的方法。
上方每个类/接口都含有一些方法,可以查相关文档。
JDBC编程步骤
- 加载数据库驱动
- 通过DriverManager获取数据库连接
- 通过Connection对象创建Statement对象
- 使用Statement执行SQL语句
- 操作结果集
- 回收数据库资源(包括ResultSet、Statement和Connection)
public class Main {public static void main(String[] args) throws ClassNotFoundException {//1、加载驱动,使用反射知识Class.forName("com.mysql.jdbc.Driver");//2、使用Connection连接数据库Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select", "root", "123456");//3、创建一个Statement对象Statement stmt = conn.createStatement();//4、执行SQL语句ResultSet = rs = stmt.execute("select * form students");//5、处理数据while(rs.next()) {System.out.println(rs.getInt(1));}}
}
执行SQL语句
Statement提供的三个执行函数:
- execute():可以执行任何SQL语句,但比较麻烦;
- executeUpdate():主要执行DML和DDL语句。执行DML语句返回受影响的行数,执行DDL语句返回0;
- executeQuery():只能执行查询语句,执行后返回ResultSet对象。
使用PreparedStatement(Statement的子接口)执行查询:
如果需要反复执行相似的SQL语句,使用PreparedStatement效率更高。
- 创建PreparedStatement对象需要使用Connection的prepareStatement()方法,该方法需要传入一个SQL字符串,字符串可以包含占位符参数(?);
- PreparedStatement也提供了execute()、executeUpdate()、executeQuery()三个方法,但这三个方法无需参数;
- PreparedStatement提供了一系列的setXxx(int index,Xxx value)方法来为占位符参数赋值,如果不清楚各参数类型,可以使用setObject(),由PreparedStatement负责类型转换。
使用Statement和PreparedStatement的对比:
//Statement执行查询
Statement stmt = conn.createStatement();
for(int i=0;i<100;i++)stmt.executeUpdate("insert int student values(" + "null,'姓名" + i +"',1)");//PreparedStatement执行查询
PreparedStatement pstmt = conn.prepareStatement("insert into student values(null,?,1)");
for(int i=0;i<100;i++){pstmt.setString(1,"姓名"+i);pstmt.executeUpdate();
}
使用PreparedStatement好处:执行效率高;无需拼接字符串;防止SQL注入。
管理结果集
可滚动、可更新的结果集:
以默认方式打开的ResultSet是不可更新的,可以在创建ResultSet或PreparedStatement传入额外的参数来创建可更新的ResultSet:
resultSetType: 控制ResultSet类型,该参数接受如下三个值:
- ResultSet.TPYE_FORWARD_ONLY: 该参数控制记录指针只能向前移动;
- ResultSet.TPYE_SCROLL_INSENSITIVE: 记录指针可以自由移动(可滚动结果集),但底层数据的改变不会影响ResultSet的内容;
- ResultSet.TPYE_SCROLL_SENSITIVE:记录指针可以自由移动(可滚动结果集),而且底层数据的改变会影响ResultSet的内容;
resultSetConcurrency: 控制ResultSet的并发类型,该参数接受两个值:
- ResultSet.CONCUR_READ_ONLY: 该常量指示ResultSet是只读的并发模式;
- ResultSet.CONCUR_UPDATABLE: 该常量指示ResultSet是可更新的并发模式。
使用ResultSetMetaData分析结果集:
执行SQL后可以通过移动指针遍历结果集,但无法获得ResultSet中包含哪些数据列,以及每个数据列的数据类型。可以通过ResultSetMetaData获取关于ResultSet的描述信息。
ResultSet里包含一个getMetaData()方法,该方法返回ResultSet对应的ResultSetMetaData对象。ResultSetMetaData常用的方法如下:
- int getColumnCount():返回该Result的列数量;
- String getColumnName(int column):返回指定索引的列名;
- int getColumnType(int column): 返回指定索引的列类型。
事务处理
事务是由一步或几步数据库操作组成的逻辑单元,这系列操作要么都执行,要么都不执行。
事务的特点:
- 原子性:事务是应用中最小的执行单位,是应用中不可再分的最小逻辑执行体;
- 一致性:事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态;
- 隔离性:各个事务执行互不干扰,任何一个事务的内部操作对其他并发的事务都是隔离的;
- 持续性:指事务一旦提交,对数据所做的任何改变都要记录到永久服务器中。
事务由以下语句组成:
一组DML语句;一条DDL语句;一条DCL语句。DDL和DCL语句最多只有一条,它们会导致事务立即提交。
当事务所包含的全部数据库操作都成功执行后,应该提交事务。显式提交:使用commit;自动提交:执行DDL或DCL语句,或者程序正常退出。
当事务所包含的任何一个操作执行失败后,应该回滚事务。显式回滚:使用rollback; 隐式回滚:系统错误或强行退出。
自动提交和开启事务正好相反,如果开启自动提交就是关闭事务,关闭自动提交就是开启事务。
如果不想关闭整个命令窗口的自动提交,而只是想临时性的开启一下事务,可以用MySQL提供的begin或start transaction两个命令,位于这两个命令后的DML语句不会立即生效,除非显式使用commit提交或使用DDL、DCL语句来隐式提交事务。
此外,MySQL还提供了savepoint设置事务中间点,通过使用事务的中间点可以让事务回滚到指定中间点而不是回滚全部事务。一旦设置了中间点后可以用rollback回滚到中间点。
savepoinnt a; //设置中间点
...
rollback to a; //回滚到中间点
JDBC的事务支持
//关闭自动提交,开启事务
conn.setAutoCommit(false);
//执行任意条DML语句
stmt.executeUpdate(...);
stmt.executeUpdate(...);
stmt.executeUpdate(...);
//提交事务
conn.commit();
//回滚事务
conn.rollback();
//设置中间点
conn.setSavepoint();
conn.setSavepoint(String name);
//回滚到中间点
conn.rollback(Savepoint savepoint);
使用连接池管理链接
数据库连接的建立和关闭是及耗费系统资源的操作每个数据库对象都对应一个物理数据库连接,频繁的打开、关闭连接将造成系统性能低下。
数据库连接池的解决方案是:当应用程序启动时,系统主动建立足够的数据库连接,并将这些连接组成一个连接池。每次应用程序请求数据库连接时,无需重新打开连接,而是从连接池中选择已有的连接使用,使用完后不再关闭数据库连接,而是直接将连接归还给连接池。
数据库连接池是Connection对象的工厂。JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由商用服务器实现,也有一些开源组织提供实现(如DBCP和C3P0)。