- JDBC简介
- 操作步骤
- 数据库 URL 制定
- 使用Properties对象
- JDBC工具类示例
- JDBC Statements
- Connection:
- Statements
- PreparedStatement
- CallableStatement
- ResultSet
- 查看结果集
- 数据类型
- 结果集类型
- 结果集并发性
- 事务
- 批处理
JDBC增删改查的通过操作代码示例
JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库。
主要用于执行 SQL 查询,并查看查询的记录。
使用 JDBC 需要先下载驱动。
驱动下载地址
mysql8需要设置时区,有cj目录,mysql5没有
操作步骤前期准备
1、在 mysql 中创建一个库,并创建相应测试表和插入一些测试数据。 2、新建一个 Java 工程,并导入 MySQL 数据库驱动包,将 mysql 驱动拷入项目根目录并右键添加到项目依赖(Add As Library)。
JDBC 操作数据步骤一般分为如下五个步骤:
一、加载数据库驱动类
JDBC 操作数据步骤一般分为如下五个步骤:
二、建立连接(Connection)
Connection connection = DriverManager.getConnection(url,user,password);
三、创建用于向数据库发送 SQL 的 Statement 对象,并发送 sql
Statement statement = connection.createStatement();
四、从结果集的 ResultSet 中取出返回数据。
ResultSet resultSet = statement.excuteQuery(sql);
五、关闭相关资源,并释放内存
*.close()数据库 URL 制定
当加载了驱动程序之后,可以通过 DriverManager.getConnection() 方法建立一个连接。
- getConnection(String url)
- getConnection(String url, Properties prop)
- getConnection(String url, String user, String password)
在这里,每个格式需要一个数据库 URL ,数据库 URL 指向数据库的地址。
下表列出了常用的 JDBC 驱动程序名和数据库URL。
| RDBMS | JDBC 驱动程序名称 | URL 格式 |
|---|---|---|
| MySQL | com.mysql.jdbc.Driver | jdbc:mysql://localhost:3306/databaseName/database?severTimezone=Asia/Shanghai&characterEncoding=utf-8&useSSL=fasle |
| ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@localhost:1521:实例ID |
| 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 |
| sqlserve | om.microsoft.jdbc.sqlserver.SQLServerDriver | jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=databaseName |
getConnection() 最常用的方式是需要你提供一个数据库 URL,用户名和密码:
调用适当的用户名和密码以及 getConnection() 方法来获得一个 Connection 对象,如下所示:
String URL = "jdbc:mysql://localhost/mydb?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8"; String USER = "username"; String PASS = "password" Connection conn = DriverManager.getConnection(URL, USER, PASS);使用Properties对象
Properties 对象可以保存了一组关键数值。它通过调用 getConnection() 方法,将驱动程序属性传递给驱动程序。
在根目录(位置可以任意)新建一个jdbc.properties文件
url=jdbc:mysql://58.42.239.163:3306/jdbc?serverTimezone=Asia/Shanghai&characterEncoding=UTF8&useSSL=false user=star password=Star@123456JDBC工具类示例
public static Connection getConnection() {
Properties properties = new Properties();
try (
FileInputStream fis = new FileInputStream("jdbc.properties")
) {
properties.load(fis);
// properties.load(JDBCUtility01.class.getResourceAsStream("dbc.properties"));
return DriverManager.getConnection(properties.getProperty("url"), properties);
} catch (IOException | SQLException e) {
e.printStackTrace();
return null;
}
}
public static void Close(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void Close(PreparedStatement statement){
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void Close(PreparedStatement statement,Connection connection){
Close(statement);
Close(connection);
}
}
JDBC Statements
JDBC中 Statement,CallableStatement和PreparedStatement接口定义了用于发送SQL命令的方法。创常见的有3中Statement:
| 接口 | 推荐使用 |
|---|---|
| Statement | 用于对数据库进行通用访问,在运行时使用静态SQL语句时很有用。 Statement接口不能接受参数。 |
| PreparedStatement | 当计划要多次使用SQL语句时使用。PreparedStatement接口在运行时接受输入参数。 |
| CallableStatement | 当想要访问数据库存储过程时使用。CallableStatement接口也可以接受运行时输入参数。 |
3中Statement中具有相同的3个方法,用于不同需求的SQL查询,并且返回结果也不一样:
-
boolean execute (String SQL) :
如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQLDDL语句或需要使用真正的动态SQL,可使用于执行创建数据库、创建表的SQL语句等等。
-
int executeUpdate (String SQL):
返回受SQL语句执行影响的行数。使用此方法执行预期会影响多行的SQL语句,例如:INSERT,UPDATE或DELETE语句。
-
ResultSet executeQuery(String SQL):
返回一个ResultSet对象。 当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
-
void close() throws SQLException;
关闭 Statement
Jdbc 程序中的 Connection,它用于代表数据库的连接,Collection 是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过 Connection 对象完成的,这个对象的常用方法: createStatement():创建向数据库发送 sql 的 Statement 对象。 prepareStatement(sql) :创建向数据库发送预编译 sql 的 PrepareSatement 对象。 prepareCall(sql):创建执行存储过程的 callableStatement 对象。 setAutoCommit(boolean autoCommit):设置事务是否自动提交。 commit() :在链接上提交事务。 rollback() :在此链接上回滚事务。Statements
在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建一个Statement对象
执行完毕后需要关闭Statement对象,顺序应该是:先关闭Statement对象,再关闭Connection对象。PreparedStatement
Jdbc 程序中的 Statement 对象用于向数据库发送 SQL 语句, Statement 对象常用方法: executeQuery(String sql) :用于向数据发送查询语句。 executeUpdate(String sql):用于向数据库发送 insert、update 或 delete 语句 execute(String sql):用于向数据库发送任意 sql 语句 addBatch(String sql) :把多条 sql 语句放到一个批处理中。 executeBatch():向数据库发送一批 sql 语句执行。PreparedStatement
是用户利用某些系统没有对输入数据进行充分的检查,从而进行恶意破坏的行为。statement 存在 sql 注入攻击问题,例如登陆用户名采用’ or 1=1 # or 时无论密码是否正确都将登录成功。
SQL 注入的根本原因是 SQL 字符串的原始拼接。它可能会导致数据库被恶意破坏,这是任何开发都需要注意的问题。随着 jdbc 的发展,为防范 SQL 注入,可以采用 PreparedStatement 取代 Statement。
PreparedStatement接口扩展了Statement接口,添加了比Statement对象更好一些优点的功能。此语句可以动态地提供/接受参数。
JDBC中的所有参数都由 ? 符号作为占位符,这被称为参数标记。 在执行SQL语句之前,必须为每个参数(占位符)提供值。
可以使用setXXX()方法将值绑定到参数,其中XXX表示要绑定到输入参数的值的Java数据类型。 如果忘记提供绑定值,则将会抛出一个SQLException。
每个参数标记是它其顺序位置引用。第一个标记表示位置1,下一个位置2等等。 该方法与Java数组索引不同(它不从0开始)。
PreperedStatement 是 Statement 的子类,它的实例对象可以通过调用 connection.preparedStatement() 方法获得,相对于 Statement 对象而言: PreperedStatement 可以避免 SQL 注入的问题。 Statement 会使数据库频繁编译 SQL,可能造成数据库缓冲区溢出。PreparedStatement 可对 SQL 进行预编译,从而提高数据库的执行效率。 并且 PreperedStatement 对于 SQL 中的参数,允许使用占位符的形式进行替换,简化 SQL 语句的编写。CallableStatement
CallableStatement 对象被用来执行调用数据库存储过程的 。
三种类型的参数有:IN,OUT 和 INOUT。
PreparedStatement 对象只使用 IN 参数。CallableStatement 对象可以使用所有的三个参数。
| 参数 | 描述 |
|---|---|
| IN | 在 SQL 语句创建的时候该参数是未知的。你可以用 setXXX() 方法将值绑定到IN参数中。 |
| OUT | 该参数由 SQL 语句的返回值提供。你可以用 getXXX() 方法获取 OUT 参数的值。 |
| INOUT | 该参数同时提供输入输出的值。你可以用 setXXX() 方法将值绑定参数,并且用 getXXX() 方法获取值。 |
使用 CallableStatement 对象就像使用 PreparedStatement 对象一样。
- 如果有 IN 参数,使用 setXXX() 方法绑定对应的 Java 数据类型。
- 当使用 OUT 和 INOUT 参数时,必须使用 CallableStatement 的 -registerOutParameter() 方法来注册参数
- registerOutParameter() 注册后,可以用适当的 getXXX() 方法来获取 OUT 参数的值。
示例:
存储过程:
create procedure test1(inout `max_age` int)
begin
declare age int;
select max(extract(year from now())-extract(year from birthday)) age from `user1` as max;
set `max_age`=99;
end;
ResultSet
查看结果集
ResultSet接口中含有几十种从当前行获取数据的方法。
每个可能的数据类型都有一个 get 方法,并且每个 get 方法有两个版本-
- 通过列名。
- 通过列的索引。
例如,如果你想查看的列包含一个 int 类型,你需要在 ResultSet 中调用 getInt()方法-
同样的,在 ResultSet 接口中还有获取八个 Java 原始类型的 get 方法,以及常见的类型,比如 java.lang.String,
Jdbc 程序中的 ResultSet 用于代表 Sql 语句的执行结果。Resultset 封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标在第一行之前,调用 resultSet.next() 方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。 ResultSet 提供检索不同类型字段的方法,常用的有: getString(int index)、getString(String columnName):通过索引或者字段名获得在数据库里是 varchar、char 等类型的数据对象。 getFloat(int index)、getFloat(String columnName):通过索引或者字段名获得在数据库里是 Float 类型的数据对象。 getDate(int index)、getDate(String columnName):通过索引或者字段名获得在数据库里是 Date 类型的数据。 getBoolean(int index)、getBoolean(String columnName):通过索引或者字段名获得在数据库里是 Boolean 类型的数据。 getObject(int index)、getObject(String columnName):通过索引或者字段名获取在数据库里任意类型的数据。 注意: ResultSet 的 index 是从 1 开始的,这与我们平时所写代码注意区分。 ResultSet 还提供了对结果集进行滚动的方法: previous():移动到前一行 absolute(int row):移动到指定行 beforeFirst():移动 resultSet 的最前面。 afterLast() :移动到 resultSet 的最后面。 注意:释放资源, Jdbc 程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常有 ResultSet,Statement 和 Connection 对象。 释放资源按照“后开先关”原则,顺序如下:ResultSet → Statement → Connection 为确保资源释放代码能正确运行,资源释放代码在使用 try-catch 时一定要放在 finally 语句中。数据类型
JDBC 驱动程序在将 Java 数据类型发送到数据库之前,会将其转换为相应的 JDBC 类型。对于大多数数据类型都采用了默认的映射关系。
| SQL | JDBC/Java | setXXX | updateXXX |
|---|---|---|---|
| VARCHAR | java.lang.String | setString | updateString |
| CHAR | java.lang.String | setString | updateString |
| LONGVARCHAR | java.lang.String | setString | updateString |
| BIT | boolean | setBoolean | updateBoolean |
| NUMERIC | java.math.BigDecimal | setBigDecimal | updateBigDecimal |
| TINYINT | byte | setByte | updateByte |
| SMALLINT | short | setShort | updateShort |
| INTEGER | int | setInt | updateInt |
| BIGINT | long | setLong | updateLong |
| REAL | float | setFloat | updateFloat |
| FLOAT | float | setFloat | updateFloat |
| DOUBLE | double | setDouble | updateDouble |
| VARBINARY | byte[ ] | setBytes | updateBytes |
| BINARY | byte[ ] | setBytes | updateBytes |
| DATE | java.sql.Date | setDate | updateDate |
| TIME | java.sql.Time | setTime | updateTime |
| TIMESTAMP | java.sql.Timestamp | setTimestamp | updateTimestamp |
| CLOB | java.sql.Clob | setClob | updateClob |
| BLOB | java.sql.Blob | setBlob | updateBlob |
| ARRAY | java.sql.Array | setARRAY | updateARRAY |
| REF | java.sql.Ref | SetRef | updateRef |
| STRUCT | java.sql.Struct | SetStruct | updateStruct |
可能的 RSType 如下所示。如果你不指定 ResultSet 类型,将自动获得的值是 TYPE_FORWARD_ONLY。
| 类型 | 描述 |
|---|---|
| ResultSet.TYPE_FORWARD_ONLY | 光标只能在结果集中向前移动。 |
| ResultSet.TYPE_SCROLL_INSENSITIVE | 光标可以向前和向后移动。当结果集创建后,其他人对数据库的操作不会影响结果集的数据。 |
| ResultSet.TYPE_SCROLL_SENSITIVE. | 光标可以向前和向后移动。当结果集创建后,其他人对数据库的操作会影响结果集的数据。 |
RSConcurrency 的值如下所示,如果你不指定并发类型,将自动获得的值是 CONCUR_READ_ONLY。
| 并发性 | 描述 |
|---|---|
| ResultSet.CONCUR_READ_ONLY | 创建一个只读结果集,这是默认的值。 |
| ResultSet.CONCUR_UPDATABLE | 创建一个可修改的结果集。 |
到目前为止我们的示例可以如下所示,可以写成初始化一个 Statement 对象来创建一个只能前进,而且只读的 ResultSet 对象-
try {
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
}
catch(Exception ex) {
//....
}
finally {
//....
}
在 ResultSet 接口中包括如下几种方法涉及移动光标-
| S.N. | 方法 & 描述 |
|---|---|
| 1 | public void beforeFirst() throws SQLException将光标移动到第一行之前。 |
| 2 | public void afterLast() throws SQLException将光标移动到最后一行之后。 |
| 3 | public boolean first() throws SQLException将光标移动到第一行。 |
| 4 | public void last() throws SQLException将光标移动到最后一行。 |
| 5 | public boolean absolute(int row) throws SQLException将光标移动到指定的第 row 行。 |
| 6 | public boolean relative(int row) throws SQLException将光标移动到当前指向的位置往前或往后第 row 行的位置。 |
| 7 | public boolean previous() throws SQLException将光标移动到上一行,如果超过结果集的范围则返回 false。 |
| 8 | public boolean next() throws SQLException将光标移动到下一行,如果是结果集的最后一行则返回 false。 |
| 9 | public int getRow() throws SQLException返回当前光标指向的行数的值。 |
| 10 | public void moveToInsertRow() throws SQLException将光标移动到结果集中指定的行,可以在数据库中插入新的一行。当前光标位置将被记住。 |
| 11 | public void moveToCurrentRow() throws SQLException如果光标处于插入行,则将光标返回到当前行,其他情况下,这个方法不执行任何操作。 |
如果你的 JDBC 连接是处于自动提交模式下,该模式为默认模式,那么每句 SQL 语句都是在其完成时提交到数据库。
若要启用手动事务模式来代替 JDBC 驱动程序默认使用的自动提交模式的话,使用 Connection 对象的的 **setAutoCommit()**方法。
如果传递一个布尔值 false 到 setAutoCommit()方法,你就关闭自动提交模式。你也可以传递一个布尔值 true 将其再次打开。
conn.setAutoCommit(false);
当你完成了你的修改,并且要提交你的修改,可以在 connection 对象里调用 **commit()**方法-
conn.commit( );
另外,用名为 conn 的连接回滚数据到数据库,使用如下所示的代码-
conn.rollback( );
下面的例子说明了如何使用提交和回滚对象-
public class UpdateData {
public static void main(String[] args) {
boolean update = update();
System.out.println(update);
}
public static boolean update(){
Connection connection = JDBCUtility01.getConnection();
PreparedStatement statement=null;
int i=0;
if (connection!=null) {
try {
connection.setAutoCommit(false);
String sql="update `user1` set username = ? where id = ?";
statement=connection.prepareStatement(sql);
statement.setString(1,"小米");
statement.setInt(2,1);
i= statement.executeUpdate();
connection.commit();
return i!=0;
} catch (SQLException e) {
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
JDBCUtility01.Close(statement,connection);
}
}
return i==0;
}
}
批处理
批处理是指你将关联的 SQL 语句组合成一个批处理,并将他们当成一个调用提交给数据库。
当你一次发送多个 SQL 语句到数据库时,可以减少通信的资源消耗,从而提高了性能。
JDBC 驱动程序不一定支持该功能。你可以使用 DatabasemetaData.supportsBatchUpdates() 方法来确定目标数据库是否支持批处理更新。如果你的JDBC驱动程序支持此功能,则该方法返回值为 true。
- Statement,PreparedStatement 和 CallableStatement 的 addBatch() 方法用于添加单个语句到批处理。
- executeBatch() 方法用于启动执行所有组合在一起的语句。
- executeBatch() 方法返回一个整数数组,数组中的每个元素代表了各自的更新语句的更新数目。
- 可以用 clearBatch() 方法删除它们。此方法删除所有用 addBatch() 方法添加的语句。
使用 Statement 对象来使用批处理所需要的典型步骤如下所示-
- 使用 createStatement() 方法创建一个 Statement 对象。
- 使用 setAutoCommit() 方法将自动提交设为 false。
- 被创建的 Statement 对象可以使用 addBatch() 方法来添加你想要的所有SQL语句。
- 被创建的 Statement 对象可以用 executeBatch() 将所有的 SQL 语句执行。
- 最后,使用 commit() 方法提交所有的更改。
下面的代码段提供了一个使用 Statement 对象批量更新的例子-
public static boolean insert(){
Connection connection = JDBCUtility01.getConnection();
PreparedStatement statement=null;
if (connection!=null) {
try {
connection.setAutoCommit(false);
String sql="insert into `user1`(username,password,birthday,gender,is_delete) value (?,?,?,?,?)";
statement = connection.prepareStatement(sql);
connection.setAutoCommit(false);
statement.setString(1,"黄盖");
statement.setString(2,"234345");
statement.setDate(3,new Date(System.currentTimeMillis()));
statement.setString(4,"男");
statement.setBoolean(5,true);
statement.addBatch();statement.setString(1,"刘禅");
statement.setString(2,"234345");
statement.setDate(3,new Date(System.currentTimeMillis()));
statement.setString(4,"男");
statement.setBoolean(5,true);
statement.addBatch();statement.setString(1,"卢布");
statement.setString(2,"234345");
statement.setDate(3,new Date(System.currentTimeMillis()));
statement.setString(4,"男");
statement.setBoolean(5,true);
statement.addBatch();
int[] row = statement.executeBatch();
connection.commit();
return true;
} catch (SQLException throwables) {
throwables.printStackTrace();
try {
connection.rollback();//回滚
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return false;
}



