文檔版本 | 開發工具 | 測試平臺 | 工程名字 | 日期 | 作者 | 備註 |
---|---|---|---|---|---|---|
V1.0 | 2016.05.11 | lutianfei | none |
JDBC
JDBC介紹
- JDBC是什麼?
- JDBC(Java Data Base Connectivity,java數據庫連接)
- SUN公司爲了簡化、統一對數據庫的操作,定義了一套Java操作數據庫的規範,稱之爲JDBC。
- 簡單說,就是可以直接通過java語言去操作數據庫。
- jdbc是一套標準,它是由一些接口與類組成的。
組成JDBC的類和接口
- java.sql
- 類:DriverManger
- 接口
Connection
Statement
ResultSet
PreparedStatement
CallableStatement
(它是用於調用存儲過程)
- javax.sql
- 接口 DataSource(數據源)
- 什麼是驅動?
- 兩個設備要進行通信,滿足一定通信數據格式,數據格式由設備提供商規定,設備提供商爲設備提供驅動軟件,通過軟件可以與該設備進行通信。
JDBC入門
第一個JDBC程序
- 編程從user表中讀取數據,並打印在命令行窗口中。
- 一、搭建實驗環境 :
- 1、在mysql中創建一個庫,並創建user表和插入表的數據。
- 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中取出數據,打印到命令行窗口
- 六、斷開與數據庫的連接,並釋放相關資源
- 一、搭建實驗環境 :
create table user(
id int primary key auto_increment,
username varchar(20) unique not null,
password varchar(20) not null,
email varchar(40) not null
);
INSERT INTO USER VALUES(NULL,'tom','123','[email protected]');
INSERT INTO USER VALUES(NULL,'fox','123','[email protected]');
- 1.加載驅動
- 將驅動jar包複製到lib下.
- 2.創建一個JdbcDemo1類
public static void main(String[] args) throws SQLException {
// 1.註冊驅動
// DriverManager.registerDriver(new Driver()); //加載了兩個驅動
Class.forName("com.mysql.jdbc.Driver"); // 加載mysql驅動
// 2.獲取連接對象
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/day17", "root", "abc");
// 3.通過連接對象獲取操作sql語句Statement
Statement st = con.createStatement();
// 4.操作sql語句
String sql = "select * from user";
// 操作sql語句(select語句),會得到一個ResultSet結果集
ResultSet rs = st.executeQuery(sql);
// 5.遍歷結果集
// boolean flag = rs.next(); // 向下移動,返回值爲true,代表有下一條記錄.
// int id = rs.getInt("id");
// String username=rs.getString("username");
// System.out.println(id);
// System.out.println(username);
while(rs.next()){
int id=rs.getInt("id");
String username=rs.getString("username");
String password=rs.getString("password");
String email=rs.getString("email");
System.out.println(id+" "+username+" "+password+" "+email);
}
//6.釋放資源
rs.close();
st.close();
con.close();
}
JDBC操作詳解
1.註冊驅動
JDBC程序中的
DriverManager
是java.sql
包下的一個驅動管理的工具類,可以理解成是一個容器(Vector),可以裝入很多數據庫驅動,並創建與數據庫的鏈接,這個API的常用方法:- DriverManager.registerDriver(new Driver())
- DriverManager.getConnection(url, user, password),
registDriver方法
分析- public static synchronized void registerDriver(java.sql.Driver driver)
- 參數:java.sql.Driver
- 我們傳遞的是 : com.mysql.jdbc.Driver;
- 在com.mysql.jdbc.Driver類中有一段靜態代碼塊:
- public static synchronized void registerDriver(java.sql.Driver driver)
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
上述代碼的問題:
- 1.在驅動管理器中會裝入兩個mysql驅動.
- 解決方案:使用反射
Class.forName("com.mysql.jdbc.Driver");
- 分析:使用反射的方式來加載驅動有什麼好處?
- 一、查看Driver的源代碼可以看到,如果採用此種方式,會導致驅動程序註冊兩次,也就是在內存中會有兩個Driver對象。
- 二、程序依賴mysql的api,脫離mysql的jar包,程序將無法編譯,將來程序切換底層數據庫將會非常麻煩。
- 解決方案:使用反射
- 2.可以通過DriverManager來獲取連接對象
Connection con=DriverManager.getConection(String url,String user,String password);
- url作用:就是用於確定使用哪一個驅動.
- mysql url:
jdbc: mysql ://localhsot:3306/數據庫名
- oralce url:
jdbc : oracle :thin :@ localhost :1521 :sid
- mysql url:
- 1.在驅動管理器中會裝入兩個mysql驅動.
DriverManager作用總結:
- 1.註冊驅動
- 2.獲取連接Connection
數據庫URL
URL用於標識數據庫的位置,程序員通過URL地址告訴JDBC程序連接哪個數據庫,URL的寫法爲:
jdbc : mysql : // localhost :3306/test ?key=value
url格式
- 主協議 子協議 主機 端口 數據庫
jdbc : mysql ://localhost:3306/day17
mysql的url可以簡寫
- 前提:主機是:localhost 端口是 :3306
jdbc : mysql : ///day17
在url後面可以帶參數
- eg: useUnicode=true&characterEncoding=UTF-8
2.Connection詳解
java.sql.Connection
,它代表的是一個連接對象。簡單說,就是我們程序與數據庫連接。Connection作用:
- 1.可以通過Connection獲取操作SQL的Statement對象。
- Statement createStatement() throws SQLException
- 示例:
- Statement st=con.createStatement();
- 2.操作事務
- setAutoCommit(boolean flag);開啓事務,設置事務是否自動提交。
- rollback();事務回滾,在此鏈接上回滾事務。
- commit();事務提交,在鏈接上提交事務。 —與事務相關!!
- 瞭解:
- 1.可以獲取執行預處理的
PreparedStatement對象
.創建向數據庫發送預編譯sql的PrepareSatement對象
- PreparedStatement prepareStatement(String sql) throws SQLException
- 2.可以獲取執行存儲過程的
CallableStatement
,創建執行存儲過程的callableStatement對象。
- CallableStatement prepareCall(String sql) throws SQLException
- 1.可以獲取執行預處理的
- 1.可以通過Connection獲取操作SQL的Statement對象。
3.Statement詳解
java.sql.Statement
用於向數據庫發送SQL語句,執行sql語句。
Statement作用
1.執行SQL
- DML :
insert
update
delete
- int executeUpdate(String sql) :用於向數據庫發送insert、update或delete語句
- 利用返回值判斷非0來確定sql語句是否執行成功。
- int executeUpdate(String sql) :用於向數據庫發送insert、update或delete語句
- DQL :
select
- ResultSet executeQuery(String sql) : 用於向數據發送查詢語句。
- execute(String sql):用於向數據庫發送任意SQL語句
- DML :
2.批處理操作
- addBatch(String sql); 將SQL語句添加到批處理
- executeBatch(); 向數據庫發送一批SQl語句執行。
- clearBatch(); 清空批處理。
4.ResultSet詳解
java.sql.ResultSet
它是用於封裝select語句執行後查詢的結果。Resultset封裝執行結果時,採用的類似於表格的方式。ResultSet 對象維護了一個指向表格數據行的遊標cursor
,初始的時候,遊標在第一行之前,調用ResultSet.next() 方法
,可以使遊標指向具體的數據行,進而調用方法獲取該行的數據。
ResultSet常用API
1.next()方法
- public boolean next();
- 用於判斷是否有下一條記錄。如果有返回true,並且讓遊標向下移動一行。
- 如果沒有返回false.
2.可以通過ResultSet提供的getXxx()方法來獲取當前遊標指向的這條記錄中的列數據。
- 常用:
- getInt()
- getString(int index)
- getString(String columnName):也可以獲得int,Data等類型
- getDate()
- getDouble()
- 參數有兩種
- 1.getInt(int columnIndex);
- 2.getInt(String columnName);
- 常用:
如果列的類型不知道,可以通過下面的方法來操作
- getObject(int columnIndex);
- getObject(String columnName);
常用數據類型轉換表
釋放資源
JDBC程序運行完後,切記要釋放程序在運行過程中,創建的那些與數據庫進行交互的對象,這些對象通常是ResultSet, Statement和Connection對象。
特別是
Connection對象
,它是非常稀有的資源,用完後必須馬上釋放,如果Connection不能及時、正確的關閉,極易導致系統宕機。- Connection的使用原則是儘量晚創建,儘量早的釋放。
爲確保資源釋放代碼能運行,資源釋放代碼也一定要放在
finally
語句中。完整版JDBC示例代碼:
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 2.獲取連接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.獲取操作sql語句對象Statement
st = con.createStatement();
// 4.執行sql
rs = st.executeQuery("select * from user");
// 5.遍歷結果集
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " " + username + " " + password
+ " " + email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.釋放資源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用JDBC對數據庫進行CRUD
Jdbc中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查語句即可。
Statement對象的
executeUpdate方法
,用於向數據庫發送增、刪、改的sql語句,executeUpdate執行完後,將會返回一個整數(即增刪改語句導致了數據庫幾行數據發生了變化)。Statement.executeQuery方法
用於向數據庫發送查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象。1.查詢
- 1.查詢全部
- 2.條件查詢—根據id
- 2.修改
- 3.刪除
4.添加
練習:編寫程序對User表進行增刪改查操作。
- 練習:編寫工具類簡化CRUD操作。(異常暫不處理)
JdbcUtils工具類
- 只抽取到Connection
//jdbc.properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql:///day17
username=root
password=abc
public class JdbcUtils {
private static final String DRIVERCLASS;
private static final String URL;
private static final String USERNAME;
private static final String PASSWORD;
static {
DRIVERCLASS = ResourceBundle.getBundle("jdbc").getString("driverClass");
URL = ResourceBundle.getBundle("jdbc").getString("url");
USERNAME = ResourceBundle.getBundle("jdbc").getString("username");
PASSWORD = ResourceBundle.getBundle("jdbc").getString("password");
}
static {
try {
// 將加載驅動操作,放置在靜態代碼塊中.這樣就保證了只加載一次.
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
// 2.獲取連接
Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
return con;
}
//關閉操作
public static void closeConnection(Connection con) throws SQLException{
if(con!=null){
con.close();
}
}
public static void closeStatement(Statement st) throws SQLException{
if(st!=null){
st.close();
}
}
public static void closeResultSet(ResultSet rs) throws SQLException{
if(rs!=null){
rs.close();
}
}
}
- JDBC CURD
//jdbc的crud操作
public class JdbcDemo6 {
@Test
public void findByIdTest() {
// 1.定義sql
String sql = "select * from user where id=1";
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 2.獲取連接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.獲取操作sql語句對象Statement
st = con.createStatement();
// 4.執行sql
rs = st.executeQuery(sql);
// 5.遍歷結果集
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " " + username + " " + password
+ " " + email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.釋放資源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 添加操作
@Test
public void addTest() {
// 定義sql
String sql = "insert into user values(null,'張三','123','[email protected]')";
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
// 1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 2.獲取連接
con = DriverManager.getConnection("jdbc:mysql:///day17", "root",
"abc");
// 3.獲取操作sql語句對象Statement
st = con.createStatement();
// 4.執行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("添加成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.釋放資源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// update操作
@Test
public void updateTest() {
// 將id=3的人的password修改爲456
String password = "456";
String sql = "update user set password='" + password + "' where id=3";
// 1.得到Connection
Connection con = null;
Statement st = null;
try {
con = JdbcUtils1.getConnection();
// 3.獲取操作sql語句對象Statement
st = con.createStatement();
// 4.執行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("修改成功");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 關閉資源
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (con != null)
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// delete測試
@Test
public void deleteTest() {
// 將id=3的人刪除
String sql = "delete from user where id=2";
// 1.得到Connection
Connection con = null;
Statement st = null;
try {
con = JdbcUtils.getConnection();
// 3.獲取操作sql語句對象Statement
st = con.createStatement();
// 4.執行sql
int row = st.executeUpdate(sql);
if (row != 0) {
System.out.println("刪除成功");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 關閉資源
try {
JdbcUtils.closeStatement(st);
JdbcUtils.closeConnection(con);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
ResultSet 滾動結果集
默認得到的ResultSet它只能向下遍歷(next()),對於ResultSet它可以設置成是滾動的,可以向上遍歷,或者直接定位到一個指定的物理行號。
設置滾動結果集的方法
- 在創建Statement對象時,不使用
createStatement()
;而使用帶參數的createStatement(int,int)
- 在創建Statement對象時,不使用
Statement createStatement(int resultSetType,
int resultSetConcurrency)
throws SQLException
、
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
第一個參數值,
resultSetType
- ResultSet.TYPE_FORWARD_ONLY 該常量指示光標只能向前移動的 ResultSet 對象的類型。
- ResultSet.TYPE_SCROLL_INSENSITIVE 該常量指示可滾動但通常不受 ResultSet 底層數據更改影響的 ResultSet 對象的類型。
- ResultSet.TYPE_SCROLL_SENSITIVE 該常量指示可滾動並且通常受 ResultSet 底層數據更改影響的 ResultSet 對象的類型。
第二個參數值,
resultSetConcurrency
- ResultSet.CONCUR_READ_ONLY 該常量指示不可以更新的 ResultSet 對象的併發模式。
- ResultSet.CONCUR_UPDATABLE 該常量指示可以更新的 ResultSet 對象的併發模式。
以上五個值,可以有三種搭配方式
- ResultSet.TYPE_FORWARD_ONLY ResultSet.CONCUR_READ_ONLY 默認,不受底層影響
- ResultSet.TYPE_SCROLL_INSENSITIVE ResultSet.CONCUR_READ_ONLY
- ResultSet.TYPE_SCROLL_SENSITIVE ResultSet.CONCUR_UPDATABLE 滾動的,可以併發更新的
常用API
- next():移動到下一行
- previous():移動到前一行
- absolute(int row):移動到指定行
- beforeFirst():移動resultSet的最前面
- afterLast() :移動到resultSet的最後面
- updateRow() :更新行數據
DAO模式——JavaEE模式
DAO模式
(Data Access Object 數據訪問對象):在持久層通過DAO將數據源操作完全封裝起來,業務層通過操作Java對象,完成對數據源操作- 業務層無需知道數據源底層實現 ,通過java對象操作數據源
DAO模式結構
- 1、DataSource數據源(MySQL數據庫)
- 2、Business Object 業務層代碼,調用DAO完成 對數據源操作 (代表數據的使用者)
- 3、DataAccessObject 數據訪問對象,持久層DAO程序,封裝對數據源增刪改查,提供方法參數都是Java對象
- 4、TransferObject 傳輸對象(值對象) 業務層通過向數據層傳遞 TO對象,完成對數據源的增刪改查(表示數據的Java Bean)
使用dao模式完成登錄操作
需求:
- 1、把文件換成數據庫
- 2、使用DAO模式
- 3、防範sql注入攻擊
1.web層
- login.jsp LoginServlet User
- 2.service層
- UserService(實際應是接口)
- 3.dao層
- UserDao(實際應是接口)
具體代碼見工程
day17_2
。
用戶註冊流程
sql注入
- 由於沒有對用戶輸入進行充分檢查,而SQL又是拼接而成,在用戶輸入參數時,在參數中添加一些SQL 關鍵字,達到改變SQL運行結果的目的,也可以完成惡意攻擊。
- 1、statement存在sql注入攻擊問題
- 例如登陸用戶名採用
xxx’ or ‘1’=‘1
- 使用mysql註釋
- 例如登陸用戶名採用
2、對於防範 SQL 注入,可以採用
PreparedStatement
取代Statement
。- 它是一個預處理的Statement,它是java.sql.Statement接口的一個子接口。
- PreparedStatement是Statement的子接口,它的實例對象可以通過調
Connection.preparedStatement(sql)
方法獲得 - Statement會使數據庫頻繁編譯SQL,可能造成數據庫緩衝區溢出。PreparedStatement 可對SQL進行預編譯,從而提高數據庫的執行效率。
- PreperedStatement對於sql中的參數,允許使用佔位符的形式進行替換,簡化sql語句的編寫。
PreparedStatement使用總結
- 1.在sql語句中,使用
?
佔位
- String sql=”select * from user where username=? and password=?”;
- 2.得到PreparedStatement對象
- PreparedStatement pst=con.prepareStatement(String sql);
- 3.對佔位符賦值
- pst.setXxx(int index,Xxx obj);
- 例如:
- setInt()
- setString();
- 參數index,代表的是”
?
“的序號.注意:從1開始。
- 4.執行sql
- DML: pst.executeUpdate();
- DQL: pst.executeQuery();
- 注意:這兩方法無參數
- 1.在sql語句中,使用
關於PreparedStatement優點:
- 1.解決sql注入(具有預處理功能)
- 2.不需要再拼sql語句。
jdbc處理大數據
在實際開發中,程序需要把大文本
Text
或二進制數據Blob
保存到數據庫。Text
是mysql叫法,Oracle中叫Clob
大數據
也稱之爲LOB
(Large Objects),LOB又分爲:- clob用於存儲大文本。Text
- blob用於存儲二進制數據,例如圖像、聲音、二進制文等。
Text和blob分別又分爲:
- Text(clob)
- TINYTEXT(255B)、TEXT(64kb)、MEDIUMTEXT(16M)和LONGTEXT(4G)
- blob
- TINYBLOB(255B)、BLOB(64kb)、MEDIUMBLOB(16M)和LONGBLOB(4G)
- Text(clob)
對於大數據操作,我們一般只有兩種: insert select
演示1: 大二進制操作
create table myblob(
id int primary key auto_increment,
content longblob
)
public class MyBlobTest {
// 添加
@Test
public void save() throws SQLException, IOException {
String sql = "insert into myblob values(null,?)";
// 1.獲取Connection
Connection con = JdbcUtils.getConnection();
// 2.獲取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
// 3.插入值
File file = new File("D:\\java1110\\day17-jdbc\\視頻\\3.jdbc快速入門.avi");
FileInputStream fis = new FileInputStream(file);
pst.setBinaryStream(1, fis, (int) (file.length())); //MySQL驅動只支持最後一個參數爲int類型的方法
int row = pst.executeUpdate();
if (row != 0) {
System.out.println("插入成功");
}
// 4.釋放資源
fis.close();
pst.close();
con.close();
}
// 獲取
@Test
public void get() throws SQLException, IOException {
String sql = "select * from myblob where id=?";
// 1.獲取Connection
Connection con = JdbcUtils.getConnection();
// 2.獲取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
pst.setInt(1, 1);
// 3.得到結果集
ResultSet rs = pst.executeQuery();
// 4.遍歷結果集
if (rs.next()) {
// System.out.println(rs.getInt("id"));
InputStream is = rs.getBinaryStream("content");// 得到的這個輸入流它的源可以理解成就是數據庫中的大二進制信息
FileOutputStream fos = new FileOutputStream("d:/a.avi");
int len = -1;
byte[] b = new byte[1024 * 100];
while ((len = is.read(b)) != -1) {
fos.write(b, 0, len);
fos.flush();
}
fos.close();
is.close();
}
// 5.關閉
rs.close();
pst.close();
con.close();
}
}
向表中插入數據可能出現的問題
問題1:java.lang.AbstractMethodError: com.mysql.jdbc.PreparedStatement.setBinaryStream(ILjava/io/InputStream;)
原因:mysql驅動不支持setBinaryStream(int,InputStream);
修改成 pst.setBinaryStream(1, fis,file.length());
原因:因爲mysql驅動不支 setBinaryStream(int,InputStream,long);
解決: mysql驅動支持setBinaryStream(int,InputStream,int);
注意:如果文件比較大,那麼需要在my.ini文件中配置
- max_allowed_packet=64M
總結:
- 存:pst.setBinaryStream(1, fis, (int) (file.length()));
- 取:InputStream is = rs.getBinaryStream(“content”);
使用JDBC處理大文本
- 對於MySQL中的Text類型,可調用如下方法
設置
:
PreparedStatement.setCharacterStream(index, reader, length);
//注意length長度須設置,並且設置爲int型
//當包過大時修改配置:[mysqld] max_allowed_packet=64M
- 對MySQL中的Text類型,可調用如下方法
獲取
:
reader = resultSet. getCharacterStream(i);
等價於
reader = resultSet.getClob(i).getCharacterStream();
- 演示:存儲大文本
create table mytext(
id int primary key auto_increment,
content longtext
)
//存儲
File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1, fr, (int) (file.length()));
//獲取:
Reader r = rs.getCharacterStream("content");
使用JDBC處理二進制數據
- 對於MySQL中的BLOB類型,可調用如下方法
設置
:
PreparedStatement. setBinaryStream(i, inputStream, length);
- 對MySQL中的BLOB類型,可調用如下方法
獲取
:
InputStream in = resultSet.getBinaryStream(i);
InputStream in = resultSet.getBlob(i).getBinaryStream();
public class MyTextTest {
// 存儲
@Test
public void save() throws SQLException, FileNotFoundException {
String sql = "insert into mytext values(null,?)";
// 1.獲取Connection
Connection con = JdbcUtils.getConnection();
// 2.獲取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
// 3.插入值
File file = new File("D:\\java1110\\workspace\\day17_3\\a.txt");
FileReader fr = new FileReader(file);
pst.setCharacterStream(1, fr, (int) (file.length()));
pst.executeUpdate();
// 4.釋放資源
pst.close();
con.close();
}
// 獲取
@Test
public void get() throws SQLException, IOException {
String sql = "select * from mytext where id=?";
// 1.獲取Connection
Connection con = JdbcUtils.getConnection();
// 2.獲取PreparedStatement
PreparedStatement pst = con.prepareStatement(sql);
pst.setInt(1, 1);
// 3.得到結果集
ResultSet rs = pst.executeQuery();
// 4.遍歷結果集
if (rs.next()) {
Reader r = rs.getCharacterStream("content");
FileWriter fw = new FileWriter("d:/筆記.txt");
int len = -1;
char[] ch = new char[1024 * 100];
while ((len = r.read(ch)) != -1) {
fw.write(ch, 0, len);
fw.flush();
}
fw.close();
r.close();
}
pst.close();
con.close();
}
}
JDBC批處理
業務場景:當需要向數據庫發送一批SQL語句執行時,應避免向數據庫一條條的發送執行,而應採用JDBC的批處理機制,以提升執行效率。
實現批處理有兩種方式,第一種方式:
- Statement.addBatch(sql)
- executeBatch()方法:執行批處理命令
- clearBatch()方法:清除批處理命令
採用Statement.addBatch(sql)方式實現批處理:
- 優點:可以向數據庫發送多條不同的SQL語句。
- 缺點:
- SQL語句沒有預編譯。
- 當向數據庫發送多條語句相同,但僅參數不同的SQL語句時,需重複寫上很多條SQL語句。例如:
- Insert into user(name,password) values(‘aa’,’111’);
- Insert into user(name,password) values(‘bb’,’222’);
- Insert into user(name,password) values(‘cc’,’333’);
- Insert into user(name,password) values(‘dd’,’444’);
實現批處理的第二種方式
- PreparedStatement.addBatch()
- addBatch();
- executeBatch();
- clearBatch();
- PreparedStatement.addBatch()
採用PreparedStatement.addBatch()實現批處理
- 優點:發送的是預編譯後的SQL語句,執行效率高。
- 缺點:只能應用在SQL語句相同,但參數不同的批處理中。因此此種形式的批處理經常用於在同一個表中批量插入數據,或批量更新表的數據。
兩個對象執行批處理區別?
- 1.Statement它更適合執行不同sql的批處理。它沒有提供預處理功能,性能比較低。
- 2.PreparedStatement它適合執行相同sql的批處理,它提供了預處理功能,性能比較高。
- eg:第一種方式
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
String sql1 = "insert into person(name,password,email,birthday)
values('kkk','123','[email protected]','1978-08-08')";
String sql2 = "update user set password='123456' where id=3";
st = conn.createStatement();
st.addBatch(sql1); //把SQL語句加入到批命令中
st.addBatch(sql2); //把SQL語句加入到批命令中
st.executeBatch();
} finally{
JdbcUtil.free(conn, st, rs);
}
- eg:第二種方式
conn = JdbcUtil.getConnection();
String sql = "insert into person(name,password,email,birthday) values(?,?,?,?)";
st = conn.prepareStatement(sql);
for(int i=0;i<50000;i++){
st.setString(1, "aaa" + i);
st.setString(2, "123" + i);
st.setString(3, "aaa" + i + "@sina.com");
st.setDate(4,new Date(1980, 10, 10));
st.addBatch();
if(i%1000==0){
st.executeBatch();
st.clearBatch();
}
}
st.executeBatch();
- 注意;mysql默認情況下,批處理中的預處理功能沒有開啓,需要開啓
- 1.在 url下添加參數
- url=jdbc :mysql :///day17?
useServerPrepStmts=true&cachePrepStmts=true&rewriteBatchedStatements=true
- url=jdbc :mysql :///day17?
- 2.注意驅動版本
- Mysql驅動要使用mysql-connector-java-5.1.13以上
- 1.在 url下添加參數
- 作業:
- 1.註冊+登錄案例
採用dao模式 使用PreparedStatement操作
2.使用PreparedStatement完成CRUD
客戶信息表DAO編寫
- 創立如下數據庫表customer,並編寫DAO進行crud操作