- 简介
JDBC(Java Database Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用序
Java 具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性,是编写数据库应用程序的杰出语言。所需要的只是 Java应用程序与各种不同数据库之间进行对话的方法。
JDBC可以在各种平台上使用Java,如Windows,Mac OS和各种版本的UNIX。
JDBC库包括通常与数据库使用相关的下面提到的每个任务的API。
- 连接数据库。
- 创建SQL或MySQL语句。
- 在数据库中执行SQL或MySQL查询。
- 查看和修改生成的记录。
JDBC API支持用于数据库访问的两层和三层处理模型,但通常,JDBC体系结构由两层组成:
- JDBC API:这提供了应用程序到JDBC管理器连接。
- JDBC驱动程序API:这支持JDBC管理器到驱动程序连接。
JDBC API使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接。
DriverManager: 此类管理数据库驱动程序列表。使用通信子协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。
Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用DriverManager对象来管理这种类型的象。
Connection:该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库的所有通信仅通过连接对象。
Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派生接口还接受参数。
ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为个迭代器,允许我们移动其数据。
SQLException:此类处理数据库应用程序中发生的任何错误
SQL 是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并
删除条目等操作。
Create, Read, Update, and Delete 通常称为CRUD操作。
CREATE DATAbase语句用于创建新的数据库:
SQL> CREATE DATAbase DATAbase_NAME;
DROP DATAbase语句用于删除现有数据库:
SQL> DROP DATAbase DATAbase_NAME;
CREATE TABLE语句用于创建新表。语法是 -
SQL> CREATE TABLE Employees ( id INT NOT NULL, age INT NOT NULL, first VARCHAr(255), last VARCHAr(255), PRIMARY KEY ( id ) );
DROP TABLE语句用于删除现有表。
SQL> DROP TABLE table_name;
INSERT的语法类似于以下内容,其中column1,column2等表示要显示在相应列中的新数据
SQL> INSERT INTO table_name VALUES (column1, column2, ...);
SELECT语句用于从数据库中检索数据。SELECT的语法是 -
SQL> SELECT column_name, column_name, ... FROM table_name WHERe conditions;
WHERe子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
UPDATe语句用于更新数据。
SQL> UPDATE table_name SET column_name = value, column_name = value, ... WHERe conditions;
WHERe子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
DELETE语句用于从表中删除数据。
SQL> DELETE FROM table_name WHERe conditions;
WHERe子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
构建JDBC应用程序涉及以下六个步骤:
- 导入包:需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用**import java.sql.***就足够了。
- 注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
- 打开连接:需要使用**DriverManager.getConnection()**方法创建一个Connection对象,该对象表示与数据库的物理连接。
- 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
- 从结果集中提取数据:需要使用相应的**ResultSet.getXXX()**方法从结果集中检索数据。
- 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。
建立JDBC连接所涉及的编程相当简单。这是简单的四个步骤
- 导入JDBC包:将Java语言的***import***语句添加到Java代码中导入所需的类。
- 注册JDBC驱动程序:此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC请求。
- 数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库。
- 创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连接。
Class.forName();
注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册
try { Class.forName("com.mysql.cj.jdbc.Driver"); }catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
DriverManager.registerDriver()
第二种方法是使用静态DriverManager.registerDriver()方法。
try { Driver myDriver = new com.mysql.cj.jdbc.Driver(); DriverManager.registerDriver( myDriver ); }catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
数据库URL配置
加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。为了方便参考,让我
列出三个重载的DriverManager.getConnection()方法 - - getConnection(String url)
- getConnection(String url,Properties prop)
- getConnection(String url,String user,String password)
创建数据库连接对象
String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; String USER = "username"; String PASS = "password" Connection conn = DriverManager.getConnection(URL, USER, PASS);
完整的连接地址:
版本1:
jdbc:mysql://localhost:3306/数据库名? useSSL=false&useUnicode=true&characterEncoding=UTF-8
版本2:
jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC
使用数据库URL和属性对象
DriverManager.getConnection()方法的第三种形式需要一个数据库URL和一个Properties对象 -
DriverManager.getConnection(String url, Properties info);
import java.util.*; String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; Properties info = new Properties( ); info.put( "user", "username" ); info.put( "password", "password" ); Connection conn = DriverManager.getConnection(URL, info);
关闭数据库连接
为确保连接关闭,您可以在代码中提供一个“finally”块。一个finally块总是执行,不管是否发生异常。
要关闭上面打开的连接,你应该调用close()方法如下 -
conn.close()6.1 JDBC执行SQL语句
一旦获得了连接,我们可以与数据库进行交互。JDBC Statement和PreparedStatement接口定义了使
您能够发送SQL命令并从数据库接收数据的方法和属性。
| 接口 | 推荐使用 |
|---|---|
| 声明 | 用于对数据库进行通用访问。在运行时使用静态SQL语句时很有用。Statement接口不能 |
| 接受参数。 | |
| PreparedStatement的 | 当您计划多次使用SQL语句时使用。PreparedStatement接口在运行时接受 |
| 输入参数。 |
创建语句对象
在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建
一个,如下例所示:
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
**加粗样式**}
catch (SQLException e) {
. . .
}
finally {
. . .
}
创建Statement对象后,您可以使用它来执行一个SQL语句,其中有三个执行方法之一。
- boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
- int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
- ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使用此方法,就像使用SELECT语句样。
关闭Statement对象
就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。
一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭Statement对象。但是,应始终显式关闭Statemen
对象,以确保正确清理。
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
stmt.close();
}
6.3 SQL注入
就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。
String username ="admin"; String password=" 'abc' or 1=1 "; String sql="select * from users where username= '"+username+"' and password="+password;7 PreparedStatement(预状态通道)
该PreparedStatement的接口扩展了Statement接口,它为您提供了一个通用的Statement对象有两
个优点附加功能。
此语句使您可以动态地提供参数。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERe id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
JDBC中的所有参数都由?符号,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。所述的setXXX()方法将值绑定到所述参数,其中XXX代表要绑定到输入参数的值的Java数据类型。如果忘记提供值,将收到一个SQLException。每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。该方法与Java数组索引不同,从0开始。
关闭PreparedStatement对象
就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象。
一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭
PreparedStatement对象。但是,应始终显式关闭PreparedStatement对象,以确保正确清理。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERe id = ?";
pstmt = conn.preparedStatement(SQL);
. . .
}catch (SQLException e) {
. . .
}finally {
pstmt.close();
}
对比statement和PreparedStatement;
(1)statement属于状态通道,PreparedStatement属于预状态通道
(2)预状态通道会先编译sql语句,再去执行,比statement执行效率高
(3)预状态通道支持占位符?,给占位符赋值的时候,位置从1开始
(4)预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理
SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示结果集数据库查询。
ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数据。
如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。
try {
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY);
}catch(Exception ex) {
....
}finally {
....
}
9 JAVA操作两表关系
四种:双向一对一,一对多,多对一,多对多
多表关系处理数据
(1) 数据库通过外键建立两表关系
(2) 实体类通过属性的方式建立两表关系
实体类要求:类名=表名,列名=属性名
-> 一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个执行单元。
10.1 事务概述
数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
事务开始于
- 连接到数据库上,并执行一条DML语句insert、update或delete
- 前一个事务结束后,又输入了另一条DML语句
事务结束于 - 执行commit或rollback语句。
- 执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
- 执行一条DDL语句,例如grant语句,在这种情况下,会自动执行commit。
- 断开与数据库的连接
- 执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句。
10.2 事务的四大特点
(ACID)
- actomicity(原子性)
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
- consistency(一致性)
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
- isolation(隔离性)
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
- durability(持久性)
持久性事务完成之后,它对于系统的影响是永久性的。
10.3 JDBC中事务应用
如果JDBC连接处于自动提交模式,默认情况下,则每个SQL语句在完成后都会提交到数据库。
事务使您能够控制是否和何时更改应用于数据库。它将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,则整个事务将失败。
要启用手动事务支持,而不是JDBC驱动程序默认使用的自动提交模式,请使用Connection对象的setAutoCommit()方法。如果将boolean false传递给setAutoCommit(),则关闭自动提交。
我们可以传递一个布尔值true来重新打开它。
10.4 事务的提交和回滚
完成更改后,我们要提交更改,然后在连接对象上调用commit()方法,如下所示:
conn.commit( );
否则,要使用连接名为conn的数据库回滚更新,请使用以下代码 -
conn.rollback( );
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
String SQL = "INSERT INTO Employees values (106, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
//Submit a malformed SQL statement that breaks
String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Singh')";
stmt.executeUpdate(SQL);
// If there is no error.
conn.commit();
}catch(SQLException se){
// If there is any error.
conn.rollback();
}
10.5 Savepoints
新的JDBC 3.0 Savepoint接口为您提供了额外的事务控制。
设置保存点时,可以在事务中定义逻辑回滚点。如果通过保存点发生错误,则可以使用回滚方法来撤消所有更改或仅保存在保存点之后所做的更改。
Connection对象有两种新的方法来帮助您管理保存点 -
- setSavepoint(String savepointName):定义新的保存点。它还返回一个Savepoint对象。
- releaseSavepoint(Savepoint savepointName):删除保存点。请注意,它需要一个Savepoint对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。
try{
//Assume a valid connection object conn
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
String SQL = "INSERT INTO Employees VALUES (106, 20, 'Rita', 'Tez')";
stmt.executeUpdate(SQL);
String SQL = "INSERTED IN Employees VALUES (107, 22, 'Sita', 'Tez')";
stmt.executeUpdate(SQL);
conn.commit();
}catch(SQLException se){
conn.rollback(savepoint1);
}
1、要取消掉JDBC的自动提交:void setAutoCommit(boolean autoCommit)
2、执行各个SQL语句,加入到批处理之中
3、如果所有语句执行成功,则提交事务 commit();如果出现了错误,则回滚:rollback()
try {
connection.setAutoCommit(false);
add(connection);
// int i = 1/0;
sub(connection);
System.out.println("===============");
connection.commit();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("---------------");
try {
connection.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
以上就是java代码利用jdbc操作数据库的最简单版本,数据库事务通常要借助补捉异常语句
11.JDBC批处理批量处理允许您将相关的SQL语句分组到批处理中,并通过对数据库的一次调用提交它们。
当您一次向数据库发送多个SQL语句时,可以减少连接数据库的开销,从而提高性能。
11.1 Statement批处理
以下是使用语句对象的批处理的典型步骤序列
- 使用**createStatement()**方法创建Statement对象。
- 使用**setAutoCommit()**将auto-commit设置为false 。
- 使用**addBatch()**方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
- 在创建的语句对象上使用**executeBatch()**方法执行所有SQL语句。
- 最后,使用**commit()**方法提交所有更改。
Statement stmt = conn.createStatement(); conn.setAutoCommit(false); //sql1 String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(200,'Zia','Ali', 30)"; stmt.addBatch(SQL); //sql2 String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(201,'Raj','Kumar', 35)"; stmt.addBatch(SQL); //sql3 String SQL = "UPDATE Employees SET age = 35 WHERe id = 100"; stmt.addBatch(SQL); int[] count = stmt.executeBatch(); conn.commit();
11.2 PreparedStatement批处理
- 使用占位符创建SQL语句。
- 使用prepareStatement() 方法创建PrepareStatement对象。
- 使用**setAutoCommit()**将auto-commit设置为false 。
- 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
- 在创建的语句对象上使用**executeBatch()**方法执行所有SQL语句。
- 最后,使用**commit()**方法提交所有更改。
String SQL = "INSERT INTO Employees (id, first, last, age) VALUES(?, ?, ?, ?)"; PreparedStatement pstmt = conn.prepareStatement(SQL); conn.setAutoCommit(false); // Set the variables pstmt.setInt( 1, 400 ); pstmt.setString( 2, "Pappu" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 33 ); // Add it to the batch pstmt.addBatch(); // Set the variables pstmt.setInt( 1, 401 ); pstmt.setString( 2, "Pawan" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 31 ); // Add it to the batch pstmt.addBatch(); //add more batches //Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
12.反射处理结果集
接口:
//查询所有的学生信息 public Listfindallstudent(Class cla);
实现类:
@Override public Listfindallstudent(Class cla) { Connection con = null; PreparedStatement pps = null; ResultSet rs =null; try { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection("jdbc:mysql://localhost:3306/yhp","root", "123456"); List list=new ArrayList(); String sqla = "select * from student"; pps = con.prepareStatement(sqla); rs = pps.executeQuery(); //得到数据库中的所有的列有哪些? ResultSetmetaData metaData = rs.getmetaData();//返回数据库中的相关信息 int count=metaData.getColumnCount();//得到列数 String[] columnnames=new String[count]; for (int i = 0; i < count; i++) { // System.out.println(metaData.getColumnName(i+1));//列的位置从1开始 columnnames[i]=metaData.getColumnName(i+1); } //得到实体类中的所有的方法 Method[] methods =cla.getDeclaredMethods(); while(rs.next()){ Object s=cla.newInstance();//调取无参构造创建对象 for (String columnname : columnnames) { String name="set"+columnname;//setstuid for (Method method : methods) { if(method.getName().equalsIgnoreCase(name)){ method.invoke(s,rs.getObject(columnname));//执行了对应的set方法 break; } } } list.add(s); } System.out.println("执行成功"); return list; } catch (Exception e) { e.printStackTrace(); } finally { try { if (rs != null) { rs.close(); } if (pps != null) { pps.close(); } if (con != null) { con.close(); } } catch (SQLException e) { e.printStackTrace(); } } return null; }



