Web全堆疊~30.JDBC
上一期
JDBC:
JDBC(Java DataBase Connectivity, Java資料庫連接) ,是一種用于執行SQL陳述句的Java API,為多種關系資料庫提供統一訪問,它由一組用Java語言撰寫的類和介面組成,有了JDBC,程式員只需用JDBC API寫一個程式,就可訪問所有資料庫,
SUN公司是規范制定者,制定了規范JDBC(連接資料庫規范)
DriverManager類
作用:管理各種不同的JDBC驅動
Connection介面
Statement介面和PreparedStatement介面
ResultSet介面
資料庫廠商微軟、甲骨文等分別提供實作JDBC介面的驅動jar包 程式員學習JDBC規范來應用這些jar包里的類,
JDBC訪問資料庫的步驟:
加載一個Driver驅動
創建資料庫連接(Connection)
創建SQL命令發送器Statement
通過Statement發送SQL命令并得到結果
處理結果(select陳述句)
關閉資料庫資源ResultSet Statement Connection
加載Driver驅動
使用反射加載驅動,其實就是獲得一個類的位元組碼,在獲得類的位元組碼的程序中,一定會加載類進入記憶體,一旦進入記憶體會執行代碼中的靜態代碼塊,一執行代碼塊,就會自動的向DriverManager中注冊一個驅動
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
mysql8 之前的資料庫驅動名 com.mysql.jdbc.Driver
mysql8 開始的資料庫驅動 com.mysql.cj.jdbc.Driver
通過DriverManager獲得鏈接
url 同一資源定位符
協議 jdbc:mysql:
ip地址 127.0.0.1/localhost
url 同一資源定位符
埠號 3306
具體的資源路徑 mydb
mysql8之前: jdbc:mysql://127.0.0.1:3306/mydb
mysql8開始: jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
useSSL=false 不使用SSL加密機制
&useUnicode=true 使用unicode字符集
&characterEncoding=utf8 使用utf8作為通信字符集
&serverTimezone=Asia/Shanghai 確定時區為 Asia/Shanghai
其中的mydb指的是資料庫名,可以根據需求修改
使用JDBC完成添加操作
public static void insert(){
Connection connection = null;
Statement statement = null;
try {
//1:加載一個Driver驅動
Class.forName("com.mysql.cj.jdbc.Driver");
//2:創建資料庫連接(Connection)
String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String uid = "root"; //賬號
String pwd = "root"; //密碼
connection = DriverManager.getConnection(url,uid,pwd);
//創建SQL命令發送器
statement = connection.createStatement();
// 向資料庫發送陳述句 資料庫執行完畢后 回傳引數
int n = statement.executeUpdate("insert into student values('689845','黃貴根','656972','資訊工程學院',666)");
if(n > 0){
System.out.println("資料添加成功!");
}else{
System.out.println("資料添加失敗!");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally{
//關閉處理
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
從上述代碼中不難發現,僅僅只是實作添加這么一個操作,就需要如此多的代碼,細想,如果要寫多個增刪改的操作,難道每次都要寫這么多行的代碼嘛?
所以一般到了這個時候,我們就需要一個工具類,來簡化,
撰寫DBUtil工具類
public class DBUtil {
//資料庫的連接的靜態方法
public static Connection getConnection(){
String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String uid = "root"; //賬號
String pwd = "root"; //密碼
Connection connection = null;
Statement statement = null;
//1:加載一個Driver驅動
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(url,uid,pwd);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
//關閉處理
public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
//關閉處理
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
這個時候我們只需要直接呼叫,就可以省略很多的代碼
public static void insert(){
Connection connection = null;
Statement statement = null;
try {
connection = DBUtil.getConnection();
//創建SQL命令發送器
statement = connection.createStatement();
// 向資料庫發送陳述句 資料庫執行完畢后 回傳引數
int n = statement.executeUpdate("insert into student values('689845','黃貴根','656972','資訊工程學院',666)");
if(n > 0){
System.out.println("資料添加成功!");
}else{
System.out.println("資料添加失敗!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
DBUtil.CloseAll(connection,statement,null);
}
}
這樣子添加看似好像沒問題,而且也已經很簡化了,可是再想想,假如我要換一個表,或者說我不想添加操作了,我要修改或者洗掉,怎么辦?重復寫不麻煩嘛?所以這個時候,我們就需要擴展一下DBUtil工具類了
擴展DBUtil
public static int executeUpdate(String sql,Object [] params) {
Connection conn = null;
PreparedStatement pstmt = null;
int n = 0;//添加失敗
try {
//2.建立和資料庫的連接
conn = getConnection();
//3.創建一個SQL命令發送器
pstmt = conn.prepareStatement(sql);
//4.準備好SQL陳述句,通過SQL命令發送器發送給資料庫,并得到結果
for (int i = 0; i <params.length ; i++) {
pstmt.setObject(i+1, params[i]);
}
n = pstmt.executeUpdate();
//System.out.println(n);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.關閉資源
CloseAll(conn,pstmt,null);
}
return n;
}
這個時候我們再添加資料,實際上只需要三行代碼就可以實作了,即使是換了個資料庫表或者其他操作,也無需重復寫代碼
public static void InsertPlus(){
//三行代碼即可完成
String sql = "insert into student value(?,?,?,?,?)";
Object []objects = {"689845","黃貴根","656972","資訊工程學院",666.0};
int n = DBUtil.executeUpdate(sql,objects);
if(n > 0){
System.out.println("資料添加成功!");
}else{
System.out.println("資料添加失敗!");
}
}
洗掉行不行呢?試試唄~
String sql = "delete from student where realname = ?";
Object []objects = {"黃貴根"};
int n = DBUtil.executeUpdate(sql,objects);
JDBC常見例外
Exception in thread "main"java.lang.ClassNotFoundException: com.mysql.jdbc2.Driver
原因:沒有添加jar包或者com.mysql.jdbc2.Driver路徑錯誤
Exception in thread "main" java.sql.SQLException: No suitable driver found for jbdc:mysql://127.0.0.1:3306/stumgr
url錯誤
Exception in thread "main" java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
原因:用戶名或者密碼錯誤
Exception in thread "main" com.mysql.jdbc.exceptions .jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry '90' for key 'PRIMARY'
原因:主鍵沖突
使用JDBC完成查詢操作
需求:查詢所有資訊工程學院的學生
創建學生物體類(get set就不寫在文章里面了,自行添加,):
public class Student {
private String son; //學號
private String realname; //姓名
private String password; //密碼
private String classname; //院系
private Double score; //總成績
}
查詢操作
public static List<Student> FindAll(){
Connection connection = DBUtil.getConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
//創建List集合來接收資料
List<Student> list = new ArrayList<>();
try {
preparedStatement = connection.prepareStatement("select * from student where classname = ?");
//1表示第一個占位符,也就是?, 而不是資料庫里面的第幾個欄位
preparedStatement.setString(1,"資訊工程學院");
//接收結果
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
//后面對應的是資料庫里面的欄位名
String son = resultSet.getString("son");
String realname = resultSet.getString("realname");
String password = resultSet.getString("password");
String classname = resultSet.getString("classname");
Double score = resultSet.getDouble("score");
//存到物體類
Student student = new Student(son,realname,password,classname,score);
//存到集合
list.add(student);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
測驗
public static void main(String[] args) {
//測驗
List<Student> list = FindAll();
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
這個時候我們發現,每個資料庫里面的欄位,都要定義一個相應的變數來接收,這么做很不方便,怎么辦呢?那我們就來擴展一下DBUtil工具類吧,
擴展DBUtil工具類
public static <T> List<T> baseQuery(T t, String sql, Object ... args){
// 獲取list集合中要裝的物件的位元組碼
Class aClass = t.getClass();
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
List<T> list = null;
try {
connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql);
// 設定引數的程序
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
set = statement.executeQuery();
// 獲取全部的欄位
Field[] fs = aClass.getDeclaredFields();
// 先設定屬性可以訪問
for(Field f:fs){
f.setAccessible(true);
}
list=new ArrayList<>();
while(set.next()){
// 創建物件
T element = (T)aClass.newInstance();
// 從結果集的一條資料中取出每個欄位的資訊,放入element物件上去
// 遍歷fs 通過屬性名 去結果集中獲取資料
for(Field f:fs){
String name = f.getName();
Object value=null;
// 判斷物體類屬性的資料型別,選擇對應的get方法
if(f.getType()==int.class){
value = set.getInt(name);
}else if(f.getType()==double.class){
value = set.getDouble(name);
}else if(f.getType()==boolean.class){
value = set.getBoolean(name);
}else{
value= set.getObject(name);
}
f.set(element,value);
}
list.add(element);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseAll(connection,statement,set);
}
return list;
}
有了這個工具類之后,我們幾乎只需要一行代碼,就可以兼容多種查詢的操作方法
測驗:
public static void FindAllPlus(){
//查詢所有資訊工程學院的學生
String sql = "select * from student where classname = ?";
//這個時候幾乎一行代碼就可以完成操作
List<Student> list = DBUtil.baseQuery(new Student(),sql,"資訊工程學院");
Iterator iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
怎么樣?是不是簡化好多了~
最終代碼
DBUtil工具類
public class DBUtil {
//資料庫的連接的靜態方法
public static Connection getConnection(){
String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
String uid = "root"; //賬號
String pwd = "root"; //密碼
Connection connection = null;
Statement statement = null;
//1:加載一個Driver驅動
try {
Class.forName("com.mysql.cj.jdbc.Driver");
connection = DriverManager.getConnection(url,uid,pwd);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
//關閉處理
public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
//關閉處理
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet != null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static int executeUpdate(String sql,Object [] params) {
Connection conn = null;
PreparedStatement pstmt = null;
int n = 0;//添加失敗
try {
//2.建立和資料庫的連接
conn = getConnection();
//3.創建一個SQL命令發送器
pstmt = conn.prepareStatement(sql);
//4.準備好SQL陳述句,通過SQL命令發送器發送給資料庫,并得到結果
for (int i = 0; i <params.length ; i++) {
pstmt.setObject(i+1, params[i]);
}
n = pstmt.executeUpdate();
//System.out.println(n);
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6.關閉資源
CloseAll(conn,pstmt,null);
}
return n;
}
public static <T> List<T> baseQuery(T t, String sql, Object ... args){
// 獲取list集合中要裝的物件的位元組碼
Class aClass = t.getClass();
Connection connection = null;
PreparedStatement statement = null;
ResultSet set = null;
List<T> list = null;
try {
connection = DBUtil.getConnection();
statement = connection.prepareStatement(sql);
// 設定引數的程序
for (int i = 0; i < args.length; i++) {
statement.setObject(i + 1, args[i]);
}
set = statement.executeQuery();
// 獲取全部的欄位
Field[] fs = aClass.getDeclaredFields();
// 先設定屬性可以訪問
for(Field f:fs){
f.setAccessible(true);
}
list=new ArrayList<>();
while(set.next()){
// 創建物件
T element = (T)aClass.newInstance();
// 從結果集的一條資料中取出每個欄位的資訊,放入element物件上去
// 遍歷fs 通過屬性名 去結果集中獲取資料
for(Field f:fs){
String name = f.getName();
Object value=null;
// 判斷物體類屬性的資料型別,選擇對應的get方法
if(f.getType()==int.class){
value = set.getInt(name);
}else if(f.getType()==double.class){
value = set.getDouble(name);
}else if(f.getType()==boolean.class){
value = set.getBoolean(name);
}else{
value= set.getObject(name);
}
f.set(element,value);
}
list.add(element);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseAll(connection,statement,set);
}
return list;
}
}
使用工具類完成操作
public static List<Student> FindAllPlus(){
//查詢所有資訊工程學院的學生
String sql = "select * from student where classname = ?";
//這個時候幾乎一行代碼就可以完成操作
List<Student> list = DBUtil.baseQuery(new Student(),sql,"資訊工程學院");
return list;
}
public static void InsertPlus(){
//三行代碼即可完成
String sql = "insert into student value(?,?,?,?,?)";
Object []objects = {"689845","黃貴根","656972","資訊工程學院",666.0};
int n = DBUtil.executeUpdate(sql,objects);
}
然而即使如此,我們未來將還會有更優質的解決方案可以使用,這就等我們接下來學Mybatis之后就知道了,下期再見~
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/256408.html
標籤:其他
上一篇:imi在虎撲上億資料遷移實踐
