文章目录
通过JDBC 访问数据
一、使用Java访问数据库
JAVA 主动 提出接口 ,各种数据库适应 这些接口
- 接口就是 JDBC Java Database Connector
- 各种数据库都会提供一套对应的驱动程序(JAR文件
- 即不同的数据库都有自己对应的JAR文件
1、导入mysql对应的JAR包
- 创建lib文件夹
- 将jar文件放入
- 右键jar包,点击
add as library
导入包
2、访问数据库的步骤
-
加载驱动:涉及到反射
Class.forName
需要捕获异常- 快速添加异常的快捷键
Alt + 回车
,选第二个
- 快速添加异常的快捷键
-
连接数据库:查找db文件
-
配置url :
jdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false
ip地址,数据库名字,编码unicode,不使用加密
zy_sys
对应的是数据库名称
-
创建连接 :
Connection connection = DriverManager.getConnection(url , user , password);
- 也需要异常捕获
-
-
写SQL语句
- 创建一个字符串存储 SQL语句
- 建议先在DBMS中测试一次
-
预编译SQL语句(判断语法错误,获取执行的对象)
- 固定语法:
PreparedStatement preparedStatement = connection.prepareStatement(sql);
- 固定语法:
-
执行操作
-
获取执行结果
-
增删改调用方法
executeUpdate()
:- 返回类型int 表示受影响的条数
- 获取执行结果只需要输出这个返回值即可
-
查找调用方法
executeQuery()
:-
返回值类型是
ResultSet
(结果集:类似对象列表) -
用 while 循环 遍历结果集.
用到
ResultSet.next()
方法——向下移动一行,返回布尔值。默认是在空行,next一行才是第一行。举个例子如下:while (resultSet.next()){ // 使用对应的方法获得相应的数据类型 String sno = resultSet.getString("sno"); String sname = resultSet.getString("sname"); int sage = resultSet.getInt("sage"); // 按顺序输出结果即可 System.out.println(sno + "\t" + sname + " \t" + sage); }
-
-
-
关闭操作(关闭连接,关闭接口,关闭对象) 释放资源
- 关闭顺序有大小之分,小的先关,大的后关
3、举个例子(增删改
package com.cykj.demo;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
try {
// 1、加载驱动 ——涉及到反射知识点
Class.forName("com.mysql.jdbc.Driver"); // Driver类 驱动
String url = "jdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
// 2、连接数据库
String user = "root"; // 账号
String password = "root"; // 密码
Connection connection = DriverManager.getConnection(url , user , password); // 创建连接
System.out.println("连接成功!");
// 3、写SQL语句
String sql = "INSERT INTO zy_student(sno,sname,ssex) VALUES ('jx220501','老王',1)";
// 4、预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 5、执行操作
int re = preparedStatement.executeUpdate();
// sql的增删改都用executeUpdate() 返回类型int 表示受影响的条数
// 6、获取执行结果
System.out.println(re);
// 7、关闭
preparedStatement.close(); // 关闭编译
connection.close(); // 关闭连接
// 关闭顺序有大小之分,小的先关,大的后关
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4、 查找例子
package com.cykj.demo;
import java.sql.*;
public class Test2 {
public static void main(String[] args) {
try {
// 1、加载驱动 ——涉及到反射知识点
Class.forName("com.mysql.jdbc.Driver"); // Driver类 驱动
// 2、连接数据库
String url = "jdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
String user = "root"; // 账号
String password = "root"; // 密码
Connection connection = DriverManager.getConnection(url , user , password); // 创建连接
System.out.println("连接成功!");
// 3、写SQL语句
String sql = "SELECT sno,sname,sage FROM zy_student WHERE sno LIKE 'AF%';";
// 4、预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 5、执行操作
ResultSet resultSet = preparedStatement.executeQuery(); // 查找数据库用的是executeQuery()
// 6、获取执行结果
while (resultSet.next()){
// 使用对应的方法获得相应的数据类型
String sno = resultSet.getString("sno");
String sname = resultSet.getString("sname");
int sage = resultSet.getInt("sage");
// 按顺序输出结果即可
System.out.println(sno + "\t" + sname + " \t" + sage);
}
// 7、关闭
resultSet.close();
preparedStatement.close(); // 关闭编译
connection.close(); // 关闭连接
// 关闭顺序有大小之分,小的先关,大的后关
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
===输出结果===
AF121101 小王 22
AF121102 小红 22
AF121103 王思思 23
AF121104 小灰 30
AF121105 小林 27
AF121106 小张 26
AF121107 小丽 32
AF121108 小花 29
AF121109 小马 26
JDBC优化
一、在预编译时拼接字符串
-
SQL语句的拼接,有什么缺点?
- 写法麻烦
- 不安全,留有SQL注入的风险
-
如何解决呢?
用问号?替代字符串中需要拼接的位置
- 在预编译时加入字符串,举个例子
// 原字符串 String sql = "SELECT * FROM tb_user WHERE userid = '" + useridText + "' OR username = '" + useridText + "'";
- 修改后
// 用问号替代拼接的字符串 意思类似挖坑 String sql = "SELECT * FROM tb_user WHERE userid = ? OR username = ?";; ps = connection.prepareStatement(sql); // 预编译 // 利用setString()方法 插入字符串,计数从1开始 ps.setString(1,useridText); ps.setString(2,useridText);
- 简单理解:这种方法类似挖坑和填坑
- 先挖坑:用问号?替代也要拼接的字符串
- 再填坑,利用setString()方法 插入字符串,计数从1开始
- 注意:setString会自动给这个字符串加入单引号,无需再添加
二、优化关闭操作
-
在JDBC操作中,如果编译出现报错,后续的关闭操作就不再执行了。这样会导致数据库负担较大
- 要如何解决该问题呢?
- 利用异常关键字finally的特点:异常处理中finally是最后必须执行一次的,可以把关闭操作写在这里!
- 要如何解决该问题呢?
-
具体操作如下
-
将需要关闭的对象,设置为全局变量
-
目标**:在finally语句块里关闭对象**
-
关闭时也要加入异常捕获,注意:每次关闭都要分别捕获异常
-
在关闭前,也要加入一个if判断,判断对象不等于null,才进行关闭操作。举个例子
try{ 。。。 } catch{ 。。。 } finally { try { if (connection != null){ // 判断连接是否为空 connection.close(); // 关闭连接 } } catch (SQLException e) { // 加入关闭操作的异常捕获 e.printStackTrace(); } try { if (ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } }
-
三、封装
经过观察发现,1、2、7三步的基本类似,
可以偷懒共同的方法,可以封装起来,甚至写成一个类,即:
共同的代码———> 方法 ———> 类
1、2、7三步的代码 ———> 分别封装成方法 ———> 放在同一个类中(工具层)
- 这种类存放在工具层,这个类就成为"工具包"
1、 工具类 Utils
- 用于存放各种封装起来的方法,提供给其他模块调用
2、封装第一步和第二步 加载驱动建立连接
-
封装1+2步
public Connection getConnection (){ try { // 1、加载驱动 Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://127.0.0.1:3306/goods_db?" + "useUnicode=true&" + "characterEncoding=UTF-8&useSSL=false"; String user = "root"; String password = "root"; // 2、建立连接 Connection connection = DriverManager.getConnection(url,user,password); return connection; // 连接成功则返回连接 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; // 连接失败则返回空 }
-
但是存在一个问题,URL,用户名,密码都是不固定的,这时候就需要用到配置文件
*.properties
” 、xml
或yml
- 如何使用配置文件?
3、properties配置文件的使用
-
键值对格式 :
key=value
- 注意:等号的两边都不能有空格
-
具体使用步骤
-
将配置文件 拷贝到 项目工程目录 下
-
读取配置文件的值
-
要有对应的库 ——> 找到对应的或对象 ——> 方法
-
Java有对应的类
Properties
,实现的思路如下:- 读取文件 调用
InputStream
类 (IO流的内容 后续会接触到 - 实例化属性类
Properties
- 调用
load(文件名)
加载文件 - 取值 用
getProperty(键名)
来搜索对应的数据,返回值类型为String
- 读取文件 调用
-
举个例子
public static void main(String[] args) { try { // 用IO读取文件 InputStream inputStream = new FileInputStream("db.properties"); // 加载 Properties pps = new Properties(); pps.load(inputStream); // 获取字符串 String driver = pps.getProperty("driver"); System.out.println(driver); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
-
-
在工具类中,获取对应的驱动,url,用户名,密码存放在String
-
在执行连接数据库时,直接调用这些字符串进行登陆即可
-
- 在实际应用场景中,只需要读取一次配置文件。那么,如何只读取一次配置文件?
构造函数?实例化的时候只运行一次,但是多次实例化还会再次执行- 这里就需要用到静态代码块——
- 语法:
static {代码块}
- 在类里的静态代码块,只会执行一次
- 执行的时间是在构造函数之前,且需要实例化的时候才会运行
- 语法:
4、封装第七步:关闭操作
-
举个例子
public void closeJdbc(Connection con , PreparedStatement ps , ResultSet rs){ try { if (rs != null){ rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (con != null){ // 判断连接是否为空 con.close(); // 关闭连接 } } catch (SQLException e) { // 加入关闭操作的异常捕获 e.printStackTrace(); } try { if (ps != null) { ps.close(); } } catch (SQLException e) { e.printStackTrace(); } }
5、调用思路
-
思路如下:
- 先将工具类实例化为全局变量 (所有需要关闭的对象也要声明为全局变量)
- 调用工具类的方法
getConnection ()
获取 连接 Connection- 对应的完成了第一步和第二步
- 继续完成 写SQL语句 预编译 执行和获取结果的步骤
- 在最后的finally的语句块中调用关闭的方法
closeJdbc()
,关闭掉对应的对象。- 由于关闭方法有多个对象,当不存在某个对象时,可以传入
null
- 由于关闭方法有多个对象,当不存在某个对象时,可以传入
6、工具类的具体案例
-
举个例子
Connection connection = null; PreparedStatement ps = null; ResultSet resultSet = null; JdbcUtils jdbcUtils = new JdbcUtils(); connection = jdbcUtils.getConnection(); // 调用方法获得连接 try { String sql = "SELECT * FROM tb_user WHERE userid = ? OR username = ?"; // 预编译 ps = connection.prepareStatement(sql); ps.setString(1, useridText); ps.setString(2, usernameText); resultSet = ps.executeQuery(); if (resultSet.next()) { JOptionPane.showMessageDialog(null, "账号已重复!", "注意", JOptionPane.WARNING_MESSAGE); return; } else { // 账号没有重复 可以继续执行操作 。。。 } } catch (SQLException e) { e.printStackTrace(); } finally { jdbcUtils.closeJdbc(connection, ps, resultSet); // 如果没有resultset,就传入null即可 }