jdbc:java数据库连接
宝剑锋从磨砺出,梅花香苦自苦寒来。
1. Class.forName("com.mysql.cj.jdbc.Driver"); # jdbc8.0版本的驱动
2. Class.forName("com.mysql.jdbc.Driver"); # jdbc8.0之前的版本
简要说明
Statement: 用于执行静态SQL语句并返回其生成的结果的对象。
DriverManager: 驱动管理对象
getConnection(String url,String user,String password)
url:" jdbc:mysql://主机名称:mysql服务端口号/数据库名称"?参数=值&参数=值
Driver接口: Java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
一、快速入门
步骤:
1. 导入驱动jar包
2. 注册驱动
3. 获取数据库连接对象Connection
4. 定义sql
5. 获取执行sql语句的对象statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
初试:
package com.jdbc_learn.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbcFirstDemo {
public static void main(String[] args) throws Exception{
//1. 导入驱动
//2. 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//3.获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root", "111");
//4.定义sql语句
String sql = "update grades set grade = 10 where id = 4";
//5.获取执行对象sql的对象 statement
Statement stmt = conn.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
System.out.println(count);
//7.释放资源
stmt.close();
conn.close();
}
}
运行后查看数据库:
二、prepareStatement
- 表示预编译的SQL语句的对象, 执行动态SQL语句。 可以通过调用 Connection 对象的
- preparedStatement(String sql) 方法获取 PreparedStatement 对象。
- SQL语句已预编译并存储在PreparedStatement对象中。 然后可以使用该对象多次有效地执行此语句。
PreparedStatement 优点:
- SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令,从而利用系统的 SQL引擎完成恶意行为的做法。对于 Java 而言,要防范 SQL 注入,只要用PreparedStatement 取代 Statement就可以了。
- Update大量的数据时, 先构建一个INSERT语句再多次的执行, 会导致很多次的网络连接.。要减少JDBC的调用次数改善性能, 可以使用PreparedStatement的AddBatch()方法一次性发送多个查询给数据库。
代码:
package com.jdbc_learn.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class jdbcTwoDemo {
public static void main(String[] args) throws Exception{
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","111");
// 更新数据
//PreparedStatement pre = conn.prepareStatement("update grades set grade=? where id=1");
//pre.setInt(1,49);
//插入数据
PreparedStatement pre = conn.prepareStatement("insert into grades values(null ,?,?)");
// pre.setInt(1, 0);
pre.setString(1,"新1");
pre.setInt(2, 100);
int i = pre.executeUpdate();
System.out.println(i);
}
}
运行结果:
完善后:
package com.jdbc_learn.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Demo3 {
public static void main(String[] args){
Connection conn=null;
PreparedStatement pre=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//获取数据库连接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","111");
// 更新数据
//PreparedStatement pre = conn.prepareStatement("update grades set grade=? where id=1");
//pre.setInt(1,49);
//插入数据
pre = conn.prepareStatement("insert into grades values(null ,?,?)");
// pre.setInt(1, 0);
pre.setString(1,"新3");
pre.setInt(2, 100);
int i = pre.executeUpdate();
System.out.println(i);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
pre.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
三、jdbc.properties配置文件
properties类表示一组持久的属性。properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。
//加载,读取jdbc.properties配置的信息
//pro.load的作用是把jdbc.properties文件中配置的信息,一一put到pro这个map中
Properties中的主要方法:
(1)load(InputStream inStream) 从输入字节流中读取属性列表(键和元素对)。
pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"));
(2)getProperty/setProperty
这两个方法是分别是获取和设置属性信息。
pro.getProperty("user")
示例:
在src下建立文件jdbc.properties
代码:
package com.jdbc_learn.test;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Properties;
public class Demo3 {
public static void main(String[] args) throws Exception{
//预先加载配置文件jdbc.properties,把配置信息封装到Properties对象中
Properties pro = new Properties();
Connection conn = null;
PreparedStatement pre = null;
try {
pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"));
// 加载与注册驱动
Class.forName(pro.getProperty("driver"));
//获取数据库连接
conn = DriverManager.getConnection(pro.getProperty("url"), pro.getProperty("user"), pro.getProperty("password"));
pre = conn.prepareStatement("insert into grades values(null, ?, ?)");
pre.setString(1,"李四");
pre.setInt(2,30);
int count = pre.executeUpdate();
if(count>0) {
System.out.println(" sucess!");
} else {
System.out.println("error!");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
pre.close();
conn.close();
}
}
}
运行结果:
四、ResultSet
-
表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。
-
ResultSet对象保持一个光标指向其当前的数据行。 最初,光标位于第一行之前。 next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false ,因此可以在while循环中使用循环来遍历结果集。
-
默认的ResultSet对象不可更新,并且只有一个向前移动的光标。 因此,您只能从第一行到最后一行迭代一次。
ResultSet 接口的常用方法:
- boolean next() 遍历
- getXxx(String columnLabel):columnLabel使用 数字索引指定的列标签或者,使用列名称
- getXxx(int index) :索引从1开始
读取方法1 –通过索引来遍历读取:
while (result.next()) {
int id = result.getInt(1); //从 1开始
String name = result.getString(2);
int grade = result.getInt(3);
System.out.println("id="+id+" "+"name="+name+" "+"grade="+grade);
}
读取方法2 – 通过字段名称来读取
略
完整代码:
package com.jdbc_learn.test;
import javax.xml.transform.Result;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class Resultset_test {
public static void main(String[] args) throws Exception{
//预先加载配置文件jdbc.properties,把配置信息封装到P。个体roperties对象中
Properties pro = new Properties();
Connection conn = null;
Statement statement = null;
try {
pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"));
// 加载与注册驱动
Class.forName(pro.getProperty("driver"));
//获取数据库连接
conn = DriverManager.getConnection(pro.getProperty("url"), pro.getProperty("user"), pro.getProperty("password"));
String sql = "select * from grades;";
statement = conn.createStatement();
//执行查询并返回结果集
ResultSet result = statement.executeQuery(sql);
while (result.next()) {
int id = result.getInt(1); //从 1开始
String name = result.getString(2);
int grade = result.getInt(3);
System.out.println("id="+id+" "+"name="+name+" "+"grade="+grade);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
statement.close();
conn.close();
}
}
}
运行结果:
五、ResultSet游标回滚
游标可以前后移动,也可移动与当前位置相关的某一行.
结果集可更新.
boolean absolute(int row) 纪录集定位到第某条
void beforeFirst() 移到第一条纪录前
可以移动游标
六、释放资源
记得释放资源
七、总结
(1)加载和注册驱动,整个项目做一次即可
(2)获取数据库连接可以封装到一个方法中
(3)释放资源可以封装到一个方法中
(4)JDBC驱动的最佳化是基于使用的是什么功能,选择PreparedStatement还是Statement取决于你要怎么使用它们,对于只执行一次的SQL语句选择Statement是最好的。相反,如果SQL语句被多次执行选用PreparedStatement是最好的。
(5)PreparedStatement的第一次执行消耗是很高的,它的性能体现在后面的重复执行,使用PreparedStatement的方式来执行一个针对数据库表的查询,JDBC驱动会发送一个网络请求到数据解析和优化这个查询,而执行时会产生另一个网络请求,在JDBC驱动中,减少网络通讯是最终的目的。如果我的程序在运行期间只需要一次请求, 那么就使用Statement,对于Statement,同一个查询只会产生一次网络到数据库的通讯。