Java雲同桌學習系列(十六)——JDBC
本部落格java雲同桌學習系列,旨在記錄本人學習java的過程,並與大家分享,對於想學習java的同學,我希望這個系列能夠鼓勵大家一同與我學習java,成為“雲同桌”。
每月預計保持更新數量三章起,每章都會從整體框架入手,介紹章節所涉及的重要知識點及相關練習題,並會設定推薦學習時間,每篇部落格涉及到的點都會在開篇目錄進行總覽。(部落格中所有高亮部分表示是面試題進階考點)
JDBC
學習時間:四天
學習建議:JDBC是一套面向各大資料庫的介面,是進行資料持久化必不可少的關鍵一環,大量的資料處理邏輯也是在建立連線獲取資料後進行操作
1.JDBC簡介、流程
JDBC
:是java與各大資料庫共同定製的一套介面,可以面向不同的資料庫
使用步驟:
-
引入相關的jar包——官方MySQL5.0 jdbc的包
切換到platform indepentment 如果是MySQL6.0以上,選擇jdbc8版本 如果是MySQL6.0以下,點選previous版本,選擇jdbc5版本
-
載入資料庫驅動
MySQL6.0以上:Class.forName("com.mysql.cj.jdbc.Driver"); MySQL6.0以下:Class.forName("com.mysql.jdbc.Driver");
-
獲取JDBC連線物件
Connection conn = DriverManager.getConnection("資料庫連線地址","帳號","密碼"); 資料庫連線地址格式: 主協議:子協議://ip地址:埠號/資料庫名稱 mysql的連線地址: jdbc:mysql://localhost:3306/java35 oracle的連線地址: jdbc:oracle:thin:@localhost:1521:ORCL
-
通過連線物件, 建立SQL執行物件 (SQL執行環境)
Statement state = conn.createStatement();
-
通過SQL執行物件 ,執行SQL語句.
state.execute(String sql語句);
-
釋放資源
切記,釋放資源這一步非常重要,如果不釋放,會始終佔用資料庫連線量,導致資源浪費,嚴重甚至無法繼續連線
state.close(); conn.close();
連線例項:
public class Demo{
public static void createTable() throws ClassNotFoundException, SQLException {
//1.載入資料庫驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取jdbc連線物件
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "424197379");
//3.建立SQL執行物件
Statement statement = conn.createStatement();
//4.執行SQL語句
statement.execute("create table test_jdbc (" +
"id int ,name varchar(10))"
);
//5.釋放資源
statement.close();
conn.close();
}
成功後資料庫中順利建立了該表
mysql> desc test_jdbc;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
注意,在進行資料庫資料插入時,若需要插入中文字元,可以在連線時的url中指定utf-8
"jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8"
2.JDBC相關類
DriverManager
模組 java.sql
軟體包 java.sql
Class DriverManager
介紹:管理JDBC驅動的基本服務類
修飾 | 方法 | 描述 |
---|---|---|
static Connection | getConnection(String url, String user, String password) | 嘗試建立與給定資料庫URL的連線,指定連線url,使用者名稱,密碼 |
static Connection | getConnection(String url, Properties info) | 嘗試建立與給定資料庫URL的連線,指定連線url,配置檔案 |
Connection
模組 java.sql
軟體包 java.sql
Interface Connection
介紹:負責管理與特定資料庫的連線服務
修飾 | 方法 | 描述 |
---|---|---|
Statement | createStatement() | 建立一個 Statement物件,用於將SQL語句傳送到資料庫。 |
PreparedStatement | prepareStatement(String sql) | 建立一個預編譯 PreparedStatement物件,用於將引數化SQL語句傳送到資料庫。 |
void | setAutoCommit(boolean autoCommit) | 將此連線的自動提交模式設定為給定狀態,false為開啟連線 |
void | rollback() | 撤消當前事務中所做的所有更改,並釋放此 Connection物件當前持有的所有資料庫鎖。 |
void | commit() | 使自上次提交/回滾以來所做的所有更改成為永久更改,並釋放此 Connection物件當前持有的所有資料庫鎖。 |
void | close() | 立即釋放此 Connection物件的資料庫和JDBC資源,而不是等待它們自動釋放。 切記使用完畢後主動釋放 |
Statement
模組 java.sql
軟體包 java.sql
Interface Statement
介紹:負責執行與資料庫互動的SQL語句並返回生成結果集,預設情況下,每個Statement物件只能同時開啟一個ResultSet物件
修飾 | 方法 | 描述 |
---|---|---|
boolean | execute(String sql) | 執行給定的SQL語句,根據是否有結果返回布林值,查詢語句返回true,其他語句返回false |
int | executeUpdate(String sql) | 執行給定的SQL語句( INSERT,UPDATE,DELETE語句,CREATE,ALTER,DROP)返回資料庫表格的影響行數,通常>0 表示執行成功 |
ResultSet | executeQuery(String sql) | 執行給定的SQL語句(select),該語句返回單個 ResultSet物件。 |
void | addBatch(String sql) | 將給定的SQL命令新增到此 Statement物件的批處理命令列表中。 |
int[] | executeBatch() | 將一批命令提交到資料庫以供執行,如果所有命令成功執行,則返回一組更新計數。 |
void | clearBatch() | 清空此 Statement物件的當前SQL命令批處理列表。 |
void | close() | 立即釋放此 Statement物件的資料庫和JDBC資源,而不是等待它自動關閉時發生。 切記使用完畢後主動釋放 |
ResultSet
模組 java.sql
軟體包 java.sql
Interface ResultSet
介紹:負責運算元據庫返回結果集,通常由select語句生成
結果集的資料結構大致如圖,遊標初始指向第0行,資料從第一行開始,通過控制遊標移動到某一行,然後通過getXxx()方法獲取該資料型別的資料
修飾 | 方法 | 描述 |
---|---|---|
boolean | next() | 將游標向下移動一行。 移動成功返回true,下一行不存在移動失敗返回false |
boolean | previous() | 將游標向上移動一行。 移動成功返回true,上一行不存在移動失敗返回false |
boolean | absolute(int row) | 將游標移動到給定行號,行號從1開始 |
int | getInt(String columnLabel) | 根據欄位名獲取該行中的資料 |
int | getInt(int columnIndex) | 根據欄位索引獲取該行中的資料 ,索引從1開始 |
String | getString(String columnLabel) | 根據欄位名獲取該行中的資料 |
String | getString(int columnIndex) | 根據欄位索引獲取該行中的資料 ,索引從1開始 |
Date | getDate(String columnLabel) | 根據欄位名獲取該行中的資料,用於時間Date型別資料 |
void | close() | 立即釋放此 ResultSet物件的資料庫和JDBC資源,而不是等待它自動關閉時發生。 切記要釋放 |
查詢練習:
查詢資料庫test中mst_weather的所有資料及第二條資料的溫度
mysql> select * from mst_weather;
+----+------------+-------------+
| id | date | temperature |
+----+------------+-------------+
| 1 | 2022-04-01 | 20 |
| 2 | 2022-04-02 | 25 |
| 3 | 2022-04-03 | 21 |
| 4 | 2022-04-04 | 24 |
+----+------------+-------------+
4 rows in set (0.11 sec)
public static void searchData() throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8","root","424197379");
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery("select * from mst_weather");
while(resultSet.next()){
int id = resultSet.getInt("id");
Date date = resultSet.getDate("Date");
int temperature = resultSet.getInt("temperature");
//格式化顯示日期
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
String stringDate = simpleDateFormat.format(date);
System.out.println(id + "\t" + stringDate + "\t" + temperature);
}
resultSet.absolute(2);
int temInt = resultSet.getInt(3);
System.out.println("第二條資料中第3個欄位的資料為:" + temInt);
}
執行結果:
PreparedStatement
模組 java.sql
軟體包 java.sql
Interface PreparedStatement
介紹:負責預編譯SQL語句的類
修飾 | 方法名 | 描述 |
---|---|---|
void | setInt(int parameterIndex, int x) | 將指定引數設定為給定的Java int值。 |
void | setDouble(int parameterIndex, double x) | 將指定引數設定為給定的Java double值。 |
void | setDate(int parameterIndex, Date x) | 使用執行應用程式的虛擬機器的預設時區將指定引數設定為給定的 java.sql.Date值。 |
boolean | execute() | 在此 PreparedStatement物件中執行SQL語句,該物件可以是任何型別的SQL語句。 |
int | executeUpdate() | 執行在該SQL語句PreparedStatement物件,它必須是一個SQL資料操縱語言(DML)語句,比如INSERT , UPDATE或DELETE ; 或者不返回任何內容的SQL語句,例如DDL語句。 |
ResultSet | executeQuery() | 執行此 PreparedStatement物件中的SQL查詢,並返回查詢生成的 ResultSet物件 |
void | addBatch() | 將給定的SQL命令新增到此PreparedStatement物件的批處理命令列表中。 |
int[] | executeBatch() | 將一批命令提交到資料庫以供執行,如果所有命令成功執行,則返回一組更新計數。 |
void | clearBatch() | 清空此PreparedStatement物件的當前SQL命令批處理列表。 |
3.工廠設計模式——靜態工廠方法模式
為了降低程式碼與資料庫的耦合性,便於切換資料庫,大多采用靜態工廠方法模式進行設定
DAO
:資料訪問介面 ,DAO模式是標準的javaEE設計模式之一,分離底層資料訪問和上層商務邏輯。
建立一個健壯的java應用,應將所有對資料來源的操作封裝到一個公共API中。其DAO實現的元件有:
1.一個DAO工廠
2.一個DAO介面
3.DAO介面的若干實現類
4.資料傳遞Bean物件
練習:建立一個使用者註冊登入的DAO工廠模式專案
DAO介面:BaseUserDao
import java.util.List;
public interface BaseUserDao {
/**
* 用於向資料庫xzk_user表格中插入一行資料
* @param username 是要插入的賬號
* @param password 是要插入的密碼
* @return 結果, 增加成功返回true
*/
boolean insert(String username,String password);
/**
* 用於從資料庫xzk_user表格中查詢一行資料
* @param username 是要查詢的條件1:賬號
* @param password 是要查詢的條件2:密碼
* @return 結果, 查詢成功返回true
*/
boolean findByPassword(String username,String password);
/**
* 用於從資料庫xzk_user表格中查詢一行資料
* @param username 是要查詢的條件1:賬號
* @param password 是要查詢的條件2:密碼
* @return 結果, 查詢成功返回true
*/
boolean findByPassword2(String username,String password);
/**
* 查詢所有使用者資訊
* @return 使用者列表
*/
List<User> findAll();
使用者Bean物件類:User
import java.util.Objects;
public class User {
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(username, user.username) &&
Objects.equals(password, user.password);
}
@Override
public int hashCode() {
return Objects.hash(username, password);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {
}
}
mySQL的DAO層實現類:MySqlUserDao
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class MySqlUserDao implements BaseUserDao{
static{
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public boolean insert(String username, String password) {
Connection conn = null;
Statement state = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
state = conn.createStatement();
//insert into xzk_user values('username','password') : 字串的定義格式 字串的表現格式
int row = state.executeUpdate("insert into xzk_user values('" + username + "','" + password + "')");
return row>0;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
@Override
public boolean findByPassword(String username, String password) {
Connection conn = null;
PreparedStatement state = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
//引數: 預編譯的SQL語句, 引數部分使用?替代.
state = conn.prepareStatement("select * from xzk_user where username=? and password=?");
//向預編譯的執行環境中, 加入引數的內容
state.setString(1,username);
state.setString(2,password);
//執行
rs = state.executeQuery();
return rs.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
rs.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
state.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
return false;
}
@Override
public boolean findByPassword2(String username, String password) {
Connection conn = null;
Statement state = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
state = conn.createStatement();
//執行
rs = state.executeQuery("select * from xzk_user where username='"+username+"' and password='"+password+"'");
return rs.next();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
rs.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
state.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
try {
conn.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
return false;
}
@Override
public List<User> findAll() {
List<User> data = new ArrayList<>();
Connection conn = null;
Statement state = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
state = conn.createStatement();
rs = state.executeQuery("select * from xzk_user");
while(rs.next()){
String username = rs.getString("username");
String password = rs.getString("password");
data.add(new User(username,password));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
state.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return data;
}
}
DAO工廠:UserDaoFactory
public class UserDaoFactory {
public static BaseUserDao get(){
return new MySqlUserDao();
}
}
Main主函式檢視類:Main
import java.util.List;
import java.util.Scanner;
public class Main {
static Scanner input = new Scanner(System.in);
static BaseUserDao dao = UserDaoFactory.get();
public static void main(String[] args) {
System.out.println("歡迎來到某某軟體");
System.out.println("請選擇:");
System.out.println("1.註冊\t\t2.登陸\t\t3.檢視所有使用者");
String menu = input.nextLine();
switch (menu){
case "1":
reg();
break;
case "2":
login();
break;
case "3":
showUsers();
break;
}
}
private static void showUsers() {
List<User> data = dao.findAll();
System.out.println("所有使用者資訊如下:");
System.out.println(data);
}
private static void login() {
System.out.println("請輸入賬號:");
String username = input.nextLine();
System.out.println("請輸入密碼:");
String password = input.nextLine();
boolean flag = dao.findByPassword(username, password);
System.out.println(flag?"恭喜你,登陸成功":"很遺憾,登陸失敗");
}
private static void reg() {
System.out.println("請輸入要註冊的賬號:");
String username = input.nextLine();
System.out.println("請輸入要註冊的密碼:");
String password = input.nextLine();
boolean flag = dao.insert(username, password);
System.out.println(flag?"恭喜你,註冊成功":"很遺憾,註冊失敗");
}
}
4.PreparedStatement 預編譯
在進行之前的SQL語句時,通常是收集到使用者輸入的資料資訊,然後拼接到SQL插入語句,但是可能會因為拼接出現歧義現象,這樣的問題稱為SQL隱碼攻擊問題
select * from xzk_user where username='hahahaheiheihei' and password='1'
select * from xzk_user where username='hahahaheiheihei' and password='1' or '1'='1'
為解決SQL隱碼攻擊問題,需要將引數進行預處理(底層原理其實就是轉義處理)
預編譯的實現是通過PreparedStatement物件實現的,直接在建立物件時便傳入預編譯的SQL語句
PreparedStatement state = conn.prepareStatement("預編譯的SQL語句");
對於需要填充引數的位置,可以使用?代替,然後通過呼叫PreparedStatement物件相應的setXxx(int index,xxx value)指定第幾個?(索引從1開始)和對應的值
填充完畢後,執行不同的execute()方法即可,見上一節對PreparedStatement常用方法的解釋
state = conn.prepareStatement("select * from xzk_user where username=? and password=?");
//向預編譯的執行環境中, 加入引數的內容
state.setString(1,username);
state.setString(2,password);
//執行
rs = state.executeQuery();
PreparedStatement與Statement效能高低的問題,取決於連線什麼資料庫
在mysql中, preparedStatement原理是拼接SQL, 所以Statement效能高.
在Oracle中, preparedStatement原理是對SQL指令進行預處理, 再傳遞的引數不具備特殊含義.有更好的SQL快取策略,PreparedStatement高.
5.事務與批處理
事務詳細內容建議看我上一篇文章Java雲同桌學習系列(十五)——MySQL資料庫
事務
:指一系列SQL操作所組成的一個程式執行邏輯單元,所有操作要麼全部失敗,要麼全部成功
- 開啟事務: conn.setAutoCommit(false);
- 回滾事務: conn.rollback();
- 提交事務: conn.commit();
通常的使用策略為:
try{
conn.setAutoCommit(false);
//可能出錯的運算元據庫語句
conn.commit();
conn.setAutoCommit(true);
}catch(Exception e){
conn.rollback();
}
批處理
:指將多條語句放到一起批量處理,可以將多條SQL語句,轉換為一個SQL指令. 顯著的提高大量SQL語句執行時的資料庫效能.
-
statement批處理
1. 得到Statement物件 Statement statement = conn.createStatement(); 2. 將一條SQL語句, 加入到批處理中. statement.addBatch(String sql); 3. 執行批處理 statement.executeBatch(); 4. 清空批處理 statement.clearBatch();
-
PreparedStatement批處理
1. 得到PreparedStatement物件 PreparedStatement preparedstate = conn.prepareStatement("預編譯的SQL"); 2. 填充預編譯的引數 preparedstate.setXXX(1,填充引數); 3. 將一條填充完畢引數的SQL, 加入到批處理中. preparedstate.addBatch(); 4. 執行批處理 preparedstate.executeBatch(); 5. 清空批處理 preparedstate.clearBatch();
上述用到的方法,都可以在 2.JDBC相關類的方法 中查到詳細介紹
6.匯入 Properties 資料庫配置檔案
之前,我們在java雲同桌學習系列(八)——IO流時詳細講解過properties配置檔案
properties型別檔案中,會以“鍵 = 值”的形式進行儲存,以“#”作為註釋的開頭符號,可以把jdbc相關的資料寫入檔案中,通過匯入快速的轉換為Properties類的物件.
1. 建立Properties物件
Properties ppt = new Properties();
2. 建立一個位元組輸入流 , 指向.properties檔案
InputStream is = new FileInputStream("檔案地址");
3. 將位元組輸入流, 傳遞給properties物件, 進行載入.
ppt.load(is);
通常將檔案放置在當前專案的src目錄下,建立對應的位元組輸入流如下:
InputStream inputStream = 當前類名.class.getClassLoader().getResourceAsStream("properties檔名");
7. 資料庫連線池
類似與執行緒池的機制,資料庫連線池也是用於快取資料的連線的,需要連線時,直接從連線池中獲取
當連線池中存在空閒連線時, 取出空閒連線使用
當連線池中不存在空閒連線時,
連線池未滿時 , 則建立連線提供給程式使用 ,並在程式使用完畢後, 快取連線.
連線池已滿時 , 則排隊等候空閒連線的出現.
使用連線池中的連線物件運算元據庫時, 操作完畢依然需要呼叫close(),實際並沒有關閉,只是重新放回了連線池
德魯伊連線池:阿里巴巴(Druid)德魯伊連線池——Java語言中最好的資料庫連線池
Druid連線池是阿里巴巴開源的資料庫連線池專案。Druid連線池為監控而生,內建強大的監控功能,監控特性不影響效能。功能強大,能防SQL隱碼攻擊,內建Loging能診斷Hack應用行為。
1. 引入相關的jar檔案
- druid-1.0.9.jar
2. 將配置檔案引入
3. 將配置檔案, 轉換為Properties物件
Properties ppt = new Properties();
ppt.load(配置檔案的輸入流);
4. 通過連線池的工廠類(DruidDataSourceFactory)的建立連線池的方法(createDataSource())
DataSource ds = DruidDataSourceFactory.createDataSource(ppt);
5. 從連線池中 獲取連線物件
Connection conn = ds.getConnection();
通常都會將德魯伊連線池封裝到一個 DruidUtil的德魯伊工具類中
以後用到德魯伊工具類直接可以將下面的類負責到工程中呼叫相關的靜態方法使用
/**
* @description: 德魯伊連線池工具類
* @author: southwindow
* @create: 2020-11-18 22:51
**/
public class DruidUtil {
private static DataSource dataSource = null;
/**
* 初始化載入配置連線池
*/
static {
Properties properties = new Properties();
InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");
try {
properties.load(is);
dataSource = DruidDataSourceFactory.createDataSource(properties);
dataSource.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 從德魯伊連線池中獲取一個連線
* @return 連線池中的一個連線物件
*/
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
return null;
}
}
/**
* 用於釋放 連線物件,SQL預編譯環境,結果集
* @param connection
* @param statement
* @param resultSet
*/
public static void close(Connection connection , Statement statement, ResultSet resultSet){
if(connection!=null){
try {
connection.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (Exception throwables) {
throwables.printStackTrace();
}
}
}
}
德魯伊連線池的配置檔案druid.properties:
url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8"
username=root
password=424197379
#驅動類名。根據url自動識別,這一項可配可不配,如果不配置druid會根據url自動識別相應的driverClassName
driverClassName=com.mysql.jdbc.Driver
#初始化時建立物理連線的個數。初始化發生在顯示呼叫init方法,或者第一次 getConnection時
initialSize=5
#最大連線池數量
maxActive=10
#最小連線池數量
minIdle=5
#獲取連線時最大等待時間,單位毫秒。
maxWait=3000
都學習到這裡了,不妨關注點贊一下吧~
相關文章
- Java學習:JDBC簡介JavaJDBC
- 碎片化學習Java(十六)Java For迴圈案例Java
- JDBC學習JDBC
- 學習Java系列Java
- Java安全之JDBC Attacks學習記錄JavaJDBC
- MCMC-2|機器學習推導系列(十六)機器學習
- JDBC學習筆記JDBC筆記
- JDBC學習日記JDBC
- Java學習筆記系列-反射Java筆記反射
- 學習Java8系列-LambdaJava
- Java NIO學習系列二:ChannelJava
- Java NIO學習系列三:SelectorJava
- Java NIO學習系列一:BufferJava
- 【Redis 系列】redis 學習十六,redis 字典(map) 及其核心編碼結構Redis
- Java 基礎學習系列一 —— Java 主要特性Java
- Hive學習之JDBC訪問HiveJDBC
- 系統學習NLP(十六)--DSSMSSM
- Java學習十六—掌握註解:讓程式設計更簡單Java程式設計
- 好程式設計師Java學習路線分享Java案例-封裝JDBC工具類程式設計師Java封裝JDBC
- Java NIO學習系列七:Path、Files、AsynchronousFileChannelJava
- Java NIO學習系列五:I/O模型Java模型
- JDBC與JavaBean學習筆記(二)JDBCJavaBean筆記
- Spring Boot 學習筆記(2):JDBCSpring Boot筆記JDBC
- 學習ASP.NET Core Blazor程式設計系列二十六——登入(5)ASP.NETBlazor程式設計
- Java 之 JDBCJavaJDBC
- Java之JDBCJavaJDBC
- 軟體測試學習教程——JDBC配置JDBC
- (十六)Python學習之內建函式Python函式
- Redis學習筆記(十六) Sentinel(哨兵)(下)Redis筆記
- Java8學習系列之匿名函式LambdaJava函式
- Java NIO學習系列四:NIO和IO對比Java
- Java命令學習系列(零)——常見命令及Java Dump介紹Java
- Java 之 JDBC(二)JavaJDBC
- 【Java】JDBC詳解JavaJDBC
- 軟體測試學習教程——JDBC開發JDBC
- 軟體測試學習教程——JDBC介紹JDBC
- 學習JDBC這一篇就夠了JDBC
- java學習之道 --- 如何學習java?Java