java 資料庫程式設計(一)JDBC連線Sql Server資料庫
一、JDBC簡介
java資料庫連線技術(Java Database Connection,JDBC)是由java提供的一組與平臺無關的資料庫的操作標準,其本身由一類與介面組成,並且在操作中將按照嚴格的順序執行。由於資料庫屬於資源操作,所以所有的資料庫操作的最後必須要關閉資料庫連線。
下面為大家介紹JDBC的四種驅動,主要是為了普及一下知識,心急的小夥伴可以直接跳過,我們講解的是JDBC本地驅動。
1.JDBC-ODBC橋接技術
Windows中的開放資料庫連線(Open Database Connectivity,ODBC)是由微軟提供的資料庫程式設計介面。JDBC-ODBC橋接技術是先利用ODBC技術作為資料庫的連線方式,再利用JDBC進行ODBC的連線,以實現資料庫的操作。此類操作由於中間會使用ODBC,所以效能較差,但是此種方式不需要任何第三方開發包配置,所以使用較為方便。
2.JDBC本地驅動(本文講解此方法)
JDBC本地驅動是由不同的資料庫生產商根據JDBC定義的操作標準實現各自的驅動程式,程式可以直接透過JDBC進行資料庫的連線操作。該操作效能較高,但是需要針對不同的資料庫配置與之匹配。
3.JDBC網路驅動
JDBC網路驅動將利用特定的資料庫連線協議進行資料庫的網路連線,這樣可以連線任何一個指定伺服器的資料庫,使用起來較為靈活,在實際開發中被廣泛使用。
4.JDBC協議驅動
JDBC協議驅動是利用JDBC提供的協議標準,將資料庫的操作以特定的網路協議的方式進行處理。
二、連線前配置
在連線資料庫之前要進行一些Sql Server配置。
1.開啟Sql Server配置管理器。
資料庫版本 檔案所在位置
Sql Server 2016 C:\Windows\SysWOW64\SQLServerManager13.msc
Sql Server 2014 C:\Windows\SysWOW64\SQLServerManager12.msc
Sql Server 2012 C:\Windows\SysWOW64\SQLServerManager11.msc
Sql Server 2008 C:\Windows\SysWOW64\SQLServerManager10.msc
根據上表種對應的版本找到相應檔案的啟動位置開啟配置管理器。
也可以根據對應版本直接在微軟小娜種搜尋配置管理器名稱,如:SQLServerManager10.msc 進行開啟。
2.開啟TCP/IP協議
找到你的Sql Server例項,雙擊開啟TCP/IP協議,檢視埠號。預設為1433,我的之前改過為1909。如果TCP/IP協議顯示禁用,要將其啟用。
3.修改Sql Server登陸設定
開啟Sql Server,右擊資料庫例項名,點選屬性,進入安全性選項。將伺服器身份驗證模式改為Ser Server和Windows驗證模式(s)並修改超級管理員sa的密碼,相信使用過Sql Server的小夥伴都進行過這項設定。以前改過的就可以跳過了。
找到安全性->登入名->sa,右鍵選擇屬性可以更改密碼
然後選擇狀態,設定允許連線到資料庫引擎
Sql Server配置到此結束,下面到微軟官網下載所需JDBC庫
https://www.microsoft.com/zh-CN/download/details.aspx?id=11774
解壓後找到jre資料夾,如果你的JDK是1.80以上的就使用jre8裡面的sqljdbc42.jar,如果是1.80以下的就使用jre7裡面的sqljdbc41.jar
進入eclipse,右鍵當前工程檔案,選擇Properties,找到Java Build Path下面的Libraries,然後點選Add External JARs,根據JDK版本選擇sqljdbc42.jar或sqljdbc41.jar,最後點選Apply And Close。連線前的配置工作到這裡就結束了。
三、連線資料庫
正如我們介紹JDBC時所說的,本篇文章針對的是本地驅動,因此需要先透過反射載入資料庫驅動程式,然後透過DriverManager類根據指定的資料庫連線地址、使用者名稱、密碼就可以取得資料庫連線了。下面會在程式中詳細介紹
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Test02 {
//SQLServer本地驅動的地址
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
//連線sqlserver資料庫;本地連線;透過1909號埠號連線(根據你自身資料庫的埠號來),
資料庫名稱DBMS
//你需要現在Sql Server客戶端上建立一個資料庫
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";//資料庫使用者名稱
private static final String PASSWORD = "1097542073";//資料庫密碼
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
System.out.println(conn);//輸出資料庫連線
}
}
注:執行此程式碼時需保證Sql Server資料庫是開啟的並且已登陸,否則連誰呢
執行程式碼後輸出以下字樣則證明已連線成功,如果想了解更多資料庫操作請閱讀java資料庫程式設計
(二) 資料庫操作
java資料庫程式設計(二) 資料庫操作
今天首先為大家介紹一下資料庫的連線及操作的核心類與介面,使大家對資料庫操作有一個總體的把握,防止片面學習。
核心類和介面
名稱 描述
Java.sql.DriverManagers類 提供資料庫的驅動管理,主要負責資料庫的連線物件取得
Java.sql.Connection介面 用於描述資料庫的連線,並且可以透過此介面關閉連線
Java.sql.Statement介面 資料庫的操作介面,透過連線物件開啟
Java.sql.PreparedStatement介面 資料庫預處理操作介面,透過連線物件開啟
Java.sql.ResultSet介面 資料查詢結果集描述,透過此介面獲得查詢結果
注:4個JDBC核心介面中都提供了close()方法,但是隻要連線關閉,所有的操作就自然進行資源釋放,因此只需要呼叫Connection介面的close()方法就可以釋放全部資源。
1.Connection介面
用於取得資料庫連線(為後續的資料庫操作做準備)及資源的釋放。
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectionTest {
//SQLServer本地驅動的地址
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
//連線sqlserver資料庫;本地連線;透過1909號埠號連線(根據你自身資料庫的埠號來),資料庫名稱DBMS
//你需要現在Sql Server客戶端上建立一個資料庫
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";//資料庫使用者名稱
private static final String PASSWORD = "1097542073";//資料庫密碼
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
System.out.println(conn);//輸出資料庫連線
conn.close();//關閉資料庫
}
}
2.Statement介面
當取得了資料庫連線物件後,就意味著可以進行資料庫操作了,而資料庫中的資料庫操作可以使用Statement介面完成。
如果要取得Statement介面的例項化物件則需要依靠Connection介面提供的方法完成。
Statement
序號 名稱 描述
1 public Statement createStatement() throws SQLException 取得Statement介面物件
2 public int executeUpdate(String sql) throws SQLException 資料更新,返回影響行數
3 public ResultSet executeQuery(String sql) throws SQLException 資料查詢,返回ResultSet結果集
(a)建立表
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class Test01 {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
//建表語句,有id、title和price三個屬性其中id是主鍵且設定為自增長。此句屬於SQL語句,不懂的小夥伴可以照抄
String createTable = "CREATE TABLE book(id int PRIMARY KEY IDENTITY(1,1),"
+ "title varchar(25) NOT NULL,"
+ "price DECIMAL)";
int len = statement.executeUpdate(createTable);//返回受影響行數
System.out.println("建表成功,影響的資料行數:" + len);
conn.close();//關閉連線,釋放資源
}
}
執行成功後可以到SQL Server中的DBMS資料庫中看到book表且其內部為空。
(b)新增資料
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class AddTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
String sql = "INSERT INTO book(title,price) VALUES('Effective',88)";
int len = statement.executeUpdate(sql);
System.out.println("插入成功,影響的資料行數:" + len);
sql = "INSERT INTO book(title,price) VALUES('java第一行程式碼',79.8)";
len = statement.executeUpdate(sql);
System.out.println("插入成功,影響的資料行數:" + len);
sql = "INSERT INTO book(title,price) VALUES('Android第一行程式碼',77)";
len = statement.executeUpdate(sql);
System.out.println("插入成功,影響的資料行數:" + len);
conn.close();
}
}
執行成功後顯示
因為每次只插入一條資料,所以每次隻影響1行。重新整理後到SQL Server中重新開啟book表可以看到插入的資料
注:右鍵表名->編輯前200行可以看到上圖中圖形化的表
(c)更新資料
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class UpdataTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
String sql = "UPDATE book set price=79 where title='Android第一行程式碼'";
int len = statement.executeUpdate(sql);
System.out.println("修改資料,影響的資料行數:" + len);
conn.close();//關閉資料庫
}
}
開啟SQL Server中的book表,可以發現Android第一行程式碼的價格從77變為79
(d)刪除資料
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class DeleteTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
String sql = "DELETE FROM book WHERE title='Effective'";
int len = statement.executeUpdate(sql);
System.out.println("刪除資料,影響的資料行數:" + len);
conn.close();//關閉資料庫
}
}
對比刪除前後的book表,注意此時只剩下id為2和3的記錄
(e)查詢資料
透過程式碼發現上面幾種操作方式基本無異,都是獲取Statement物件之後,呼叫其executeUpdate()方法執行SQL語句。查詢操作稍有不同,也不過是把executeUpdate()方法改為executeQuery()方法,並且使用ResultSet進行接收。
在java.sql.ResultSet介面裡面定義了一下兩種方法。
ResultSet
序號 名稱 描述
1 public boolean next() throws SQLException 向下移動指標並判斷是否有資料行
2 getInt()、getDouble()、getString()、getDate() 取出不同型別的數列內容
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class QueryTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();//取得Statement物件
String sql = "SELECT * FROM book";
ResultSet rs = statement.executeQuery(sql);//使用ResultSet接收資料
while(rs.next()) {
String title = rs.getString("title");//根據屬性列名稱獲取書名
double price = rs.getDouble("price");//根據屬性列名稱獲取價格
System.out.println(title + "-->" + price);//輸出
}
conn.close();//關閉資料庫
}
}
如果感覺每次都要透過屬性列名稱查詢比較麻煩還可以透過以下方式查詢
String sql = "SELECT * FROM book";
ResultSet rs = statement.executeQuery(sql);
while(rs.next()) {//判斷下一行是否有資料
int index = rs.getInt(1);//第一個屬性列
String title = rs.getString(2);//第二個屬性列
double price = rs.getDouble(3);//第三個屬性列
System.out.println(index + "\t" + title + "\t" + price);//輸出
}
輸出結果,知識輸出的時候控制格式不同而已,輸出的資料是一樣的。
3.PreparedStatement介面
我們在實際的開發中絕大多數會只用拼湊SQL語句的方式進行資料庫操作,如果變數中含有”’”或者“”“等用於定義資料庫操操作語句的符號的話,必定會產生錯誤,而其在變數中又很難對其進行轉義。為了解決Statement介面中的這種缺陷,就引入了PreparedStatement介面。
PreparedStatement屬於Statement的子介面,但是如果要取得該子介面的例項化物件,依然需要使用Connection所提供的方法:public PreparedStatement preparedStatement(String sql) throws SQLException。
此方法需要傳入一個SQL語句,這個SQL是一個具備特殊標記的完整SQL,但是此時沒有內容,所有的內容都會以佔位符“?“的形式出現,而當取得了PreparedStatement介面物件後需要使用一系列setXxx()方法為指定編號(根據”?”從1開始排序)的佔位符設定具體內容。
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
public class PreparedStatementTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
String sql = "INSERT INTO book(title,price) VALUES(?,?)";
//獲取PreparedStatement物件
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, "Effective java");//設定第一個屬性列引數
preparedStatement.setDouble(2, 39);//設定第二個屬性列引數
int len = preparedStatement.executeUpdate();
System.out.println("插入成功,影響的資料行數:" + len);
conn.close();//關閉連線
}
}
透過程式碼發現其實和Statement用法沒有太大區別,只是多了佔位符而已。學過SQL的小夥伴肯定對佔位符再熟悉不過了,插入資料正常。
批處理與事務處理
所謂批處理指的是一次性向資料庫中發出多條操作命令,而後所有的SQL語句將一起執行。在Statement介面與PreparedStatement介面中都有關於批處理的操作。
Statement介面定義的方法:
增加批處理語句:public void addBatch(String sql) throws SQLException
執行批處理:public int[] executeBatch() throws SQLException
PreparedStatement介面定義的方法
增加批處理語句:public void addBatch(String sql) throws SQLException
執行批處理:public int[] executeBatch() throws SQLException
執行批處理(以Statement介面為例)
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
public class Test {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
//新增批處理語句
statement.addBatch("INSERT INTO book(title,price) VALUES('Effective',88)");
statement.addBatch("INSERT INTO book(title,price) VALUES('java第一行程式碼',79.8)");
statement.addBatch("INSERT INTO book(title,price) VALUES('Effective',88)");
//執行批處理語句
int[] results = statement.executeBatch();//執行批處理
System.out.println("插入成功,影響的行數分別為:" + Arrays.toString(results));
conn.close();
}
}
在正常情況下批處理描述的一定是一組關聯的SQL操作,而如果執行多條更新語句中有一條語句出現了錯誤,那麼理論上所有的語句都不應該被更新。不過預設情況下在錯誤語句之前的SQL更新都會正常執行,而出錯之後的資訊並不會執行。為了實現對批次處理操作的支援,可以使用事務來進行控制。
JDBC提供事務處理來進行手工的事務控制,所有的操作方法都在Connection介面裡定義。
事務
序號 名稱 描述
1 public void commit() throws SQLException 事務提交
2 public void rollback() throws SQLException 事務回滾
3 public void setAutoCommit(boolean autoCommit)
throws SQLException 設定是否為自動提交
利用事務處理
package com.tjut.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
public class BatchTest {
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String DBURL = "jdbc:sqlserver://localhost:1909;databaseName=DBMS";
private static final String USER = "sa";
private static final String PASSWORD = "1097542073";
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//第三步:進行資料庫的資料操作
Statement statement = conn.createStatement();
conn.setAutoCommit(false);//取消自動提交
try {
//新增批處理語句
statement.addBatch("INSERT INTO book(title,price) VALUES('Effective java',88)");
statement.addBatch("INSERT INTO book(title,price) VALUES('java第一行程式碼',79.8)");
statement.addBatch("INSERT INTO book(title,price) VALUES('Android第一行程式碼',88)");
//執行批處理語句
int[] results = statement.executeBatch();//執行批處理
System.out.println("插入成功,影響的行數分別為:" + Arrays.toString(results));
conn.commit();//如果沒有錯誤,進行提交
} catch (SQLException e) {
e.printStackTrace();
conn.rollback();//如果批處理中出現異常,則進行回滾
}
conn.close();//關閉資料庫連線
}
}
讀取ms sqlserver資料內容 示例如下:
package pkg;
import java.sql.Connection;
import java.sql.DriverManager;
//import java.sql.SQLException;
import java.sql.ResultSet;
import java.sql.PreparedStatement;
//import java.sql.Statement;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Main {
//SQLServer本地驅動的地址
private static final String DBDRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
//連線sqlserver資料庫;本地連線;透過1433號埠號連線(根據你自身資料庫的埠號來),資料庫名稱DBMS
//你需要現在Sql Server客戶端上建立一個資料庫
private static final String DBURL = "jdbc:sqlserver://localhost:1433;databaseName=fkxt";
private static final String USER = "sa";//資料庫使用者名稱
private static final String PASSWORD = "Wsyqjjxt-Pass-9";//資料庫密碼
public static void main(String[] args) throws Exception {
//第一步:載入資料庫驅動程式,此時不需要例項化,因為會由容器自己負責
Class.forName(DBDRIVER);
//第二步:根據連線協議、使用者名稱、密碼連線資料庫
Connection conn = DriverManager.getConnection(DBURL,USER,PASSWORD);
//System.out.println(conn);//輸出資料庫連線
//Statement statement = conn.createStatement();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String str1 = "2021-01-01";
String str2 = "2021-01-31";
Date starDate = sdf.parse(str1);
Date endDate = sdf.parse(str2);
String sql = "SELECT * FROM htxx where htrq between ? and ? ";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, sdf.format(starDate));//設定第一個屬性列引數
preparedStatement.setString(2, sdf.format(endDate));//設定第一個屬性列引數
ResultSet rs = preparedStatement.executeQuery( );//使用ResultSet接收資料
while(rs.next()) {
String htbh = rs.getString("htbh");//根據屬性列名稱獲取 合同編號
Date htrq = rs.getDate("htrq");//根據屬性列名稱獲取 合同日期
double htbz = rs.getDouble("htsl");//根據屬性列名稱獲取 合同數量
System.out.println(htbh + " --> "+ sdf.format(htrq) +" --> " + htbz);//輸出
}
conn.close();
}
} //main