1.JDBC: Java DataBase Connectivity
可以为多种关系型数据库DBMS提供统一的访问方式;
目的:用Java来操作数据库
2.JDBC API 主要功能:
三件事,具体是通过以下类/接口实现:
DriverManager:管理jdbc驱动(不同数据库的驱动)
Connection:连接
Statement(子类:PreparedStatement):增删改查
CallableStatement:调用数据库中的存储过程/存储函数
ResultSet:返回的结果集
3.jdbc访问数据库的具体步骤:
a.导入驱动,加载具体的驱动类
b.与数据库建立连接
c.发送sql,执行
d.处理结果集(查询)
4.数据库驱动 驱动jar 具体驱动类
(1)Oracle Ojdbc-x.jar oracle.jdbc.OracleDriver
(2)MySQL mysql-connector-java-x.jar com.mysql.jdbc.Driver
(3)SqlServer sqljdbc-x.jar com.microsoft.sqlserver.jdbc.SQLServerDriver
连接字符串:
jdbc:oracle:thin:@localhost:1521:ORCL
jdbc:mysql://localhost:3306/数据库实例名
jdbc:microsoft:sqlserver:localhost:1433;databasename=数据库的实例名
使用jdbc操作数据库时,如果对数据库进行了更换,只需要替换:
驱动、具体驱动类、连接字符串、用户名、密码
例子(oracle):
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JDBCDemo {
private static final String URL = “jdbc:oracle:thin:@localhost:1521:ORCL”;
private static final String USERNAME = “scott”;
private static final String PWD = “tiger”;
public static void update(){//增删改
Connection connection = null;
Statement stmt = null;
try{
//a.导入驱动,加载具体的驱动类
Class.forName(“oracle.jdbc.OracleDriver”);//加载具体驱动类
//b.与数据库建立连接
connection = DriverManager.getConnection(URL,USERNAME,PWD);
//c.发送sql,执行(增删改)
stmt =connection.createStatement ();
//String sql = “insert into student values(1,’zs’.23,’s1’)”;
//String sql = “update student set STUNAME =’ls’ where stuno = 1”;
String sql = “delete from student where stuno = 1”;
//执行SQL
Int count = stmt.executeUpdate(sql);//返回值表示 增删改 几条数据
//d.处理结果
if(count > 0){
System.out.println(“操作成功!”);
}
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(stmt != null) stmt.close();//对象.方法
if(connection != null) connection.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
public static void query(){//查询
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
try{
//a.导入驱动,加载具体的驱动类
Class.forName(“oracle.jdbc.OracleDriver”);//加载具体驱动类
//b.与数据库建立连接
connection = DriverManager.getConnection(URL,USERNAME,PWD);
//c.发送sql,执行(查)
stmt =connection.createStatement ();
String sql = “select stuno,stuname from student”;
//执行SQL
rs = stmt.executeQuery(sql);//返回值表示 增删改 几条数据
//d.处理结果
while(rs.next()){
int sno = rs.getInt(“stuno”);
String sname = rs.getString(“stuname”);
System.out.println(sno + “--” + sname);
}
}catch(ClassNotFoundException e){
e.printStackTrace();
}catch(SQLException e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(stmt != null) stmt.close();//对象.方法
if(connection != null) connection.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
Connection产生操作数据库的对象:
Connection产生Statement对象:createStatement()
Connection产生PreparedStatement对象:prepareStatement()
Connection产生CallableStatement对象:prepareCall()
Statement操作数据库:
增删改:executeUpdate();
查询:executeQuery();
ResultSet:保存结果集 select * from xxx
next():光标下一,判断是否有下一条数据:true/false
previous():true/false
getXxx(字段名|位置):获取具体的字段值
PreparedStatement操作数据库:
public interface PreparedStatement extends Statement
因此:增删改:executeUpdate();
查询:executeQuery(); 赋值操作:setXxx();
PreparedStatement与Statement在使用时的区别:
1 Statement:
sql
executeUpdate(sql);
2 PreparedStatement:
sql(可能存在占位符?)
在创建PreparedStatement对象时,将sql预编译 prepareStatement(sql)
setXxx()将?替换掉
executeUpdate()
推荐使用PreparedStatement:原因如下:
1.编码更加简便(避免了字符串的拼接 例子:’ ”+name+” ’)
例子:
Statement:
String name = “zs”;
int age = 23;
String sql = “insert into stdent(stuno,stuname) value (‘”+name+”’,”+age+”)”;
stmt.executeUpdate(sql);
prepareStatement:
String name = “zs”;
int age = 23;
String sql = “insert into stdent(stuno,stuname) value (?,?)”;
pstmt = connection.prepareStatement(sql);//预编译SQL
pstmt.setString(1,name);
pstmt.setInt(2,age);
2.提高性能 预编译 本质executeUpdate() 是否有sql语句
3.安全(可以有效防止sql注入)
sql注入:将客户输入的内容和开发人员的SQL语句混为一体
sql注入:用户名:任意值 ’or 1=1 – (–sql里的注释语句)
密码:任意值
分析:select … where uname=’ 任意值 ‘or 1=1 --’ and upwd = ‘任意值’;
–jdbc中,除了Class.forName() 抛出ClassNotFoundException
其余方法全部抛出SQLException
注意:close时应先判断调用close的对象是否为空;
CallableStatement:调用存储过程、存储函数
connection.prepareCall(参数:存储过程或存储函数名)
参数格式:
存储过程(无返回值return,用Out参数代替):
{ call 存储过程名(参数列表)}
存储函数(有返回值return):
{ ? = call 存储函数名(参数列表)}
存储过程:例子:
create or replace procedure addTwoNum (num1 in number,num2 in number,result out number) ------ 1+2- ->3
as
begin
result := num1+num2;
end ;
/
强调:
如果通过sqlplus(cmd命令台)访问数据库,只需要开启主服务(OracleServiceSID)
通过其他程序访问数据(sqldevelop、navicat、JDBC),需要开启:主服务与监听器
JDBC调用存储过程的步骤:
a.产生调用存储过程的对象(CallableStatement) cstmt = connection.prepareCall(“…”);
b.通过setXxx()处理 输出参数值 cstmt.setInt(1,30);
c.通过registerOutParameter(…)处理输出参数类型
d.cstmt.execute(); 执行
e.接收输出值(返回值) getXxx();
存储函数:例子:
create or replace function addTwoNumFunction (num1 in number,num2 in number)
------ 1+2–>3
return number
as
result number;
begin
result := num1+num2;
return result;
end ;
/
JDBC调用存储函数:与调存储过程的区别:
在调用时,注意参数:“{ ? = call addTwoNumFunction(?,?) }”
5.处理CLOB[mysql:Text]/BLOB类型
处理稍大型数据:
a.存储路径
通过JDBC存储文件路径,然后根据IO操作处理
缺点:换电脑等操作路径就不一样了
b.CLOB:大文本数据(小说…)
c.BLOB:二进制(直白点说 所有文件)
clob与blob缺点:太笨重 占地方
clob: 大文本数据 字符流 Reader Writer
存小说:
1.先通过pstmt 的?代替小说内容(占位符);
2.在通过pstmt.setCharacterStream(2,reader,(int)file.length());将上一步的?替换成小说流,注意第三个参数要强转为int类型;
取小说:
1.通过Reader reader = rs.getCharacterStream(“NOVEL”); 将clob类型的数据 保存到Reader对象中;
2.将Reader通过Writer输出即可;
blob: 二进制 字节流 InputStream OutputStream
与CLOB步骤基本一致,区别:setBinaryStream(…) getBinaryStream(…)
6.JSP访问数据库
JSP就是在html中嵌套的java代码,因此java代码可以写在jsp中(<% … %>)
导包操作:java项目: 1.Jar复制到工程中 2.右键该Jar:build path->add to build Path
Web项目: jar复制到WEB-INF/lib
核心:就是将java中的JDBC代码,复制到JSP中的<% … %>
7.JavaBean
刚才我们将jsp中登录操作的代码转移到了LoginDao.java;其中LoginDao类就称之为
JavaBean。
JavaBean的作用:a.减轻jsp复杂度 b.提高代码复用(可以直接调用LoginDao类的实例)
JavaBean(就是一个Java类)的定义:满足下列两点就是JavaBean
a.public修饰的类,public无参构造
b.所有属性(如果有)都是private,并且提供set/get
(如果boolean 则get可以替换成is)
使用层面,Java分为2大类:
a.封装业务逻辑的JavaBean(LoginDao.java封装了登录逻辑)
b.封装数据的JavaBean (实体类,Student.java Person.java)