Java DataBase Connectivity(Java语言连接数据库)
JDBC是SUN公司制定的一套接口(interface)
java.sql.*; (这个软件包下有很多接口。)
接口都有调用者和实现者。
面向接口调用、面向接口写实现类,这都属于面向接口编程。
为什么要面向接口编程?
解耦合:降低程序的耦合度,提高程序的扩展力。
多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
为什么SUN制定一套JDBC接口呢?
因为每一个数据库的底层实现原理都不一样。
Oracle数据库有自己的原理。
MySQL数据库也有自己的原理。
MS SqlServer数据库也有自己的原理。
....
每一个数据库产品都有自己独特的实现原理。
JDBC的本质到底是什么?
一套接口。
先从官网下载对应的驱动jar包,然后将其配置到环境变量classpath当中。
以上的配置是针对于文本编辑器的方式开发,使用IDEA工具的时候,不需要配置以上的环境变量。IDEA有自己的配置方式。下面我来演示一下.
1.选择一个Module
2.点击 Open Module Settings
3.选择Libraries
4.点击加号,选择对应的jar包
第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
第三步:获取数据库操作对象(专门执行sql语句的对象)
第四步:执行SQL语句(DQL DML....)
第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
import java.sql.*;
/*
JDBC编程六步
*/
public class JDBCTest01 {
public static void main(String[] args) {
Connection connection =null;
Statement statement = null;
try {
// 1.获取驱动
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
// 2.建立连接
String url = "jdbc:mysql://127.0.0.1:3306/testdatabase";
String username = "root";
String password = "123";
connection = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象
statement = connection.createStatement();
// 4.执行SQL语句
String sql = "insert into dept(deptno,dname,loc) values(50,'人事部','北京')";
//专门执行DML语句(insert delete update)
//返回值是"影响数据库中的记录的条数"
int count = statement.executeUpdate(sql);
System.out.println(count); // 1
// 5.处理查询结果集(只在select语句中才用)
// 6.释放资源
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
使用JDBC完成update和delete
代码执行前:
代码执行后:
代码部分:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest02 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
// 2.建立连接
String url = "jdbc:mysql://localhost:3306/testdatabase";
String username = "root";
String password = "123";
connection = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象
statement= connection.createStatement();
// 4.执行SQL语句
String sql = "delete from dept where deptno = 40";
int count = statement.executeUpdate(sql);
System.out.println(count == 1? "删除成功":"删除失败");
// 5.处理查询结果集
// 6.关闭资源
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
/*
JDBC完成delete,update
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCTest02 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
try {
// 1.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
// 2.建立连接
String url = "jdbc:mysql://localhost:3306/testdatabase";
String username = "root";
String password = "123";
connection = DriverManager.getConnection(url,username,password);
// 3.获取数据库操作对象
statement= connection.createStatement();
// 4.执行SQL语句
// String sql = "delete from dept where deptno = 40";
String sql = "update dept set dname = '销售部' ,loc = '苏州' where deptno = 20";
int count = statement.executeUpdate(sql);
System.out.println(count == 1? "更新成功":"更新失败");
// 5.处理查询结果集
// 6.关闭资源
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
// 注册驱动的另一种方式
public class JDBCTest03 {
public static void main(String[] args) {
try {
//这种注册方法更常用,用到了静态代码块的知识
//静态代码块的类加载的时候执行,只执行一次
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql//:localhost:3306/testdatabase");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 关闭
}
}
}
// 将连接数据库的所有信息配置到配置文件中去
/*
实际开发中不建议把数据连接到数据库中的信息写死到java程序中
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.ResourceBundle;
public class JDBCTest04 {
public static void main(String[] args) {
// 使用资源绑定器绑定属性配置文件
// java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
// 使用以下这种方式打包,属性配置文件xxx.properties必须放到类路径下
// 资源绑定器,只能绑定xxx.properties文件,并且这个文件必须在类路径下,文件拓展名也必须是properties
// 并且写路径的时候,后面的拓展名不写 .properties不写
ResourceBundle bundle = ResourceBundle.getBundle("com/JDBC");
String driver = bundle.getString("driver");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
Connection connection =null;
Statement statement = null;
try {
//1.注册驱动
Class.forName(driver);
//2.获取连接
connection = DriverManager.getConnection(url,user,password);
//3.获取数据库连接对象
statement = connection.createStatement();
//4.执行SQL语句
// String sql = "delete from dept where deptno = 40";
//JDBC 的sql语句不要写分号
String sql = "update dept set dname = '销售部2' ,loc = '苏州2' where deptno = 20";
int count = statement.executeUpdate(sql);
System.out.println(count == 1 ? "修改成功" : "修改失败");
//5.处理查询结果集(只有在select语句中才会用)
} catch (SQLException throwables) {
throwables.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (connection!= null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
import java.sql.*;
// 使用JDBC调用查询语句
public class JDBCTest05 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdatabase","root","123");
// 3.获取数据库操作对象
statement = connection.createStatement();
// 4.执行sql语句
String sql = "select empno,ename,sal from emp";
resultSet = statement.executeQuery(sql);
// 5.处理查询数据集
while(resultSet.next()){
// 这样是通过列的下标获取的, getString 可以将得到的信息全部变为String类型
/*String empno = resultSet.getString(1);
String ename = resultSet.getString(2);
String sal = resultSet.getString(3);*/
String empno = resultSet.getString("empno");
String ename = resultSet.getString("ename");
//String sal = resultSet.getString("sal");
// 还可以直接按着int 类型提出来
int sal = resultSet.getInt("sal");
System.out.println(empno + " , " + ename + " , " +sal);
}
// 6.关闭资源
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
}
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
实现功能:
1.需求:模拟用户登录功能的实现
2.业务需求:
程序运行的时候,提供一个输入的入口,可以让用户输入用户名的密码
用户输入用户名和密码之后,提交信息,java程序收集到用户信息
java程序连接数据库验证用户名和密码是否合法
合法:显示登陆成功
不合法:显示登陆失败
3.数据的准备:
在实际开发中,表的设计会使用一个专业的建模工具,我们这里安装一个建模工具:powerDesigner
使用PD工具来进行数据库表的设计(参见user-login.sql脚本)
4.当前程序存在的问题:
请输入用户名:
dashuaige
请输入密码
dashuaige ' or '1' = '1
登陆成功
这种现象叫做sql注入(安全隐患)
5.导致SQL注入的根本原因是什么?
用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程
导致sql语句的原意被扭曲,进而达到了sql注入.
*/
public class JDBCTest06 {
public static void main(String[] args) {
// 初始化一个界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
// 输出结果
System.out.println(loginSuccess ? "登陆成功" : "登录失败");
}
/**
* 用户登陆
* @param userLoginInfo 用户登陆信息
* @return false 表示失败 true 表示成功
*/
private static boolean login(Map<String, String> userLoginInfo) {
//打标记意识
boolean loginFlag = false;
//单独定义变量
String loginName = userLoginInfo.get("LoginName");
String loginPwd = userLoginInfo.get("LoginPwd");
//JDBC 代码
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdatabase","root","123");
// 3.获取数据库操作对象
statement = connection.createStatement();
// 4.执行sql
String sql = "select * from t_user where loginName = '"+ loginName +"' and loginPwd = '"+ loginPwd+"'" ;
//以上正好完成了sql语句的拼接,以下代码的含义是,发送SQL语句到DBMS,DBMS进行sql编译.
//真好将用户提供的"非法信息"编译进去,导致原sql语句的含义被扭曲了
resultSet = statement.executeQuery(sql);
// 5.处理结果集
if(resultSet.next()){
// 登陆成功
loginFlag = true;
}
// 6.释放资源
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return loginFlag;
}
/**
* 初始化用户界面
* @return 用户输入的用户名和密码等登录信息
*/
private static Map<String, String> initUI() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String LoginName = scanner.nextLine();
System.out.println("请输入密码");
String LoginPwd = scanner.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("LoginName",LoginName);
userLoginInfo.put("LoginPwd",LoginPwd);
return userLoginInfo;
}
}
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/*
* 1.如何解决sql注入的问题?
* 主要用户提供的信息不参与SQL语句的编译过程,问题就解决了
* 即使用户提供的信息中含有sql语句的关键字,但是没有参与编译,不起作用
* 要想用户的信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
* PreparedStatement属于预编译的数据库操作对象
* PreparedStatement原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传"值".
* 2.//解决了sql注入的问题
//请输入用户名:
//dashuaige
//请输入密码
//dashuaige ' or '1' = '1
//登录失败
3.解决SQL注入的关键是:用户提供的信息中即使含有SQL语句的关键字,但是这些关键字并没有参与编译,不起作用
4.对比Statement和PreparedStatement?
- Statement存在SQL注入的问题, PreparedStatement解决了SQL注入的问题
- Statement是编译一次执行一次, PreparedStatement 是编译一次执行n次 PreparedStatement 效率更高
- PreparedStatement 会在编译阶段做类型的安全检查
*
* 综上所述: PreparedStatement 使用较多,只有极少数情况下需要使用Statement
5. 什么情况下必须使用SQL注入?
* 业务方面要求必须使用SQL注入的时候
* Statement支持SQL注入,凡是业务方面是需要SQL语句拼接的,必须使用Statement
* */
public class JDBCTest07 {
public static void main(String[] args) {
// 初始化一个界面
Map<String,String> userLoginInfo = initUI();
// 验证用户名和密码
boolean loginSuccess = login(userLoginInfo);
// 输出结果
System.out.println(loginSuccess ? "登陆成功" : "登录失败");
}
/**
* 用户登陆
* @param userLoginInfo 用户登陆信息
* @return false 表示失败 true 表示成功
*/
private static boolean login(Map<String, String> userLoginInfo) {
//打标机意识
boolean loginFlag = false;
//单独定义变量
String loginName = userLoginInfo.get("LoginName");
String loginPwd = userLoginInfo.get("LoginPwd");
//JDBC 代码
Connection connection = null;
//Statement statement = null;
PreparedStatement preparedStatement =null;
ResultSet resultSet = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取连接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdatabase","root","123");
// 3.获取数据库操作对象
// statement = connection.createStatement();
// 3.获取预编译的数据库操作对象
// 问号里面只能添加值,一个问号代表一个占位符,一个问号将来接受一个值,注意:占位符不能用单引号括起来
String sql = "select * from t_user where loginName = ? and loginPwd = ?" ; //sql语句的框子
//程序执行到此,会发送sql语句的框子到DBMS,然后DBMS会进行sql语句的预先编译
preparedStatement = connection.prepareStatement(sql);
//给占位符?传值(第一个问号下表是1,第二个问号下标是2,JDBC所有的下标从1开始)
preparedStatement.setString(1,loginName);
preparedStatement.setString(2,loginPwd);
// 4.执行sql
//String sql = "select * from t_user where loginName = '"+ loginName +"' and loginPwd = '"+ loginPwd+"'" ;
//resultSet = statement.executeQuery(sql);
resultSet = preparedStatement.executeQuery();
// 5.处理结果集
if(resultSet.next()){
// 登陆成功
loginFlag = true;
}
// 6.释放资源
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (preparedStatement != null){
try {
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return loginFlag;
}
/**
* 初始化用户界面
* @return 用户输入的用户名和密码等登录信息
*/
private static Map<String, String> initUI() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String LoginName = scanner.nextLine();
System.out.println("请输入密码");
String LoginPwd = scanner.nextLine();
Map<String,String> userLoginInfo = new HashMap<>();
userLoginInfo.put("LoginName",LoginName);
userLoginInfo.put("LoginPwd",LoginPwd);
return userLoginInfo;
}
}