JDBC(Java Data Base Connectivity,java數據庫連接)是一種用於執行SQL語句的Java API,可以爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此可以構建更高級的工具和接口,使數據庫開發人員能夠編寫數據庫應用程序。簡言之,JDBC就是Java用於執行SQL語句實現數據庫操作的API。
使用JDBC的大體步驟是這樣的:
1.註冊數據庫驅動
通常使用 Class.forName() 的方式進行註冊.不同數據庫驅動不同,本例採用的是 mysql 驅動.下面介紹了兩種數據庫對應的驅動樣式.
RDBMS | JDBC驅動名稱 | URL格式 |
---|---|---|
MySQL | com.mysql.jdbc.Driver | jdbc:mysql://hostName/databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@hostName:portNumber:databaseName |
Calss.forName("JDBC驅動名稱")
2.獲取數據庫鏈接
Connection connection = DriverManager.getConnection();
方法參數可選,不過最終都是調用的此方法
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException{
...
}
3.創建發送sql語句對象
可以根據需求選擇創建三種對象: Statement,PreparedStatement,CallableStatement,三者關係爲
Statment 接口提供了執行語句和獲取結果的基本方法,支持普通的不帶參數的sql語句,批量更新、刪除等操作。每次使用都需要重新載入sql語句。
PreparedStatement 爲 Statment 子接口,添加了 IN 參數的處理方法,支持可變參數sql,採用預編譯處理,編譯一次,執行多次,較Statment 接口而言,效率大大提高,而且也可以有效的防止sql注入問題。
CallableStatement 爲 PreparedStatement 子接口,添加了 OUT , INOUT 參數的處理方法,支持調用存儲過程。
4.發送sql語句
發送sql語句方法以及設置動態參數方法很多,建議閱讀源碼.這裏介紹三種發送sql語句方法:
executeQuery() 用於發送查詢語句
executeUpdate() 用於發送增添,修改,刪除語句
execute() 用於發送所有語句
5.釋放資源
接下來進行詳細的演示
一、配置文件 jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.20.103:3306/my_test
user=root
password=123456
編寫配置文件的目的是數據庫有修改時只需修改配置文件,編寫的工具類不需要改動.也可以省略此步驟,在工具類內部直接使用數據庫的基本配置.
二、JDBC工具類
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* @author YoonaLt
* @date 2019/11/1
* jdbc工具類
*/
public class JdbcUtils {
/**
* 獲取數據庫鏈接
*
* @return mysql鏈接對象
*/
public static Connection getConnection() {
// 獲取此類的類加載器
ClassLoader classLoader = JdbcUtils.class.getClassLoader();
// 獲取配置文件的輸入流
InputStream inputStream = classLoader.getResourceAsStream("jdbc.properties");
// 配置工具
Properties properties = new Properties();
// 加載
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
// 從配置文件讀取需要的配置屬性
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String driver = properties.getProperty("driver");
// 加載數據庫驅動
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 獲取數據庫鏈接
Connection connection = null;
try {
connection = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
/**
* 釋放資源
*
* @param connection 鏈接對象
* @param statement 發送sql語句對象
* @param resultSet 返回對象集合
*/
public static void release(Connection connection, Statement statement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
三、測試
1.建表
public static void createTable() {
// 獲取數據庫鏈接
Connection connection = JdbcUtils.getConnection();
PreparedStatement ps = null;
String sql = "create table user(id int auto_increment primary key,name varchar(50) comment '姓名'," +
"sex tinyint comment '0男,1女',birthday datetime comment '生日',profession varchar(20) comment '職業')" +
"default charset=utf8;";
try {
// 創建向數據庫發送sql語句對象
ps = connection.prepareStatement(sql);
// 發送sql語句
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 釋放資源
JdbcUtils.release(connection, ps, null);
}
}
2.插入數據
public static void insert() {
LocalDateTime localDateTime = LocalDateTime.of(1990, 5, 30, 12, 50, 40);
long l = localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
Date dateYoona = new Date(l);
Date dateIU = Date.valueOf("1993-05-16");
Connection connection = JdbcUtils.getConnection();
PreparedStatement ps = null;
// 可以直接填寫完整的sql語句,也可以使用佔位符.
String sql = " insert into user(name,sex,birthday,profession) values ('IU',1,?,'idol'),('Yoona',1,?,'idol')";
try {
ps = connection.prepareStatement(sql);
// 使用佔位符時,最好使用佔位類型對應的設置方法.也可都使用setObject()方法,第一個參數爲佔位符位置,從 1 開始,第二個爲替換值
ps.setDate(1, dateIU);
ps.setObject(2, dateYoona);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection, ps, null);
}
}
3.查詢數據
(1)返回的數據確定只有一條
public static void select() {
Connection connection = JdbcUtils.getConnection();
PreparedStatement ps = null;
// 查詢返回結果集
ResultSet resultSet = null;
String sql = "select * from user where name = ?";
try {
ps = connection.prepareStatement(sql);
ps.setString(1, "Yoona");
resultSet = ps.executeQuery();
if (resultSet.next()) {
System.out.println(resultSet.getString("name"));
System.out.println(resultSet.getInt("sex"));
System.out.println(resultSet.getDate("birthday"));
System.out.println(resultSet.getString("profession"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection, ps, resultSet);
}
}
(2) 返回的結果可能是多條
public static void selectMany() {
List<Map<String, String>> list = new ArrayList();
Connection connection = JdbcUtils.getConnection();
PreparedStatement cs = null;
ResultSet resultSet = null;
String sql = "select * from user";
try {
cs = connection.prepareStatement(sql);
resultSet = cs.executeQuery();
// 使用while
while (resultSet.next()) {
Map<String, String> m = new HashMap(16);
m.put("name", resultSet.getString("name"));
m.put("profession", resultSet.getString("profession"));
list.add(m);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.release(connection, cs, resultSet);
}
// 打印驗證是否成功取出多條數據
list.forEach(map -> System.out.println(map.get("name") + " 的職業是 " + map.get("profession")));
}
使用 while 循環,將每一個返回集放入準備好的容器中
4.事務
在jdbc中處理事務,是通過使用同一個 Connection 來實現的.
setAutoCommit(boolean autoCommit),設置是否自動提交事務,默認爲 true,如果設置爲false,則代表開啓事務
commit() ,提交事務
rollback(),回滾
public static void commit() {
Connection c = JdbcUtils.getConnection();
PreparedStatement ps = null;
try {
// 開啓事務
c.setAutoCommit(false);
// 設置主鍵衝突,觸發事務
String sqlOne = " insert into user(id,name,sex,profession) values (1,'Yoona',1,'idol')";
ps = c.prepareStatement(sqlOne);
ps.executeUpdate();
String sqlTwo = " insert into user(id,name,sex,profession) values (1,'IU',1,'idol')";
ps = c.prepareStatement(sqlTwo);
ps.executeUpdate();
// 提交事務
c.commit();
} catch (SQLException e) {
try {
// 發生異常即回滾
c.rollback();
System.out.println("----------回滾----------");
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtils.release(c, ps, null);
}
}
項目使用的框架對JDBC 已經封裝的十分好了,不過適當的瞭解JDBC的工作步驟還是有助於對框架的理解的.由於本人水平有限,難免出現錯誤與遺漏,歡迎指正.