JDBC
JDBC(Java DataBase Connectivity)
可以为多种关系型数据库DBMS提供统一的访问方式,用Java来操作数据库
JDBC API:提供各种操作访问接口,Connection、Statement、PreparedStatement、ResultSet
主要功能:
- 与数据库建立连接:
- 发送SQL语句
- 返回处理结果
类/接口:
DriverManager:管理jdbc驱动
Connection:连接
Statement(PreparedStatement):增删改查
CallableStatement:调用数据库中的 存储过程/存储函数
Result:返回的结果集
JDBC访问数据库的具体步骤:
导入驱动,加载具体的驱动类
与数据库建立连接
发送sql,执行
处理结果集(查询)
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在使用时的区别:
Statement先写sql,然后写executeUpdate(sql);
PreparedStatement,写sql,可能存在占位符(?),在创建PreparedStatement对象时,将sql预编译prepareStatement(sql),executeUpdate(),setXxx()替换占位符
推荐使用PreparedStatement:原因如下:
- 编码使用简便(避免字符串拼接)
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();
提高性能
若需要重复增加200条数
stmt:需要编译200次
psmt:只需要预编译一次,只是executeUpdate()执行100次,省去编译操作。
安全(可以有效防止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{
导入驱动包、加载具体驱动类ClassforName("具体驱动类");
与数据建立连接connection = DriverManager.getConnection(...);
通过connection,获取操作数据库的对象(Statement)
stmt = connection.createStatement();
- (查询)处理结果集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 | create or replace procedure addTwoNum(num1 in number,num2 in number,result out number)-- 1+2->3 -- 后跟注释 |
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
16public 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
42public 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分为两大类:
封装业务逻辑的JavaBean(LoginDao.java封装了登录逻辑)用于操作一个封装数据的JavaBean
封装数据的JavaBean(实体类,Student.java Person.java)对应于数据库的一张表
eg:Login login = new Login(uname,upwd);//即用Login对象 封装了2个数据
可以发现,JavaBean可以简化代码(jsp->jsp+java)、提高代码复用