JavaWeb-15:JDBC編程
JDBC編程
一、JDBC簡介
數據庫驅動:SUN公司爲了簡化、統一對數據庫的操作,定義了一套Java操作數據庫的規範,稱之爲JDBC。
JDBC全稱爲:Java Data Base Connectivity(java數據庫連接),它主要由接口組成。
組成JDBC的2個包:
java.sql
javax.sql
開發JDBC應用需要以上2個包的支持外,還需要導入相應JDBC的數據庫實現(即數據庫驅動)。
二、第一個JDBC程序
演示JDBC的項目:
1、把數據庫的驅動加入到classpath中
2、開發步驟:
開發步驟:(必須記住的)
(1、註冊驅動
(2、獲取與數據庫的鏈接
(3、得到代表發送和執行SQL語句的對象 Statement
(4、執行語句
(5、如果執行的是查詢語句,就會有結果集,處理
(6、釋放佔用的資源
3、具體代碼
Test01.java
package com.itheima.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
create table user(
id int primary key auto_increment,
username varchar(20),
password varchar(30),
email varchar(100),
birthday date
);
* @author wangli
*
*/
public class Test01 {
public static void main(String[] args) {
try {
//1.註冊驅動
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.建立連接
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day14", "root", "yw2633275");
//3.獲取用於發送和執行SQL語句的對象 Statement
Statement st = con.createStatement();
//4.執行語句CRUD
//4.1添加記錄
st.executeUpdate("insert into user(username,password,email,birthday) values('cgx','123','[email protected]','1980-10-1')");
//4.2更新
//st.executeUpdate("update user set username='aj' where id=1");
//4.3刪除
//st.executeUpdate("delete from user where id=1");
ResultSet rs = st.executeQuery("select * from user");
//5.如果是查詢,要處理結果集
while(rs.next()){
System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"+rs.getObject(3)+"\t"+rs.getObject(4)+"\t"+rs.getObject(5));
}
//6.關閉資源
rs.close();
st.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.1、程序詳解:DriverManager
作用:a、註冊驅動b、獲取與數據庫的鏈接
Jdbc程序中的DriverManager用於加載驅動,並創建與數據庫的鏈接,這個API的常用方法:
DriverManager.registerDriver(new Driver())
DriverManager.getConnection(url, user, password),
注意:在實際開發中並不推薦採用registerDriver方法註冊驅動。原因有二:
a、查看Driver的源代碼可以看到,如果採用此種方式,會導致驅動程序註冊兩次,也就是在內存中會有兩個Driver對象。
b、程序依賴mysql的api,脫離mysql的jar包,程序將無法編譯,將來程序切換底層數據庫將會非常麻煩。
改進註冊驅動:(不能依賴具體的數據庫驅動)
推薦方式:Class.forName(“com.mysql.jdbc.Driver”);
採用此種方式不會導致驅動對象在內存中重複出現,並且採用此種方式,程序僅僅只需要一個字符串,不需要依賴具體的驅動,使程序的靈活性更高。
同樣,在開發中也不建議採用具體的驅動類型指向getConnection方法返回的connection對象。
獲取與數據庫的鏈接的三種方式:
方式一:(推薦)
DriverManager.getConnection("jdbc:mysql://localhost:3306/day17", "root", "sorry");
jdbc:mysql://localhost:3306/day17 :SUN和數據庫廠商定義的協議,具體的參考數據庫的文檔。
jdbc:mysql:///day17 (鏈接本機的默認端口3306)= jdbc:mysql://localhost:3306/day17
方式二:
方式三:
3.2、程序詳解:數據庫URL
URL用於標識數據庫的位置,程序員通過URL地址告訴JDBC程序連接哪個數據庫,URL的寫法爲:jdbc:mysql:[]//localhost:3306/test ?參數名=參數值
3.3、程序詳解—Connection
createStatement():創建向數據庫發送sql的statement對象。
prepareStatement(sql) :創建向數據庫發送預編譯sql的PrepareSatement對象。
3.4、程序詳解—Statement
Jdbc程序中的Statement對象用於向數據庫發送SQL語句, Statement對象常用方法:
executeQuery(String?sql) :用於向數據發送查詢語句。
executeUpdate(String?sql):用於向數據庫發送insert、update或delete語句
execute(String sql):用於向數據庫發送任意sql語句
3.5、程序詳解—ResultSet
Jdbc程序中的ResultSet用於代表Sql語句的執行結果。Resultset封裝執行結果時,採用的類似於表格的方式。ResultSet 對象維護了一個指向表格數據行的遊標,初始的時候,遊標在第一行之前,調用ResultSet.next() 方法,可以使遊標指向具體的數據行,進行調用方法獲取該行的數據。
ResultSet既然用於封裝執行結果的,所以該對象提供的都是用於獲取數據的get方法:
獲取任意類型的數據
getObject(int index)
getObject(string columnName)
獲取指定類型的數據,(封裝數據時方便)例如:
getString(int index)
getString(String columnName)
常用數據類型轉換表
ResultSet還提供了對結果集進行滾動的方法:
next():移動到下一行
Previous():移動到前一行
absolute(int row):移動到指定行
beforeFirst():移動resultSet的最前面。
afterLast() :移動到resultSet的最後面。
3.6、程序詳解—釋放資源
Jdbc程序運行完後,切記要釋放程序在運行過程中,創建的那些與數據庫進行交互的對象,這些對象通常是ResultSet, Statement和Connection對象。
特別是Connection對象,它是非常稀有的資源,用完後必須馬上釋放,如果Connection不能及時、正確的關閉,極易導致系統宕機。Connection的使用原則是儘量晚創建,儘量早的釋放。
爲確保資源釋放代碼能運行,資源釋放代碼也一定要放在finally語句中。
3.7、使用JDBC對數據庫進行CRUD
Jdbc中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查語句即可。
Statement對象的executeUpdate方法,用於向數據庫發送增、刪、改的sql語句,executeUpdate執行完後,將會返回一個整數(即增刪改語句導致了數據庫幾行數據發生了變化)。
Statement.executeQuery方法用於向數據庫發送查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象。
三、改善後的JDBC編程。
text02.java
package com.itheima.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.itheima.domain.User;
/**
create table user(
id int primary key auto_increment,
username varchar(20),
password varchar(30),
email varchar(100),
birthday date
);
* @author wangli
*
*/
public class Test02 {
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
//1.註冊驅動 缺點:1.導致二次註冊驅動 2.嚴重依賴mysql jar文件
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");
//2.建立連接
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day15", "root", "yw2633275");
/*Properties props = new Properties();
props.put("user", "root");
props.put("password", "root");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day15",props);*/
//Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/day15?user=root&password=root");
//3.獲取用於發送和執行SQL語句的對象 Statement
st = con.createStatement();
//4.執行語句CRUD
//4.1添加記錄 executeUpdate()專用於CUD操作
int i = st.executeUpdate("insert into user(username,password,email,birthday) values('cgx','123','[email protected]','1980-10-1')");
System.out.println(i);
//4.2更新
//st.executeUpdate("update user set username='aj' where id=1");
//4.3刪除
//st.executeUpdate("delete from user where id=1");
//executeQuery()專注於查詢操作
//ResultSet rs = st.executeQuery("select * from user");
//execute()執行所有SQL語句都 可以
/*boolean flag = st.execute("select * from user");
ResultSet rs =null;
if(flag){
rs = st.getResultSet();
//5.如果是查詢,要處理結果集
while(rs.next()){
System.out.println(rs.getObject(1)+"\t"+rs.getObject(2)+"\t"+rs.getObject(3)+"\t"+rs.getObject(4)+"\t"+rs.getObject(5));
}
}*/
List<User> list = new ArrayList<User>();
rs = st.executeQuery("select * from user");
while(rs.next()){
//封裝結果集到集合中
list.add(new User(rs.getInt("id"),rs.getString("username"),rs.getString("password")
,rs.getString("email"),rs.getDate("birthday")));
}
for(User user :list){
System.out.println(user);
}
System.out.println(list);
//boolean flag = st.execute("delete from user where id=4");
//System.out.println(flag);
} catch (Exception e) {
e.printStackTrace();
}finally{
//6.關閉資源
/* try {
if(rs!=null){
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
rs = null;
if(st!=null){
try {
st.close();
} catch (Exception e) {
e.printStackTrace();
}
st = null;
if(con!=null){
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
con=null;
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}*/
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
con = null;
}
}
}
}
四、標準JDBC模板
text03.java
package com.itheima.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test03 {
public static void main(String[] args) {
Connection con =null;
Statement st = null;
ResultSet rs = null;
try {
Class.forName("");
con = DriverManager.getConnection("", "root", "root");
st = con.createStatement();
st.executeUpdate("");//CUD
rs = st.executeQuery("");//R
while(rs.next()){
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
con = null;
}
}
}
}
五、封裝到JAVABEAN
遍歷結果集打印到控制檯沒有意義,應該封裝到JavaBean中:
user.java
package com.itheima.domain;
import java.util.Date;
public class User {
private int id;
private String username;
private String password;
private String email;
private Date birthday;
public User() {
super();
}
public User(int id, String username, String password, String email,
Date birthday) {
super();
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.birthday = birthday;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password="
+ password + ", email=" + email + ", birthday=" + birthday
+ "]";
}
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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
首先把之前的代碼抽取出來封裝成工具類,因爲之前容易把配置給寫死了,所以寫一個jdbccfg.properties文件(配置裏面的信息)
jdbccfg.properties
新建JdbcUtil.java(工具類,用來配置Jdbc連接的信息)
JdbcUtil.java
package com.itheima.util;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtil {
private static String DRIVER ;
private static String URL;
private static String USER;
private static String PASSWORD;
static{
InputStream is =JdbcUtil.class.getClassLoader().getResourceAsStream("jdbccfg.properties");
Properties p = new Properties();
try {
p.load(is);
DRIVER = p.getProperty("driver");
URL = p.getProperty("url");
USER = p.getProperty("user");
PASSWORD = p.getProperty("password");
Class.forName(DRIVER);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到連接
* @throws SQLException
*
*/
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(URL,USER,PASSWORD);
}
/**
* 關閉資源
*/
public static void release(ResultSet rs,Statement st,Connection con){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
con = null;
}
}
}
爲了只加載一次,使用靜態代碼塊
在類裏爲得到方法、關閉資料封裝成工具方法提供給我們使用、
新建test04去測試JDBCUtil.java
test04.java
package com.itheima.test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.itheima.domain.User;
import com.itheima.util.JdbcUtil;
public class Test04 {
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = JdbcUtil.getConnection();
st = con.createStatement();
//CUD
//st.executeUpdate("");
//R
List<User> list = new ArrayList<User>();
rs = st.executeQuery("select * from user");
while(rs.next()){
//封裝結果集到集合中
list.add(new User(rs.getInt("id"),rs.getString("username"),rs.getString("password")
,rs.getString("email"),rs.getDate("birthday")));
}
for(User user :list){
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(rs, st, con);
}
}
}
六、實例:利用JDBC改寫之前的用戶註冊案例
七、理解Dao解耦的好處(很關鍵)
BeanFactory+接口實現類+Properties文件解決dao耦合性過強的弊端。在利用JDBC改寫之前的用戶註冊案例中,我們利用了BeanFactory來導入用來配置信息的properties文件,用戶可以手動更改properties的內容來切換系統和各種類型的數據庫的連接,這種機制同時是藉助於接口的特性還有接口和實現類之間的多態特性來完成,當程序員拿到了一個本來是使用別的數據庫的項目時,由於項目使用了三層架構模型,那麼就可以利用接口實現自己需要的數據庫類型的實現類,並使用BeanFactory來進行切換。
八、大數據處理:使用JDBC編程進行對大容量數據進行上傳下載
項目:blob03
jdbccfg.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://localhost\:3306/day15
user=root
password=root
JdbcUtil.java
package com.itheima.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtil {
private static String DRIVER ;
private static String URL;
private static String USER;
private static String PASSWORD;
static{
InputStream is =JdbcUtil.class.getClassLoader().getResourceAsStream("jdbccfg.properties");
Properties p = new Properties();
try {
p.load(is);
DRIVER = p.getProperty("driver");
URL = p.getProperty("url");
USER = p.getProperty("user");
PASSWORD = p.getProperty("password");
Class.forName(DRIVER);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 得到連接
* @throws SQLException
*
*/
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(URL,USER,PASSWORD);
}
/**
* 關閉資源
*/
public static void release(ResultSet rs,Statement st,Connection con){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
st = null;
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
con = null;
}
}
}
Test.java
package com.itheima.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.itheima.utils.JdbcUtil;
/**
create table blobtest(
id int primary key,
content longblob
);
*
*/
public class Test {
public static void main(String[] args) {
//testWriter();
testReader();
}
private static void testReader() {
Connection con = null;
PreparedStatement st = null;
ResultSet rs = null;
String sql = "select * from blobtest where id=1";
try {
con = JdbcUtil.getConnection();
st = con.prepareStatement(sql);
rs = st.executeQuery();
if(rs.next()){
InputStream is = rs.getBinaryStream("content");
OutputStream os = new FileOutputStream("d:/2.jpg");
//寫文件
int len=-1;
byte [] buffer = new byte[1024];
while((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
}
os.close();
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(rs, st, con);
}
}
private static void testWriter() {
Connection con = null;
PreparedStatement st = null;
String sql = "insert into blobtest values(?,?)";
try {
con = JdbcUtil.getConnection();
st = con.prepareStatement(sql);
st.setInt(1, 1);
InputStream is =new FileInputStream("src/1.jpg");
st.setBinaryStream(2, is, is.available());
st.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(null, st, con);
}
}
}
Test02.java
package com.itheima.test;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.Reader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import com.itheima.utils.JdbcUtil;
/**
create table clobtest(
id int primary key,
content longtext
);
*
*/
public class Test02 {
public static void main(String[] args) {
//testWriter();
testReader();
}
private static void testReader() {
Connection con = null;
PreparedStatement st = null;
ResultSet rs = null;
String sql = "select * from clobtest where id=1";
try {
con = JdbcUtil.getConnection();
st = con.prepareStatement(sql);
rs = st.executeQuery();
if(rs.next()){
Reader reader = rs.getCharacterStream("content");
FileWriter fw = new FileWriter("d:/2.txt");
int len=-1;
char []buffer = new char[1024];
while((len=reader.read(buffer))!=-1){
fw.write(buffer,0,len);
}
reader.close();
fw.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(rs, st, con);
}
}
private static void testWriter() {
Connection con = null;
PreparedStatement st = null;
String sql = "insert into clobtest values(?,?)";
try {
con = JdbcUtil.getConnection();
st = con.prepareStatement(sql);
st.setInt(1, 1);
File file = new File("src/1.txt");
FileReader reader = new FileReader(file);
st.setCharacterStream(2, reader, (int)file.length());//MySQL最多支持4G,而Oracle是可以的
st.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtil.release(null, st, con);
}
}
}
資料下載