Java中JDBC的超详细总结

Java中JDBC的超详细总结

前言

1、JDBC是什么?

Java DataBase Connectivity(Java语言连接数据库)

2、JDBC的本质

是sun公司制定的一个接口。在java.sql.*包下。

为什么SUN需要制定一套JDBC接口? 因为每一个数据库的底层实现原理都不一样。Oracle数据库有自己的原理,MySQL数据库也有自己的原理,MS SqlServer数据库也有自己的原理… 每一个数据库产品都有自己独特的实现原理,如果没有这套接口就需要写多套java程序。 驱动:就是一个jar包,里面包含了JDBC的实现类。

3、在idea工具中连接Mysql数据库

(1)先去官网下载jar包 下载jar包,具体可看此文章 jar包尽量下载最新的,因为下载旧版本可能会出现各种编译错误。

(2)导入驱动 Jar 包 使用IDEA工具JDBC代码配置驱动,导入jar包(两种方法)

4、JDBC编程六步

-说明第一步:注册驱动作用:告诉Java程序,即将要连接的是哪个品牌的数据库第二步:获取连接表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信使用完之后一定要关闭通道第三步:获取数据库操作对象专门执行sql语句的对象第四步:执行SQL语句DQL DML…第五步:处理查询结果集只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集第六步:释放资源使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭

一、JDBC编程

1、创建一个mysql数据库作为测试

create database test;

use test;

DROP TABLE IF EXISTS EMP;

DROP TABLE IF EXISTS DEPT;

DROP TABLE IF EXISTS SALGRADE;

CREATE TABLE DEPT

(DEPTNO int(2) not null ,

DNAME VARCHAR(14) ,

LOC VARCHAR(13),

primary key (DEPTNO)

);

CREATE TABLE EMP

(EMPNO int(4) not null ,

ENAME VARCHAR(10),

JOB VARCHAR(9),

MGR INT(4),

HIREDATE DATE DEFAULT NULL,

SAL DOUBLE(7,2),

COMM DOUBLE(7,2),

primary key (EMPNO),

DEPTNO INT(2)

)

;

CREATE TABLE SALGRADE

( GRADE INT,

LOSAL INT,

HISAL INT );

INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES (

10, 'ACCOUNTING', 'NEW YORK');

INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES (

20, 'RESEARCH', 'DALLAS');

INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES (

30, 'SALES', 'CHICAGO');

INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES (

40, 'OPERATIONS', 'BOSTON');

commit;

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7369, 'SMITH', 'CLERK', 7902, '1980-12-17'

, 800, NULL, 20);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20'

, 1600, 300, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7521, 'WARD', 'SALESMAN', 7698, '1981-02-22'

, 1250, 500, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7566, 'JONES', 'MANAGER', 7839, '1981-04-02'

, 2975, NULL, 20);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28'

, 1250, 1400, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01'

, 2850, NULL, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7782, 'CLARK', 'MANAGER', 7839, '1981-06-09'

, 2450, NULL, 10);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7788, 'SCOTT', 'ANALYST', 7566, '1987-04-19'

, 3000, NULL, 20);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7839, 'KING', 'PRESIDENT', NULL, '1981-11-17'

, 5000, NULL, 10);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08'

, 1500, 0, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7876, 'ADAMS', 'CLERK', 7788, '1987-05-23'

, 1100, NULL, 20);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7900, 'JAMES', 'CLERK', 7698, '1981-12-03'

, 950, NULL, 30);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7902, 'FORD', 'ANALYST', 7566, '1981-12-03'

, 3000, NULL, 20);

INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,

DEPTNO ) VALUES (

7934, 'MILLER', 'CLERK', 7782, '1982-01-23'

, 1300, NULL, 10);

commit;

INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES (

1, 700, 1200);

INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES (

2, 1201, 1400);

INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES (

3, 1401, 2000);

INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES (

4, 2001, 3000);

INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES (

5, 3001, 9999);

commit;

包含3表:部门表、员工表、薪资等级表。

2、JDBC中重要的接口和类

DriverManager类(驱动管理类)里面全是静态方法,我们用它来注册驱动:

DriverManager 类中的静态方法说明static void registerDriver(Driver driver)向 DriverManager 注册驱动程序static Connection getConnection(String url, String user, String password)建立到给定数据库 URL 的连接

Statement接口(执行sql)用于执行静态 SQL 语句并返回它所生成结果的对象:

statement中的方法说明int executeUpdate(String sql)执行更新语句,该语句可能为 INSERT、UPDATE 或 DELETE 语句,返回值是“影响数据库中的记录条数”ResultSet executeQuery(String sql)执行 SQL查询语句,该语句返回单个 ResultSet 对象

ResultSet接口(查询结果集),sql查询语句后可以将结果封装到ResultSet中:

ResultSet中的方法说明boolean next()将光标从当前位置向前移一行。ResultSet 光标最初位于第一行之前;第一次调用 next 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推(用来查询结果)String getString(int columnIndex)不管数据库中的数据类型是什么,都以String的形式取出(columnIndex是指取列数,第一列,第二列…)String getString(String columnLabel)不管数据库中的数据类型是什么,都以String的形式取出( columnLabel指查询语句中的列名)

3、反射机制注册驱动(最常用的注册驱动方法)

加载和注册数据库驱动,数据库驱动由 mysql 厂商 "com.mysql.jdbc.Driver"提供

public static void main(String[] args) {

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、获取连接

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","root");

System.out.println(conn);

} catch (SQLException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

4、示例1:插入操作

import java.sql.*;

public class JDBCTest01 {

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

try {

//1、注册驱动的第二种方法,告诉java我要连接mysql

Driver driver = new com.mysql.jdbc.Driver();

DriverManager.registerDriver(driver);

//2、获取连接,告诉java我要连接哪台机器的mysql,并写入用户和密码

//127.0.0.1和localhost都是本地ip地址

String url = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false";

String user = "root";

String password = "root";

conn = DriverManager.getConnection(url,user,password);

System.out.println(conn);

//3、获取数据库操作对象(statement专门执行sql语句)

stmt = conn.createStatement();

//4、执行sql

String sql = "insert into dept(deptno,dname,loc) values(50,'军部','长安');";

//专门执行DML语句(insert、delete、update)

//返回值是“影响数据库中的记录条数”

int a = stmt.executeUpdate(sql);

System.out.println(a);

System.out.println(a == 1 ? "保存成功":"保存失败");

//5、处理查询结果集

//插入语句,暂时不需要查询

} catch (SQLException e) {

e.printStackTrace();

} finally {

//6、释放资源

//为了保证资源一定释放,在finally语句块中关闭资源

//分别要遵循从小到大依次关闭

if (stmt != null) {

try {

stmt.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

}

5、示例2:删除操作

import java.sql.*;

public class JDBCTest02 {

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

try {

//1、注册驱动

DriverManager.registerDriver(new com.mysql.jdbc.Driver());

//2、获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","root");

//3、获取数据库操作对象

stmt = conn.createStatement();

//4、执行sql语句

String sql = "delete from dept where deptno = 50;";

int count = stmt.executeUpdate(sql);

System.out.println(count == 1 ? "删除成功":"删除失败");

} catch(SQLException e) {

e.printStackTrace();

} finally {

if (stmt != null) {

try {

stmt.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

}

6、示例3:从资源文件中读取连接数据库信息

将连接数据库的所有信息配置到配置文件jdbc.properties中:

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/test?useSSL=false

user=root

password=root

实际开发中不建议把来连接数据库的信息写死到java程序中,因为用户可能不会把数据库的密码给你。

import java.sql.*;

import java.util.*;

public class JDBCTest04 {

public static void main(String[] args) {

ResourceBundle bundle = ResourceBundle.getBundle("jdbc");

String driver = bundle.getString("driver");

String url = bundle.getString("url");

String user = bundle.getString("user");

String password = bundle.getString("password");

Connection conn = null;

Statement stmt = null;

try {

Class.forName(driver);

conn = DriverManager.getConnection(url,user,password);

stmt = conn.createStatement();

int count = stmt.executeUpdate("insert into dept(deptno,dname,loc) values(50,'人事部','北京');");

System.out.println(count == 1? "保存成功":"保存失败");

} catch(SQLException e){

e.printStackTrace();

} catch(ClassNotFoundException e) {

e.printStackTrace();

} finally {

if(conn != null) {

try {

conn.close();

} catch(SQLException e){

e.printStackTrace();

}

}

if(stmt != null) {

try {

stmt.close();

} catch(SQLException e){

e.printStackTrace();

}

}

}

}

}

7、示例4:处理查询结果集(遍历查询结果)

ResultSet中的next( )方法: next()中的光标:

import java.sql.*;

public class JDBCTest05 {

public static void main(String[] args) {

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","root");

//3、获取数据库连接对象

stmt = conn.createStatement();

//执行sql

String sql = "select empno,ename,sal from emp;";

rs = stmt.executeQuery(sql);

//5、处理查询结构集

while (rs.next()) {

//1、第一种方法

//String empno = rs.getString(1); //第一列

//String ename = rs.getString(2); //第二列

//String sal = rs.getString(3); //第三列

//System.out.println(empno + "\t" + ename + "\t" + sal + "\t"); //jdbc中所有下标从1开始

//2、第二种方法

String empno = rs.getString("empno"); //第一列

String ename = rs.getString("ename"); //第二列

String sal = rs.getString("sal"); //第三列

System.out.println(empno + "\t" + ename + "\t" + sal + "\t"); //jdbc中所有下标从1开始

}

} catch (Exception e) {

e.printStackTrace();

} finally {

//6、释放资源

if (rs != null) {

try {

rs.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

}

释放资源时先释放查询结果集,再释放数据库操作对象,最后释放数据库连接对象。

二、sql注入现象

1、用户登录程序

在数据库中先建一个用户表:

create table t_user

(

id bigint auto_increment,

loginName varchar(255),

loginPwd varchar(255),

realName varchar(255),

primary key (id)

);

insert into t_user(loginName,loginPwd,realName) values('zhangsan','123','张三');

insert into t_user(loginName,loginPwd,realName) values('jack','123','杰克');

commit;

select * from t_user;

编写一个java程序,当输入的账户和密码与表中的数据一致时,显示“登录成功”,否则“登录失败”。

import java.util.HashMap;

import java.util.Map;

import java.util.Scanner;

import java.sql.*;

//模拟用户登录成功功能的实现

public class JDBCTest06 {

public static void main(String[] args) {

Map userLoginInfo = initUI();

System.out.println(login(userLoginInfo) ? "登录成功" : "登录失败");

}

//传入一个map集合,并拿它与数据进行对比,如果账户密码合法就返回“true”,否则返回“false”

private static boolean login(Map userLoginInfo) {

boolean flag = false;

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

//1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

//2、获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","root");

//3、获取数据库操作对象

stmt = conn.createStatement();

//4、执行sql语句

//String sql = "select .* from t_user where userName = '" + userLoginInfo.get("userName") + "' and userPassword = '" + userLoginInfo.get("' userPassword;");

String sql = "select * from t_user where loginName = '"+ userLoginInfo.get("userName")+ "' and loginPwd = '" + userLoginInfo.get("userPassword")+ "'";

rs = stmt.executeQuery(sql);

flag = rs.next();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SQLException e) {

e.printStackTrace();

} finally {

if (rs != null) {

try {

rs.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (stmt != null) {

try {

stmt.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

return flag;

}

//输入函数,用户在此函数中输入自己的账户和密码,并存入map集合中去与数据库中的数据进行比较

private static Map initUI() {

Scanner s = new Scanner(System.in);

System.out.printf("请输入账号: ");

String userName = s.nextLine();

System.out.printf("请输入密码: ");

String userPassword = s.nextLine();

Map userLoginInfo = new HashMap<>();

userLoginInfo.put("userName",userName);

userLoginInfo.put("userPassword",userPassword);

return userLoginInfo;

}

}

执行结果:

2、演示sql注入现象

当我输入以下账户和密码时,它也显示登录成功!! 这种现象称为sql注入(黑客经常使用),这是一个安全隐患。

为什么会出现sql注入现象? 用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程。导致sql语句的原意被扭曲,进而达到sql注入。 因为我们上面的sql语句被写成了 select * from t_user where loginName = ‘lll’ and loginPwd = ‘lll’ or ‘1’ = ‘1’; 这个1=1是恒成立的。

3、解决sql注入

思想:不让用户的输入信息参加编译。 要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进行简单的字符串拼接。

方法:使用PreparedStatement接口 (1)prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。 (2)安全性更高,没有 SQL 注入的隐患。

操作请看注释,解释代码:

import java.sql.*;

import java.util.HashMap;

import java.util.Map;

import java.util.Scanner;

public class JDBCTest07 {

public static void main(String[] args) {

// 初始化界面

Map userLoginInfo = initUI();

// 验证用户名和密码

boolean loginSuccess = login(userLoginInfo);

// 输出最后结果

System.out.println(loginSuccess ? "登录成功" : "登录失败");

}

/**

* 用户登录

* @param userLoginInfo 用户登录信息

* @return true表示登录成功,false表示登录失败

*/

private static boolean login(Map userLoginInfo) {

boolean loginSuccess = false;

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

try {

// 1、注册驱动

Class.forName("com.mysql.jdbc.Driver");

// 2、获取连接

conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false","root","root");

// 3、获取预编译的数据库操作对象

// sql语句的框架中,一个?,表示一个占位符,一个?将来接收一个值。注意:?不要用单引号括起来

String sql = "select * from t_user where loginName = ? and loginPwd = ?";

// 程序执行到此处,会发送sql语句框架给DBMS,DBMS对sql语句框架进行预编译。

ps = conn.prepareStatement(sql);

// 给占位符?传值,第一个?的下标是1,第二个?的下标是2(JDBC中下标都从1开始)

ps.setString(1,userLoginInfo.get("userName"));

ps.setString(2,userLoginInfo.get("userPassword"));

// 4、执行sql语句

rs = ps.executeQuery();

// 5、处理结果集

if(rs.next()) {

loginSuccess = true;

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SQLException throwables) {

throwables.printStackTrace();

} finally {

// 6、释放资源

if (rs != null) {

try {

rs.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (ps != null) {

try {

ps.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

return loginSuccess;

}

/**

* 初试化界面

* @return 用户输入的用户名和密码等登录信息

*/

private static Map initUI() {

Scanner s = new Scanner(System.in);

System.out.print("请输入用户:");

String userName = s.nextLine();

System.out.print("请输入密码:");

String userPassword = s.nextLine();

Map userLoginInfo = new HashMap<>();

userLoginInfo.put("userName",userName);

userLoginInfo.put("userPassword",userPassword);

return userLoginInfo;

}

}

三、JDBC事务

把注册驱动和获取连接封装到一个工具类中,以后就不用次次写代码都写那么多了:

import java.sql.*;

/*

JDBC工具类,简化JDBC编程

*/

public class DBUtil {

/**

* 工具类中的构造方法是私有的

* 因为工具类中的方法都是静态的,直接通过类名去调即可。

*/

private DBUtil(){}

/**

* 静态代码块,类加载的时候执行

* 把注册驱动程序的代码放在静态代码块中,避免多次获取连接对象时重复调用

*/

static {

try {

Class.forName("com.mysql.jdbc.Driver");

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

public static Connection getConnection() throws SQLException {

return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase?useSSL=false","root","root");

}

public static void close(Connection conn, Statement ps, ResultSet rs){

if (rs != null) {

try {

rs.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (ps != null) {

try {

ps.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

if (conn != null) {

try {

conn.close();

} catch (SQLException throwables) {

throwables.printStackTrace();

}

}

}

}

在java中执行sql事务:

package ustc.java.jdbc;

import ustc.java.jdbc.DBUtil.DBUtil;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

/*

行级锁/悲观锁

*/

public class JDBCTest14 {

public static void main(String[] args) {

Connection conn = null;

PreparedStatement ps = null;

ResultSet rs = null;

try {

conn = DBUtil.getConnection();

// 开启事务

conn.setAutoCommit(false);

ps = conn.prepareStatement("select ename,job,sal from emp where job = ? for update ");

ps.setString(1,"MANAGER");

rs = ps.executeQuery();

while(rs.next()) {

System.out.println(rs.getString("ename") + "," + rs.getString("job") + "," + rs.getString("sal"));

}

// 提交事务(事务结束)

conn.commit();

} catch (SQLException throwables) {

// 回滚事务(事务结束)

try {

conn.rollback();

} catch (SQLException e) {

e.printStackTrace();

}

throwables.printStackTrace();

} finally {

DBUtil.close(conn,ps,rs);

}

}

}

相关推荐

完美英文怎么写?
office365ios版本

完美英文怎么写?

📅 07-06 👁️ 1175
《蓝精灵:失落的村庄》
beat365体育亚洲网页版

《蓝精灵:失落的村庄》

📅 07-22 👁️ 3995
花甲茯苓,花甲茯苓是多少年的(现在的茯苓是几年的)
beat365体育亚洲网页版

花甲茯苓,花甲茯苓是多少年的(现在的茯苓是几年的)

📅 07-03 👁️ 4367
教你boot怎么设置u盘为第一启动项
beat365体育亚洲网页版

教你boot怎么设置u盘为第一启动项

📅 06-29 👁️ 271
闪信快借审核需要多久?
office365ios版本

闪信快借审核需要多久?

📅 07-02 👁️ 643
主板内存插槽能维修(主板内存插槽坏了1个维修教程)
详解联想bios怎么进入u盘启动
在线365bet盘口

详解联想bios怎么进入u盘启动

📅 07-09 👁️ 8251
科普 | 如何才能优雅地放屁还不被人发现?
office365ios版本

科普 | 如何才能优雅地放屁还不被人发现?

📅 07-28 👁️ 3614
什么不什么晴的成语
office365ios版本

什么不什么晴的成语

📅 07-05 👁️ 1942