0%

JDBC

JDBC


JDBC(Java DataBase Connectivity)

可以为多种关系型数据库DBMS提供统一的访问方式,用Java来操作数据库

JDBC API:提供各种操作访问接口,Connection、Statement、PreparedStatement、ResultSet

主要功能:

  • 与数据库建立连接:
  • 发送SQL语句
  • 返回处理结果

类/接口:

DriverManager:管理jdbc驱动

Connection:连接

Statement(PreparedStatement):增删改查

CallableStatement:调用数据库中的 存储过程/存储函数

Result:返回的结果集

JDBC访问数据库的具体步骤:

  1. 导入驱动,加载具体的驱动类

  2. 与数据库建立连接

  3. 发送sql,执行

  4. 处理结果集(查询)

  5. JDBC DriveManager:管理不同的数据库驱动

各种数据库驱动:相应的数据库厂商提供的,连接

数据库驱动:

驱动jar 具体驱动类 连接字符串
Oracle ojdbc-x.jar oracle.jdbc.OracleDriver jdbc:oracle:thin:@localhost:1521:ORCL
MySQL mysql-connector-java-x.jar com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/数据库实例名
SqlServer sqljdbc-x.jar com.microsoft.sqlserver.jdbc.SQLServerDriver jdbc:microsoft:sqlserver:localhost:1433;databasename=数据库实例名

Connection产生操作数据库的对象:

Connection产生Statement对象:createStatement()

Connection产生PreparedStatement对象:prepareStatement()

Connection产生CallableStatement对象:prepareCall()

Statement操作数据库:

增删改:excuteUpdate()

查询:excuteQuery();

ResultSet:保存结果集 select * from xxx

next():光标下移,判断是否有下一条数据:true/false

previous():光标上移

getXxx(字段名/位置):获取具体的字段值

PreparedStatement操作数据库:

public interface PreparedStatement extends Statement

因此

增删改:excuteUpdate()

查询:executeQuery();

赋值操作:setXxx();

PreparedStatement与Statement在使用时的区别:

  1. Statement先写sql,然后写executeUpdate(sql);

  2. PreparedStatement,写sql,可能存在占位符(?),在创建PreparedStatement对象时,将sql预编译prepareStatement(sql),executeUpdate(),setXxx()替换占位符

推荐使用PreparedStatement:原因如下:

  1. 编码使用简便(避免字符串拼接)

1
2
3
4
5
6
7
8
9
10
11
//statement方式
String name = "zs";
int age = 23;
String sql = "insert into student(stuno,stuname) values ('"+name+"', "+age+“) ";
stmt.executeUpdate(sql);
//preparedStatement方式
String sql = "insert into student(stuno,stuname) values(?,?)";
psmt = connection.prepareStatement(sql);//预编译SQL
psmt.setString(1,name);
psmt.setInt(2,age);
psmt.executeUpdate();

  1. 提高性能

    若需要重复增加200条数

    stmt:需要编译200次

    psmt:只需要预编译一次,只是executeUpdate()执行100次,省去编译操作。

  2. 安全(可以有效防止SQL注入)

    stmt:存在被sql注入的风险

    (例如输入 用户名:任意值 ‘ or 1=1 -- 密码:任意值)

    分析:select count(*) from login where uname='任意值' or 1=1 --' and upwd = '任意值';

    ​ =select count(*) from login where uname='任意值' or 1=1

    ​ =select count(*) from login;

    pstmt:有效防止sql注入

jdbc总结(模板):

try{

  1. 导入驱动包、加载具体驱动类ClassforName("具体驱动类");

  2. 与数据建立连接connection = DriverManager.getConnection(...);

  3. 通过connection,获取操作数据库的对象(Statement)

stmt = connection.createStatement();

  1. (查询)处理结果集rs = pstmt.executeQuery();

while(rs.next){rs.getXxx(...);}、

}catch(ClassNotFoundException e1){...}catch(SQLException e2){...}catch(Exception e ){...}finally{xx.close;//打开顺序与关闭顺序相反 rs.close();stmt.close();connection.close();}

CallableStatement:调用 存储过程、存储函数

connection.prepareCall(参数:存储过程或存储函数名)

参数格式:

存储过程(无返回值return,用Out参数代替):{call 存储过程名(参数列表)}

存储函数(有返回值return):{?=call 存储函数名(参数列表)}

eg:

1
2
3
4
5
6
create or replace procedure addTwoNum(num1 in number,num2 in number,result out number)-- 1+2->3 -- 后跟注释
as
begin
result := num1+num2;
end ;
/

JDBC处理大文本CLOB及二进制BLOB类

JSP访问数据库

导包操作:复制到WEB-INF中的lib中

命名规范:如果在src新建一个数据库是用来操作数据库的,名字后面加上Dao(Data Access object)

src文件中的java文件注意新建包,然后将文件放入包中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Login {
private String name;
private String pwd;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class LoginDao {
public int login(Login login) {
final String URL = "jdbc:mysql://localhost:3306/JavaMysql";
final String USERNAME = "root";
final String PWD = "";
int count = -1;
Statement stmt = null;
Connection connection = null;
ResultSet rs = null;
try {
// 导入驱动,加载具体的驱动类
Class.forName("com.mysql.jdbc.Driver");
// 与数据库建立连接
connection = DriverManager.getConnection(URL, USERNAME, PWD);
// 发送sql,执行
stmt = connection.createStatement();


String sql = "select count(*) from login where name='" + login.getName() + "'and pwd='" + login.getPwd() + "'";
rs = stmt.executeQuery(sql);
if (rs.next()) {
count = rs.getInt(1);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (connection != null) connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Titile</title>
</head>
<body>
<form action="check.jsp" method="post">
用户名:<input type="text" name="uname">
密码:<input type="password" name="upwd">
<input type="submit">
</form>

</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page import="Util.LoginDao" %>
<%@ page import="Util.Login" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
Login login = new Login();
login.setName(request.getParameter("uname"));
login.setPwd(request.getParameter("upwd"));
int count = new LoginDao().login(login);
if(count==1){
out.print("登录成功");
}else{
out.print("登录失败");
}
%>
</body>
</html>

JavaBean

上述LoginDao.java中的函数login()本在jsp中操作,我们将其提取转移到LoginDao.java中,其中LoginDao类,就称之为JavaBean。

JavaBean的作用:

a.减轻了jsp的复杂度

b.提高代码的复用度(以后任何地方的登录操作,均可调用LoginDao.java中的login()方法)

JavaBean(就是一个类)的定义:满足以下两点,就可称为JavaBean

a.public 修饰的类,public无参构造

b.所有属性都是private,并且提供set/get(如果boolean则get可以替换成is)

使用层面,Java分为两大类:

  1. 封装业务逻辑的JavaBean(LoginDao.java封装了登录逻辑)用于操作一个封装数据的JavaBean

  2. 封装数据的JavaBean(实体类,Student.java Person.java)对应于数据库的一张表

eg:Login login = new Login(uname,upwd);//即用Login对象 封装了2个数据

可以发现,JavaBean可以简化代码(jsp->jsp+java)、提高代码复用