# 一、使用JDBC批量添加 ## 知識點複習: 1、JDBC的六大步驟 (導入jar包, 載入驅動類,獲取連接對象, 獲取sql執行器、執行sql與並返回結果, 關閉資料庫連接) 2、封裝了一個DBUtil 類, 通過讀取屬性文件的方式獲取 基礎連接信息。 3、批量添加: 一次性可執行多 ...
一、使用JDBC批量添加
知識點複習:
1、JDBC的六大步驟 (導入jar包, 載入驅動類,獲取連接對象, 獲取sql執行器、執行sql與並返回結果, 關閉資料庫連接)
2、封裝了一個DBUtil 類, 通過讀取屬性文件的方式獲取 基礎連接信息。
3、批量添加: 一次性可執行多個添加記錄 ,將多個sql語句在當前這次連接中執行完畢。
// 設置部門集合
List<Dept> list = new ArrayList<>();
list.add(new Dept(60,"市場部","武漢市"));
list.add(new Dept(70,"研發部","武漢市"));
list.add(new Dept(80,"教學部","武漢市"));
//通過DBUtil獲取資料庫連接
Connection conn = DBUtil.getConn();
String sql="insert into dept(deptno,dname,loc) values (?,?,?)";
//獲取預編譯sql執行器
PreparedStatement ps = conn.prepareStatement(sql);
//批量設置該條sql語句的 參數
for(Dept dept : list){
//設置參數
ps.setInt(1,dept.getDeptno());
ps.setString(2,dept.getDname());
ps.setString(3,dept.getLoc());
// 將設置好的參數 先放入批量添加的容器中
ps.addBatch();
// 對於完整的sql語句 可以用有參的
// ps.addBatch(sql);
}
// 執行sql語句 返回每一行sql語句影響的行數 ,
int [] counts = ps.executeBatch();
System.out.println("結果長度:"+ counts.length);
System.out.println("結果:"+ Arrays.toString(counts));
//關閉sql語句
DBUtil.closeAll(conn,ps,null);
二、結果集的元數據:
columnCount 結果集的列數
columnName 列的名稱 // select columnName as columnLabel…
columnLabel 列的別名(label)
columnClassName 列在Java中對應的類型(可配合Class.forName(String className)獲取Class類型的返回值)
columnType 列在資料庫中的類型(數值編號)
columnTypeName 列在資料庫中的類型名稱
columnDisplaySize 列大小
結果集(ResultSet)和結果集元數據(ResultSetMetaData)同為JDBC標準中的介面|標準。
java.sql.ResultSet
java.sql.ResultSetMetaData
三、Class反射
1、為什麼需要使用反射
由於之前創建對象的過程 ,是已知這個類,然後對類進行編譯,編譯通過之後才可以創建對象, 現在可能出現 “未知的類” 只有“包名+類名” ,在運行期間才知道 該類是否存在,並動態創建該類的對象。 這時 創建對象的過程 可以通過反射的方式 完成。
反射機制的定義: 對於任意一個類,都可以在運行期間,動態的創建該類的對象,能知曉該對象的屬性和方法,並動態調用屬性 和方法 ,這個過程就是Java的反射機制
對於任意類 都存在一個該類的Class類型 ,如何獲取類的Classs類型
方式一: Class cls = Class.forName("類的全類名")
方式二: Class cls = 類名.class;
方式三: Class cls = 類的對象名.getClass()
常用API
Construct:
cls.getConstructor(int.class , String.class); 根據參數類型和個數 獲取cls 對應的 構造器對象
Field : 屬性對應的類型
getDeclareFields () : 獲取所有聲明的屬性 (包括 任何修飾符,不包括private修飾)
getFields(): 獲取所有聲明的public修飾的屬性
getDeclareFiled(String name): 根據屬性名獲取屬性對象
getField(String name):根據屬性名獲取屬性對象 (必須是共有的 )
Method : 方法對應的類型
getDeclaredMethods() : 返回當前類的自己聲明的方法
getMethods() :返回所有的方法(包括父類的)
invoke(obj,參數值) :調用該方法
getMethod(“方法名” ,參數值):根據方法名返回Method
四、反射封裝(增刪改查)
preparedStatement的作用:
1、提前傳入sql,執行的時候,不傳入sql
2、支持傳入sql中的參數
3、解決sql註入邏輯漏洞
4、提高執行效率
Object ...params(可變形參數組) 作用:在調用函數時,可以傳入任意個任意類型的參數
標題查詢多行的封裝
//查詢多行多列
public static <T> List<T> list(String sql,Class<T> c,Object...params){
//創建一個集合,存放所有的對象
List<T> tList=new ArrayList<>();
try {
//1、註冊驅動-反射去載入jar包中com.mysql.jdbc.Driver這個類中的 DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、獲取連接對象
var conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer-camp2023?characterEncoding=utf8", "root", "admin");
//3、定義sql
//4、需要創建statement
var st = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
st.setObject(i+1,params[i]);
}
//5、statement 執行sql,返回 結果集
var rs = st.executeQuery();
//結果集rs得到結果集元數據
ResultSetMetaData md=rs.getMetaData();
//獲取結果集總列數
var columnCount = md.getColumnCount();
//6、解析rs
while (rs.next()) {//rs.next 讀取結果集的游標向下移動一行,游標預設在哪一行,列名所在的那一行
//根據每一行數據,封裝成一個實體對象
T t = c.newInstance();
// 1、取出某一行的每個數據,封裝到對象t的屬性中
for (int i = 1; i <= columnCount; i++) {
//通過列的序號,獲取每一列的值
var value = rs.getObject(i);
if (value!=null){
//通過列的序號,獲取每一列的列名
var columnName = md.getColumnName(i);
//因為列名和實體類t中的屬性名一致,為每一個屬性構造一個反射中的set方法
var f = c.getDeclaredField(columnName);
//賦予私有屬性的賦值許可權
f.setAccessible(true);
//使用反射,把value給到對象t的屬性中
f.set(t,value);//理解為:把value賦值給對象t的ColumName,相當於set方法
}
}
//把對象存入集合中
tList.add(t);
}
//7、關閉資源
st.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return tList;
}
查詢一行的封裝
//查詢一行
public static <T> T selectRow(String sql,Class<T> c,Object...params){
//創建一個集合,存放所有的對象
List<T> tList=new ArrayList<>();
try {
//1、註冊驅動-反射去載入jar包中com.mysql.jdbc.Driver這個類中的 DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、獲取連接對象
var conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer-camp2023?characterEncoding=utf8", "root", "admin");
//3、定義sql
//4、需要創建statement
var st = conn.prepareStatement(sql);
//執行前給sql傳遞參數
for (int i = 0; i < params.length; i++) {
st.setObject(i+1,params[i]);
}
//5、statement 執行sql,返回 結果集
var rs = st.executeQuery();
//結果集rs得到結果集元數據
ResultSetMetaData md=rs.getMetaData();
//獲取結果集總列數
var columnCount = md.getColumnCount();
//根據每一行數據,封裝成一個實體對象
//6、解析rs
T t=null;
if (rs.next()) {//rs.next 讀取結果集的游標向下移動一行,游標預設在哪一行,列名所在的那一行
t = c.newInstance();
// 1、取出某一行的每個數據,封裝到對象t的屬性中
for (int i = 1; i <= columnCount; i++) {
//通過列的序號,獲取每一列的值
var value = rs.getObject(i);
if (value!=null){
//通過列的序號,獲取每一列的列名
var columnName = md.getColumnName(i);
//因為列名和實體類t中的屬性名一致,為每一個屬性構造一個反射中的set方法
var f = c.getDeclaredField(columnName);
//賦予私有屬性的賦值許可權
f.setAccessible(true);
//使用反射,把value給到對象t的屬性中
f.set(t,value);//理解為:把value賦值給對象t的ColumName,相當於set方法
}
}
}
//7、關閉資源
st.close();
conn.close();
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
查詢一列的封裝
//查詢一列
public static <T> List<T> selectColumn(String sql,Class<T> c,Object...params){
//創建一個集合,存放所有的對象
List<T> tList=new ArrayList<>();
try {
//1、註冊驅動-反射去載入jar包中com.mysql.jdbc.Driver這個類中的 DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、獲取連接對象
var conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer-camp2023?characterEncoding=utf8", "root", "admin");
//3、定義sql
//4、需要創建statement
var st = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
st.setObject(i+1,params[i]);
}
//5、statement 執行sql,返回 結果集
var rs = st.executeQuery();
//結果集rs得到結果集元數據
ResultSetMetaData md=rs.getMetaData();
//獲取結果集總列數
var columnCount = md.getColumnCount();
//6、解析rs
while (rs.next()) {//rs.next 讀取結果集的游標向下移動一行,游標預設在哪一行,列名所在的那一行
//通過列的序號,獲取每一列的值
T t = (T) rs.getObject(1);
//把對象存入集合中
tList.add(t);
}
//7、關閉資源
st.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return tList;
}
查詢單個的封裝
//查詢單個
public static <T> T selectOne(String sql,Class<T> c,Object...params){
try {
//1、註冊驅動-反射去載入jar包中com.mysql.jdbc.Driver這個類中的 DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、獲取連接對象
var conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer-camp2023?characterEncoding=utf8", "root", "admin");
//3、定義sql
var st = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
st.setObject(i+1,params[i]);
}
//5、statement 執行sql,返回 結果集
var rs = st.executeQuery();
//結果集rs得到結果集元數據
ResultSetMetaData md=rs.getMetaData();
//獲取結果集總列數
var columnCount = md.getColumnCount();
//6、解析rs
T t=null;
if (rs.next()) {
t = (T) rs.getObject(1);
}
//7、關閉資源
st.close();
conn.close();
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
增刪改封裝方法
//增刪改
public static int update(String sql,Object...params){
try {
//1、註冊驅動-反射去載入jar包中com.mysql.jdbc.Driver這個類中的 DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");
//2、獲取連接對象
var conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer-camp2023?characterEncoding=utf8", "root", "admin");
//3、定義sql
//4、需要創建statement
var st = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
st.setObject(i+1,params[i]);
}
//5、statement 執行sql,返回 結果集
var i = st.executeUpdate();
//7、關閉資源
st.close();
conn.close();
return i;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
總的來說,封裝只是為了讓代碼變得更簡潔,為後面的開發做鋪墊!