百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 优雅编程 > 正文

JavaWeb07-JDBC(Java真正的全栈开发)

sinye56 2024-10-04 23:53 8 浏览 0 评论

【Java帮帮】QQ空间,技术文章,视频,面试资料;免费分享,欢迎关注!

jdbc

一、JDBC介绍

1. JDBC定义

JDBC(Java Data Base Connectivity,java数据库连接),说白了就是用Java语言来操作数据库.它是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序.

JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

2. JDBC的优点

有了JDBC,向各种关系数据发送SQL语句就是一件很容易的事。换言之,有了JDBC API,就不必为访问MySql数据库专门写一个程序,为访问Oracle数据库又专门写一个程序,或为访问DB2数据库又编写另一个程序等等,程序员只需用JDBC API写一个程序就够了,它可向相应数据库发送SQL调用。

3. JDBC作用

通过上面介绍,我们知道了,如果要java语言来操作数据库,就需要使用JDBC,那么我们使用JDBC到底可以做些什么操作哪?

简单的说,通过JDBC我们可以做三件事:

与数据库建立连接

发送sql语句给数据库

处理返回数据集

二、JDBC入门案例

1.新建java项目

2.导入mysql数据库驱动:mysql-connector-java-5.1.22-bin.jar

3.新建数据库

CREATE DATABASE day06;

USE day06

CREATE TABLE USER(

id INT PRIMARY KEY AUTO_INCREMENT,

username VARCHAR(20) ,

PASSWORD VARCHAR(20) ,

email VARCHAR(40)

);

INSERT INTO USER VALUES(NULL,'tom','123','tom@163.com');

INSERT INTO USER VALUES(NULL,'fox','456','fox@163.com');

INSERT INTO USER VALUES(NULL,'james','789','james@163.com');

4.常用的类与接口

在java体系结构中,有这样两个包是与jdbc有关的

java.sql.* javax.sql.*

在java.sql.*包下有以下类与接口,是我们在使用jdbc时需要用到的。

DriverManager类:它主要用于管理驱动

Connection接口:它用于与数据库建立连接

Statement接口:它用于向数据库发送sql语句

PreparedStatement接口:它是Statement的子接口,它提供了预编译功能

CallableStatement接口:它是PreparedStatement的子接口,它用于处理存储过程

ResultSet接口:它用封装查询操作返回的结果信息。

5.编写java代码连接mysql数据库,并获取user表中数据步骤

a)通过DriverManger注册驱动

b)通过DriverManager获取连接对象Connection

c)通过Connection获取一个可以向数据库发送sql语句的对象Statement d)通过Statement对象执行sql语句(select) 得到一个结果集ResultSet e)遍历结果集ResultSet,得到数据表中的数据

f)释放资源

编写java代码

// 1.通过DriverManger注册驱动

DriverManager.registerDriver(new Driver());

// 2.通过DriverManager获取连接对象

Connection con = DriverManager.getConnection(

"jdbc:mysql://localhost:3306/day06", "root", "1234");

// 3.通过Connection获取一个操作sql语句的对象Statement

Statement st = con.createStatement();

// 4.执行sql语句(select) 得到一个ResultSet

String sql = "select * from user";

ResultSet rs = st.executeQuery(sql);

// 5.操作结果集,得到数据

while (rs.next()) {

System.out.println("ID:" + rs.getInt("id") + "\tUSERNAME:"

+ rs.getString("username") + "\tPASSWORD:"

+ rs.getString("password") + "\tEMAIL:"

+ rs.getString("email"));

}

// 6.释放资源

rs.close();

st.close();

con.close();


运行结果:

三、JDBC api详情

1. DriverManager

Drivermanager是java.sql包下的一个类,它的作用是用于管理一组JDBC驱动程序的基本服务。

常用方法:

static void registerDriver(Driver driver) :向 DriverManager 注册给定驱动程序。

registDriver方法分析:

我们可以查看mysql驱动中Driver类的加载,会发现在其内部有一个静态代码块

static {

try {

java.sql.DriverManager.registerDriver(new Driver());

} catch (SQLException E) {

throw new RuntimeException("Can't register driver!");

}

}

在其中它也完成了一个注册操作,那么很明显在我们的程序中会将驱动注册两次。并且我们在使用registDriver方法是,还需要在程序中显示的导入mysql驱动中的driver类import com.mysql.jdbc.Driver;

通过以上分析,我们通过registDriver方法完成驱动的注册存在两个问题:

1.驱动对象在内存中存在两个

2.我们的程序依赖于数据库驱动

为了解决上述问题,我们在实际开发中,一般会通过反射的方式来加载我们的驱动程序

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

static Connection getConnection(String url,String user,String password):试图建立到给定数据库 URL 的连接。

getConnection方法分析:

通过这个方法,我们可以获取一个java.sql.Connection对象

getConnection方法有三个参数:

url: URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库

user:这个是数据库的用户名,对于我们来说,就是root用户

password:这个是root用户的密码

关于URL

对于url,它的基本格式如下:

协议 : 子协议 : 子名称

例如: jdbc:mysql://localhost:3306/day06

如果我们连接的是本机并且端口号是3306,以上代码也可以简写成

Jdbc:mysql:///day06

我们在jdbc中使用url很重要的一个目的是为了让DriverManager知道我们要通过哪一个数据库驱动来完成与数据库的连接。

扩展:常用的数据库连接URL

Oracle写法:jdbc:oracle:thin:@localhost:1521:sid

对于url来说,我们有时也会在其后面携带参数例如:

jdbc:mysql://localhost:3306/day06?useUnicode=true&characterEncoding=UTF-8

2. Connection

Connection是java.sql包下的一个接口

Connection代表的是一个与数据库连接的对象,当我们获取了一个Connection对象时,我们就可以说,已经与数据库连接成功.

Connection对象的获取是通过DriverManager的getConnection方法的返回值获取到的。

常用方法:

Statement createStatement():创建一个 Statement 对象来将 SQL 语句发送到数据库

PreparedStatement prepareStatement(String sql):创建一个PreparedStatement 对象来将参数化的 SQL 语句发送到数据库

CallableStatement prepareCall(String sql):创建一个 CallableStatement 对象来调用数据库存储过程

3. Statement

Statement是java.sql包下的一个接口

Statement对象用于执行静态 SQL 语句并返回它所生成结果的对象。

常用方法:

ResultSet executeQuery(String sql) :执行给定的sql语句,该语句通常是select,返回单个的ResultSet对象

int executeUpdate(String sql):执行给定的sql语句,该语句可能为update,delete,insert,返回的是行计数

boolean execute(String sql) :执行给定的sql语句,该语句返回多个结果,如果第一个结果为ResultSet对象,则返回true,其它则返回false,

4. ResultSet

ResultSet是java.sql包下的一个接口

ResultSet对象表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。

Resultset封装执行结果时,采用的类似于表格的方式。ResultSet 对象维护了一个指向表格数据行的游标cursor,初始的时候,游标在第一行之前,调用ResultSet.next() 方法,可以使游标指向具体的数据行,进而调用方法获取该行的数据。

常用方法

boolean next():将光标从当前位置向前移一行。ResultSet 光标最初位于第一行之前;第一次调用 next 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。如果存在下一行,则返回true,不存在则返回false.

获取数据

获取任意类型数据

Object getObject(String columnLabel):参数 columnLabel代表的是列的名称

Object getObject(int columnIndex) :参数columnIndex代表的是列的序号,第一列序号为1,第二列是2,以此类推

获取指定类型数据

int getInt(int columnIndex)

int getInt(String columnLabel)

Date getDate(int columnIndex)

Date getDate(String columnLabel)

String getString(int columnIndex)

String getString(String columnLabel)

以上只是列举出一部分获取指定类型数据的方法,其它的可以查看API

四、JDBC CRUD操作

1. 添加

@Test

public void insertTest() throws ClassNotFoundException, SQLException {

// 1加载驱动

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

// 2.获取Connection对象取

Connection con = DriverManager.getConnection("jdbc:mysql:///day06",

"root", "1234");

// 3.获取Statement对象

Statement st = con.createStatement();

// 4.添加操作

String sql = "insert into user values(null,'张三','123','zs@itcast.cn')";

int row = st.executeUpdate(sql);

if (row != 0) {

System.out.println("添加成功");

}

// 5.关闭资源

st.close();

con.close();

}

2. 修改

@Test

public void updateTest() throws ClassNotFoundException, SQLException {

// 1加载驱动

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

// 2.获取Connection对象取

Connection con = DriverManager.getConnection("jdbc:mysql:///day06",

"root", "1234");

// 3.获取Statement对象

Statement st = con.createStatement();

// 4.添加操作

String sql = "update user set username='李四' where id=4";

int row = st.executeUpdate(sql);

if (row != 0) {

System.out.println("修改成功");

}

// 5.关闭资源

st.close();

con.close();

}


3. 删除

@Test

public void deleteTest() throws ClassNotFoundException, SQLException {

// 1加载驱动

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

// 2.获取Connection对象取

Connection con = DriverManager.getConnection("jdbc:mysql:///day06",

"root", "1234");

// 3.获取Statement对象

Statement st = con.createStatement();

// 4.添加操作

String sql = "delete from user where id=4";

int row = st.executeUpdate(sql);

if (row != 0) {

System.out.println("删除成功");

}

// 5.关闭资源

st.close();

con.close();

}

4. 查询

@Test

public void findById() throws ClassNotFoundException, SQLException {

// 1加载驱动

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

// 2.获取Connection对象取

Connection con = DriverManager.getConnection("jdbc:mysql:///day06",

"root", "1234");

// 3.获取Statement对象

Statement st = con.createStatement();

// 4.添加操作

String sql = "select * from user where id=1";

ResultSet rs = st.executeQuery(sql);

if (rs.next()) {

System.out.println("ID:" + rs.getInt("id") + "\tUSERNAME:"

+ rs.getString("username") + "\tPASSWORD:"

+ rs.getString("password") + "\tEMAIL:"

+ rs.getString("email"));

}

// 5.关闭资源

st.close();

con.close();

}

五、JDBC工具类抽取

经过上面的CRUD操作之后,发现有重复的步骤:

l 加载驱动

l 获取连接对象

l 释放资源

那么我们是否可以将这部分内容抽取出来,当使用时,调用一下就可以了呢?

1. 工具类抽取1:

public class JdbcUtils {

public static Connection getConnection() throws ClassNotFoundException,

SQLException {

//加载驱动

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

//获取连接对象

return DriverManager.getConnection("jdbc:mysql:///day06","root", "1234");

}

public static void closeResource(Connection conn,Statement st,ResultSet rs){

if(rs!=null){

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (st!=null) {

try {

st.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn!=null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

上述代码,我们只是简单的抽取加载驱动与获取连接对象,那么这种方式存在一些问题,例如,当每一次调用JdbcUtils.getConnection()方法时,都会重新加载驱动,并且我们连接的数据库也已经固定了,可扩展性太差,为了解决这些问题,我们使用下面的方式会更加合适。

2. 工具类抽取2:

在src下新建一个properties文件,

DRIVERCLASSNAME=com.mysql.jdbc.Driver

URL=jdbc:mysql:///day06

USER=root

PASSWORD=1234

public class JdbcUtils {

private static final String DRIVERCLASSNAME;

private static final String URL;

private static final String USER;

private static final String PASSWORD;

static {

// 通过读取配置文件给常量赋值

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

DRIVERCLASSNAME = bundle.getString("DRIVERCLASSNAME");

URL = bundle.getString("URL");

USER = bundle.getString("USER");

PASSWORD = bundle.getString("PASSWORD");

}

static {

// 加载驱动

try {

Class.forName(DRIVERCLASSNAME);

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public static Connection getConnection() throws ClassNotFoundException,

SQLException {

// 获取连接对象

return DriverManager.getConnection(URL,USER,PASSWORD);

}

public static void closeResource(Connection conn,Statement st,ResultSet rs){

if(rs!=null){

try {

rs.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (st!=null) {

try {

st.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

if (conn!=null) {

try {

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

六、JDBC案例-登录

功能描述

要求在控制台上输入用户名与密码,如果信息正确,会显示出用户的详细信息

功能分析

1.要从键盘录入用户名与密码我们需要使用Scanner类完成操作

2.接收到用户名与密码后,我们需要调用jdbc程序根据用户名与密码查询数据库

select * from user where username=xxx and password=xxx;

3.若有该用户,则把用户的所有信息都打印出来;若无,则打印登录失败

代码实现:

sql用户表创建

CREATE DATABASE day06;

USE day06

CREATE TABLE USER(

id INT PRIMARY KEY AUTO_INCREMENT,

username VARCHAR(20) ,

PASSWORD VARCHAR(20) ,

email VARCHAR(40)

);

INSERT INTO USER VALUES(NULL,'tom','123','tom@163.com');

INSERT INTO USER VALUES(NULL,'fox','456','fox@163.com');

INSERT INTO USER VALUES(NULL,'james','789','james@163.com');

user类

public class User {

private int id;

private String username;

private String password;

private String email;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

@Override

public String toString() {

return "User [id=" + id + ", username=" + username + ", password="

+ password + ", email=" + email + "]";

}

}

Jdbc工具类 mysql驱动包

html表单

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

</head>

<body>

<form method="post" action="/day1001/login">

<table>

<tr>

<td>用户名:</td>

<td><input type="text" name="username">

</td>

</tr>

<tr>

<td>密码:</td>

<td><input type="password" name="password">

</td>

</tr>

<tr>

<td colspan='2'><input type="submit">

</td>

</tr>

</table>

</form>

</body>

</html>

userOperation操作类

public class UserOperation {

public User login(String username, String password) {

User user = null;

Connection conn = null;

Statement st = null;

ResultSet rs = null;

try {

con = JdbcUtils.getConnection();

st = con.createStatement();

String sql = "select * from user where username='" + username

+ "' and password='" + password + "'";

rs = st.executeQuery(sql);

if (rs.next()) {

user = new User();

user.setId(rs.getInt("id"));

user.setUsername(rs.getString("username"));

user.setPassword(rs.getString("password"));

user.setEmail(rs.getString("email"));

}

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SQLException e) {

e.printStackTrace();

} finally {

JdbcUtils.closeResource(conn,st,rs);

}

return user;

}

}

程序入口

public class LoginDemo {

public static void main(String[] args) {

Scanner sc =new Scanner(System.in);

System.out.println("请输入用户名");

String username = sc.nextLine();

System.out.println("请输入密码");//1' or 1=1 or '1

String password = sc.nextLine();

UserOperation uo = new UserOperation();

User user=uo.login(password, username);

if (user != null) {

System.out.println("用户登陆成功");

System.out.println(user);

} else {

System.out.println("登陆失败");

}

}

}

七、sql注入

对于上面的程序,如果我们在输入用户名与密码时,输入的信息如下:

用户名:tom' or 1=1 or 1='

密码:任意输入

这时会发现,我们的程序正确运行了,并显示用户登陆成功及用户的详细信息。这就产生了SQL注入问题.所谓SQL 注入是用户利用某些系统没有对输入数据进行充分的检查,从而进行恶意破坏的行为。对于SQL注入问题,我们可以使用PreparedStatement来替换Statement来解决这类问题。

八、PreparedStatement(解决sql注入)

PreparedStatement是java.sql包下的一个接口。它是Statement的一个子接口,表示预编译的 SQL 语句的对象。

SQL 语句被预编译并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

通过 Connection的preparedStatement(sql)获取该对象

注意:

参数sql,代表的是要预编译的sql语句,在语句中可以使用 “?”占位符来占位

常用方法:

ResultSet executeQuery() :用于执行select操作,注意无参数

int executeUpdate():用于执行update delete insert操作,注意无参数

对预编译的sql语句中?占位符赋值操作

void setInt(int parameterIndex,int x)

void setString(int parameterIndex,String x)

void setObject(int parameterIndex,Object x)

参数parameterIndex代表的是第几个?号,也就是参数的序号,从1开始计数,后一个参数,是要赋的值

更多方法大家可以查询帮助文档。


【Java帮帮】QQ空间,技术文章,视频,面试资料;免费分享,欢迎关注!

相关推荐

Linux中10大常用命令之sort使用案例

请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言Linux中的sort命令用于对文本文件的内容进行排序。本教程向您展示了sort...

java开发常用的Linux命令,高频的没你想象的多

Linux的命令非常多,多到有些使用的场景你工作两三年也没有遇到过,工作三四年才能遇到(Linux内核开发,Shell脚本开发,嵌入式开发、、、),但这个不是今天分享的重点,今天分享的重点是Java开...

linux常用命令(收藏版)

linux小白注意啦,给大家分享一点干货,请笑纳!1.关机命令shutdown-hnow关闭系统(1)init0关闭系统(2),0为系统的进程号telinit0关闭系统(3)shutdo...

延续Win10三年需付超3000元!微软彻底封堵:删除绕过Win11系统要求教程、将第三方工具标记为恶意软件

一切都是为了用户能够正规地升级到Windows11。整理|屠敏出品|CSDN(ID:CSDNnews)距离Windows10退役仅剩8个月,微软最近这段时间,终是忍不住接连出手了...

敲完就让你提桶跑路的Linux命令

不谨慎可能就会让你提桶的Linux命令!!!删除文件rm-rf该命令是删除文件或文件夹等最快的方式之一。删除后的内容很难恢复,如果删除系统文件可能会导致系统崩坏。˃rm-rf/#强制删除根...

超级蠕虫,累计感染40万台服务器,让Linux内核服务器感染两年

最近著名安全公司ESET发布安全报告,报告分析了其对一个超级蠕虫Ebury的15年追踪分析。在15年中该病毒持续感染了40万台服务器,曾经在2011年(2009年)攻克了Linux内核维护站点kern...

linux redhat破解密码

适用于RedhatCentosFedora1.开机选择第一个启动项,按e进入编辑模式2.在启动项编辑模式找到linux16开头的文件,按ctrl+e快速定位到该行的行末,输入空格rd.break...

慎用!Linux最危险的10个命令!

Linux是一个强大而灵活的操作系统,它提供了许多功能丰富的命令和工具,让用户可以方便地管理和控制系统。但是,有些命令如果不小心或不知情地使用,可能会造成严重的后果,甚至导致系统崩溃或数据丢失。因此,...

Linux文件和目录删除

今天只讲一个命令,这个命令已经让万千运维人既爱又恨。rm删除文件或者目录基本用法:-i显示删除提示信息-f强制删除文件-r进行目录的递归删除在公司里为了保证数据安全,一般会创建一个alias...

给你的Linux系统穿上“防弹衣”:安全加固全攻略

为什么Linux系统需要安全加固在当今数字化时代,Linux系统以其开源、稳定、高效等特性,在服务器领域占据着举足轻重的地位。无论是大型互联网公司的核心业务,还是中小企业的日常运营,都离不开L...

一天一个Linux命令:文件操作「删」rm

命令:rm-rf文件名(慎用,慎用,慎用)rm(选项)(参数)命令功能:rm-rf是一条UNIX系统下的文件删除命令,作用是无提示地强制递归删除一个目录中的一个或多个文件或目录,如果没有使用...

Linux下通过 rm -f 删除大量文件时报错:Argument list too long

问题现象云服务器ECSLinux下通过rm-f删除大量的小文件时出现类似如下错误信息:-bash:?/bin/rm:?Argument?list?too?long如下图所示:问题原因如?待删...

这10个Linux命令太危险,千万慎用!数据毁灭的瞬间只需一个回车

你好,这里是网络技术联盟站,我是瑞哥。Linux系统,以其开源自由的特性,吸引了无数开发者和科技爱好者。其强大的命令行工具赋予了用户前所未有的控制能力。然而,正如俗话所说,“能力越大,责任越大”。某些...

Linux的10大危险命令,用过的运维都很刑

rm-rf命令该命令可能导致不可恢复的系统崩坏。˃rm-rf/#强制删除根目录下所有东西。˃rm-rf*#强制删除当前目录的所有文件。˃rm-rf.#强制删除当前...

Linux环境变量设置与查看全攻略

Linux环境变量设置与查看全攻略在Linux系统中,环境变量是用于定义系统和用户级设置的一种方法,它可以影响程序的行为和系统的运行方式。了解如何设置和查看环境变量对于Linux用户来说是非常重要的技...

取消回复欢迎 发表评论: