JavaWeb(四)JDBC操作Oracle
JDBC:Java DataBase Connectivity(java資料庫連線)
SUN公司為了簡化、統一對資料庫的操作,定義了一套Java操作資料庫的規範,稱之為JDBC。
jdbc是一套標準,它是由一些介面與類組成的。
涉及到的類與介面: java.sql 類:DriverManger 介面 Connection Statement ResultSet PreparedStatement CallableStatement(它是用於呼叫儲存過程) javax.sql 介面 DataSource
驅動:
兩個裝置要進行通訊,滿足一定通訊資料格式,資料格式由裝置提供商規定,裝置提供商為裝置提供驅動軟體,通過軟體可以與該裝置進行通訊。
不同的資料庫不同的驅動,有了JDBC這套標準,我們只需要學JDBC就可以。
無JDBC和有JDBC:
操作流程:
一、搭建實驗環境 :
1、建立一資料庫庫,並建立表和插入表的資料。
2、新建一個Java工程,並匯入資料驅動。
二、編寫程式,在程式中載入資料庫驅動
DriverManager. registerDriver(Driver driver)
三、建立連線(Connection)
Connection conn = DriverManager.getConnection(url,user,pass);
四、建立用於向資料庫傳送SQL的Statement物件,併發送sql
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
五、從代表結果集的ResultSet中取出資料,列印到命令列視窗
六、斷開與資料庫的連線,並釋放相關資源
JDBC中的類:
DriverManager 類
static void registerDriver(Driver driver) 註冊一個JDBC驅動程式
注意:DriverManager中可以同時註冊多個JDBC驅動 例如:同時註冊 mysql、oralce、db2 驅動 ,通過對JDBC URL分析,決定採用哪個驅動
static Connection getConnection(String url, String user, String password) 根據jdbc url 和 使用者名稱、密碼獲得一個數據庫連線
實際開發中,不推薦使用DriverManager.registerDriver 會導致驅動註冊兩次、會使得程式依賴 具體資料庫API
推薦使用 :Class.forName("com.mysql.jdbc.Driver"); 載入Driver類時完成驅動註冊,使得程式不依賴MySQL的API
***** 不要引入 與資料庫相關 具體 API
JDBC URL
jdbc:mysql://localhost:3306/day13
這裡 jdbc: 是JDBC連線協議
這裡 mysql:// 是mysql資料庫連線協議,JDBC子協議
localhost:3306 主機和埠
Connection 連線介面
應用一:獲得SQL的操作物件
Statement conn.createStatement() 該物件可以將SQL傳送給資料庫進行執行
PreparedStatement conn.prepareStatement(sql) 對SQL語句進行預編譯,防止SQL注入
CallableStatement conn.prepareCall(sql); 該物件可以呼叫資料庫中儲存過程 (以後Oracle學習)
應用二:對資料庫事務進行管理(明天)
conn.setAutoCommit(boolean); 設定事務是否自動提交
conn.commit(); 提交資料庫事務
conn.rollback(); 回滾資料庫事務
Statement 用於將SQL 傳送給資料庫 獲得操作結果
傳送單條SQL
executeUpdate 用於向資料庫傳送 insert update delete 語句,返回int 型別引數,代表影響記錄行數
executeQuery 用於向資料庫傳送 select 語句,返回ResultSet 結果集物件
execute 用於資料庫傳送任何SQL語句(包括 DDL DML DCL) 返回boolean ,SQL執行結果是ResultSet 返回true,否則 false
傳送多條SQL
addBatch(sql) 將SQL加入批處理佇列
executeBatch() 執行佇列中所有SQL語句 ,一次性向資料庫傳送多條SQL
使用ResultSet 遍歷結果集
while(rs.next()){
// 根據資料庫內部 列型別,選擇相應 getXXX方法
int ---- getInt
varchart ---- getString
date ----- getDate
}
在java.sql 定義Date、Time 、TimeStamp 對應資料庫中 date time timestamp 型別 --------------- java.sql.Date/Time/TimeStamp 都是 java.util.Date 子類
java.sql.Date 只有日期沒有時間
java.sql.Time 只有時間沒有日期
java.sql.TimeStamp 既有日期也有時間
getXXX 有兩種寫法 第一種 getString(index) 結果集中列索引 第二種 getString(列名)
思考:如果SQL語句可能會返回一行資料,也可能查不到任何記錄時,程式碼應該怎麼寫? ----- 用於登陸
if(rs.next()){
// 查到了資料
}else{
// 沒有查到資料
}
ResultSet 高階應用 ---- 滾動結果集
Connection 介面的 createStatement() 返回Statement物件,操作SQL後 產生ResultSet 預設執行next 向前滾動,不支援在滾動中對資料進行修改 (只讀不執行滾動)
Connection 介面還提供 createStatement(int resultSetType, int resultSetConcurrency) 在建立Statement物件 設定結果集型別,併發策略
結果集型別
ResultSet.TYPE_FORWARD_ONLY 只能向前,只能呼叫next 不能向回滾動
ResultSet.TYPE_SCROLL_INSENSITIVE 支援結果集向回滾動,不能檢視修改結果
ResultSet.TYPE_SCROLL_SENSITIVE 支援結果集向回滾動,檢視修改結果
結果集併發策略
ResultSet.CONCUR_READ_ONLY 只讀
ResultSet.CONCUR_UPDATABLE 支援修改
常見三種組合
ResultSet.TYPE_FORWARD_ONLY 和 ResultSet.CONCUR_READ_ONLY (預設) 只讀不支援向回滾動
ResultSet.TYPE_SCROLL_INSENSITIVE 和 ResultSet.CONCUR_READ_ONLY 只讀,支援向回滾動
ResultSet.TYPE_SCROLL_SENSITIVE 和 ResultSet.CONCUR_UPDATABLE 支援向回滾動,支援對資料修改
例子:
首先專門寫一個類連結資料庫
順序:先用 init() 初始化連結,拿到連結之後呼叫 con.prepareStatement(sql) 把 sql 語句傳進去,返回物件給pste,然後呼叫 pste.executeQuery(); 查詢,返回結果集給 rs ,然後遍歷結果集輸出內容。最後關閉。
package com.hanqi.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcConnectionUtil {
private static final String USERNAME = "test";//使用者名稱
private static final String PASSWORD = "test";//資料庫密碼
private static final String URL = "jdbc:oracle:thin:@localhost:1521:xe";
private static final String DRIVERCLASSNAME = "oracle.jdbc.OracleDriver";//載入連結資料庫的驅動包,需要將驅動包貼上到WEB-INF下lib下
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(DRIVERCLASSNAME);//載入驅動
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void destroy(Connection conn, Statement sm, ResultSet rs) {
if (conn != null) {
try {
conn.close();
conn = null;//沒有指向,垃圾回收
} catch (SQLException e) {
e.printStackTrace();
}
}
if (sm != null) {
try {
sm.close();
sm = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
rs = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
package com.hanqi.dal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.hanqi.model.AppUser;
import com.hanqi.model.Dept;
import com.hanqi.model.Emp;
import com.hanqi.util.JdbcConnectionUtil;
public class MethodDal {
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
public List<AppUser> selectAppUser() {
String sql = "select a.id,a.username hh,a.password,a.realname,a.createtime from appuser a where a.id in (76,73)";
init();
List<AppUser> list = new ArrayList<AppUser>();
try {
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
/* AppUser au = new AppUser(
rs.getInt("id"),
rs.getString("hh"),
rs.getString("password"),
rs.getString("realname"),
rs.getDate("createtime"));*/
AppUser au = new AppUser();
au.setId(rs.getInt(1));
au.setUsername(rs.getString(2));
au.setPassword(rs.getString(3));
au.setRealname(rs.getString(4));
au.setCreatetime(rs.getDate(5));
list.add(au);
}
} catch (SQLException e) {
e.printStackTrace();
}
close();
return list;
}
public List<Emp> selectEmpWithDept() {
String sql = "SELECT e.ename,d.dname FROM p_emp e, p_dept d "
+ "WHERE e.deptno=d.deptno AND d.deptno=30";
init();
List<Emp> list = new ArrayList<Emp>();
// List<Dept> list = new ArrayList<Dept>();
try {
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()) {
Emp emp = new Emp();
Dept dept = new Dept();
emp.setEname(rs.getString("ename"));
dept.setDname(rs.getString("dname"));
emp.setDept(dept);
list.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
}
close();
return list;
}
public void init() {
con = JdbcConnectionUtil.getConnection();
}
public void close() {
JdbcConnectionUtil.destroy(con, ps, rs);
}
}
實際使用中不應該設定為靜態變數,因為靜態變數只有一個值。如同以下,可以作為測試理解
package com.hanqi.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.hanqi.util.JdbcConnectionUtil;
public class Test {
private static Connection con;//獲取連結
private static PreparedStatement pste;// 用來執行SQL語句
private static ResultSet rs;//
public static void main(String[] args) {
init();//呼叫連結的方法
String sql = "select * from appuser";
try {
pste = con.prepareStatement(sql);//獲取執行SQL的物件
rs = pste.executeQuery();
while(rs.next()) {
System.out.println(rs.getInt("id"));
System.out.println(rs.getString("username"));
System.out.println(rs.getString("password"));
System.out.println(rs.getString("realname"));
System.out.println(rs.getDate("createtime"));
System.out.println("================================");
}
} catch (SQLException e) {
e.printStackTrace();
}
close();
}
public static void init() {
con = JdbcConnectionUtil.getConnection();
}
public static void close() {
JdbcConnectionUtil.destroy(con,pste,rs);
}
}
新增內容:
?佔位符:後面的語句會根據順序找到相應的第幾個佔位符
// 新增指定的引數
public int insertData(AppUser user) {
init();
int i = -1;
String sql = "insert into appuser " + "values(testsq.nextval,?,?,?,?)";
long l = new Date().getTime();
try {
ps = con.prepareStatement(sql);
ps.setString(1, user.getUsername());
ps.setString(2, user.getPassword());
ps.setString(3, user.getRealname());
ps.setDate(4, new java.sql.Date(l));
i = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
close();
return i;
}
// 批量新增資料
public int[] insertBatchData() {
init();
int[] arr = null;
try {
String sql = "insert into appuser values(testsq.nextval,?,?,?,sysdate)";
ps = con.prepareStatement(sql);
for (int i = 0; i < 5; i++) {
ps.setString(1, "user" + i);
ps.setString(2, "1234" + i);
ps.setString(3, "名稱" + i);
ps.addBatch();//批量
}
arr = ps.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
}
close();
return arr;
}
刪除、修改、查詢
package com.hanqi.dal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.hanqi.model.AppUser;
import com.hanqi.model.Dept;
import com.hanqi.model.Emp;
import com.hanqi.util.JdbcConnectionUtil;
public class MethodDal {
private Connection con;
private PreparedStatement ps;
private ResultSet rs;
// 刪除一條記錄
public int deleteData(int id) {
init();
int i = -1;
String sql = "delete appuser a where a.id=?";
try {
ps = con.prepareStatement(sql);
ps.setInt(1, id);
i = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
close();
return i;
}
// 更新表中的資料
public int updateData(int id, String realname) {
init();
int i = -1;
String sql = "update appuser a set a.realname=? where a.id=?";
try {
ps = con.prepareStatement(sql);
ps.setString(1, realname);
ps.setInt(2, id);
i = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
close();
return i;
}
public List<AppUser> selectAppUser() {
String sql = "select a.id,a.username hh,a.password,a.realname,a.createtime from appuser a where a.id in (76,73)";
init();
List<AppUser> list = new ArrayList<AppUser>();
try {
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
/* AppUser au = new AppUser(
rs.getInt("id"),
rs.getString("hh"),
rs.getString("password"),
rs.getString("realname"),
rs.getDate("createtime"));*/
AppUser au = new AppUser();
au.setId(rs.getInt(1));
au.setUsername(rs.getString(2));
au.setPassword(rs.getString(3));
au.setRealname(rs.getString(4));
au.setCreatetime(rs.getDate(5));
list.add(au);
}
} catch (SQLException e) {
e.printStackTrace();
}
close();
return list;
}
public List<Emp> selectEmpWithDept() {
String sql = "SELECT e.ename,d.dname FROM p_emp e, p_dept d "
+ "WHERE e.deptno=d.deptno AND d.deptno=30";
init();
List<Emp> list = new ArrayList<Emp>();
// List<Dept> list = new ArrayList<Dept>();
try {
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while(rs.next()) {
Emp emp = new Emp();
Dept dept = new Dept();
emp.setEname(rs.getString("ename"));
dept.setDname(rs.getString("dname"));
emp.setDept(dept);
list.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
}
close();
return list;
}
public void init() {
con = JdbcConnectionUtil.getConnection();
}
public void close() {
JdbcConnectionUtil.destroy(con, ps, rs);
}
}
使用者註冊與登入的驗證:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="com.util.User,java.util.*,com.test.*" errorPage="error.jsp" %>
<%
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
%>
<%
String sub_type = request.getParameter("sub_type");
String password = request.getParameter("password");
String password1 = request.getParameter("password1");
MethodDal m=new MethodDal();
if("reg".equals(sub_type)) {
String username = request.getParameter("username");
if (!password.equals(password1)) {
out.print("兩次輸入的密碼不一致 !");
} else {
String selectname=m.selectName(username);
if (!selectname.equals("no")) {
out.print("使用者名稱已經存在 !");
} else {
User user = new User();
user.setUsername(username);
user.setPassword(password);
m.insertData(user);
out.print("註冊成功 !");
}
}
out.print("<br>");
out.print("<a href='denglu.jsp'>跳轉登陸</a>");
}
if("log".equals(sub_type)) {
String username = request.getParameter("username");
String selectname=m.selectName(username);
String spwd=m.selectPwd(password);
if(username.equalsIgnoreCase(selectname)&&password.equalsIgnoreCase(spwd)) {
session.setAttribute("currentUser", 1);
response.sendRedirect("Maintest.jsp");
} else {
out.print("使用者名稱或密碼不正確 !");
}
out.print("<br>");
out.print("<a href='denglu.jsp'>跳轉登陸</a>");
}
%>
package com.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import com.util.JdbcConnectionUtil;
import com.util.User;
public class MethodDal {
private Connection con;
private PreparedStatement pste;
private ResultSet rs;
//向表中新增資料
public int insertData(){
init();
int i=-1;
String sql="insert into puser values('c','c')";
try {
pste=con.prepareStatement(sql);
i=pste.executeUpdate();//針對於增刪改資料嗎,返回受影響的行數
} catch (SQLException e) {
e.printStackTrace();
}
return i;
}
//向表中新增資料
public int insertData(User user){
init();
int i=-1;
String sql="insert into puser values(?,?)";
try {
pste=con.prepareStatement(sql);
pste.setString(1,user.getUsername());
pste.setString(2, user.getPassword());
i=pste.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
return i;
}
//刪除記錄
public int deleteDate(int id){
return 0;
}
//查現有姓名
public String selectName(String name){
init();
String sql="select * from puser p where p.pname=?";
try {
pste=con.prepareStatement(sql);
pste.setString(1,name);
rs = pste.executeQuery();
while(rs.next()) {
String pname=rs.getString("pname");
if(pname!=null){
return pname;
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return "no";
}
//根據姓名查密碼
public String selectPwd(String name){
init();
String sql="select * from puser p where p.pname=?";
try {
pste=con.prepareStatement(sql);
pste.setString(1,name);
rs = pste.executeQuery();
while(rs.next()) {
String pwd=rs.getString("ppassword");
return pwd;
}
} catch (SQLException e) {
e.printStackTrace();
}
return "wu";
}
public void init(){
con=JdbcConnectionUtil.getConnection();
}
}