02.SSM框架集~再談JDBC?
本文是上一篇文章的後續,詳情點擊該鏈接~
jar包提取碼:1asg
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之後就知道了。下期再見~