JDBC(重點)
資料庫驅動
JDBC
SUN公司為了簡化 開發人員的(對資料庫的同一)操作,提供了一個(Java運算元據庫的)規範,俗稱JDBC
這些規範的實現由具體的廠商去做
對於開發人員來說,我們只需要掌握JDBC介面的操作即可
java.sql
javax.sql
還需要匯入一個資料庫驅動包
第一個JDBC程式
-
建立普通專案
-
匯入資料庫驅動
-
編寫程式碼
package com.gs.lesson; import com.mysql.jdbc.Driver; import java.sql.*; /** * @version: java version 1.8 * @author: 14 * @description: */ public class JdbcFisrstDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 1、載入驅動 Class.forName("com.mysql.jdbc.Driver"); // 2、使用者資訊和url String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false"; String username = "root"; String password = "123456"; // 3、連線成功,返回資料庫物件 Connection connection = DriverManager.getConnection(url, username, password); // 4、執行sql的物件 Statement statement = connection.createStatement(); // 5、執行sql的物件 去執行 sql,可能存在結果,檢視返回結果 String sql = "select * from users"; ResultSet resultSet = statement.executeQuery(sql);// 返回的結果集,封裝了全部的查詢結果 while (resultSet.next()) { System.out.println("id:" + resultSet.getObject("id")); System.out.println("name:" + resultSet.getObject("name")); System.out.println("pwd:" + resultSet.getObject("password")); System.out.println("email:" + resultSet.getObject("email")); System.out.println("birth:" + resultSet.getObject("birthday")); } // 6、釋放連線 resultSet.close(); statement.close(); connection.close(); } }
步驟總結:
- 載入驅動
- 連線資料庫 DriverManager
- 獲得執行sql的物件 Statement
- 獲得返回的結果集
- 釋放連線
DriverManager
//DriverManager.registerDriver(new Driver());
Class.forName("com.mysql.jdbc.Driver");//固定寫法,載入驅動
Connection connection = DriverManager.getConnection(url, username, password);
//connection 代表資料庫
//資料庫設定自動提交
//事務提交
//事務回滾
connection.setAutoCommit();
connection.commint();
connection.rollback();
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";
//mysql --- 3306
//jdbc:mysql://主機地址:埠號/資料庫名?引數1&引數2&引數3
//oralce --- 1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement | PrepareStatement 執行sql的物件
String sql = "select * from users" //編寫sql
statement.executeQuery();//查詢操作 返回ResultSet
statement.execute();//執行任何SQL
statement.executeUpdate();//更新、插入、刪除 都是用這個, 返回一個受影響的行數
ResultSet 查詢的結果集:封裝了所有的查詢結果
獲得指定的資料型別
resultSet.getObject();// 在不指定列型別的情況下使用
// 如果知道列型別就使用指定型別
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
遍歷,指標
resultSet.beforeFirst();//移動到最前面
resultSet.afterLast();//移動到最後面
resultSet.next();//移動到下一個
resultSet.previous();//移動到前一行
resultSet.absolute();//移動到指定行
釋放資源
// 6、釋放連線
resultSet.close();
statement.close();
connection.close();// 消耗資源,用完關掉
statement物件
程式碼實現
1、提取工具類
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
// 1、驅動只用載入一次
Class.forName(driver);
}catch (Exception e){
e.printStackTrace();
}
}
//獲取連線資源
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//釋放連線資源
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
2、編寫增刪改的方法 executeUpdate
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); //獲取資料庫連線
stmt = conn.createStatement(); //獲得sql的執行物件
String sql = "INSERT INTO users(ID,NAME,PASSWORD,EMAIL,BIRTHDAY)"+
"VALUES(4,'KUANGSHEN','123456','1235563@QQ.COM','2025-1-1')";
int i = stmt.executeUpdate(sql);
if (i > 0){
System.out.println("插入成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, stmt, rs);
}
}
}
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
String sql = "delete from users where id=4";
int i = stmt.executeUpdate(sql);
if ( i > 0){
System.out.println("刪除成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,stmt,null);
}
}
}
public class TestUpdate {
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement stmt = null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
String sql = "UPDATE users SET name= 'kuangshen' ,email = '858728@qq.com' where id = 1";
int i = stmt.executeUpdate(sql);
if (i > 0) {
System.out.println("修改成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, stmt, null);
}
}
}
3、查詢execuQuery
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
//SQL
String sql = "select * from users where id = 1";
rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, stmt, rs);
}
}
}
SQL隱碼攻擊的問題
sql存在漏洞,會被攻擊導致資料洩露 SQL會被拼接 or
public class SQL隱碼攻擊 {
public static void main(String[] args) {
login("' or'1=1","' or'1=1");
}
public static void login(String username, String password){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
stmt = conn.createStatement();
String sql = "select * from users where name = '"+username+"' and password = '"+password+"'";
rs = stmt.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn, stmt, rs);
}
}
}
PreparedStatement
PreparedStatement 可以防止SQL隱碼攻擊,並且效率更高
1、新增
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection(); //獲取資料庫連線
//區別
//使用?佔位符 代替引數
String sql = "INSERT INTO users(ID,NAME,PASSWORD,EMAIL,BIRTHDAY)"+
"VALUES(?,?,?,?,?)";
ps = conn.prepareStatement(sql);//預編譯SQL,先寫sql,然後不執行
//手動給引數賦值
ps.setInt(1,6);
ps.setString(2,"shisi");
ps.setString(3,"123456");
ps.setString(4,"8578482@qq.com");
//注意點:sql.Date 資料庫 java.sql.Date
// util.Date java new Date().getTime() 獲得時間戳
ps.setDate(5, new java.sql.Date(new Date().getTime()));
//執行
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("插入成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, ps, rs);
}
}
}
2、刪除
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtils.getConnection();
String sql = "delete from users where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 5);
int i = ps.executeUpdate();
if ( i > 0){
System.out.println("刪除成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn,ps,null);
}
}
}
3、更新
public class TestUpdate {
public static void main(String[] args) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtils.getConnection();
String sql = "UPDATE users SET name=? where id =?";
ps = conn.prepareStatement(sql);
ps.setString(1, "kuangshen");
ps.setInt(2, 5);
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("修改成功");
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, ps, null);
}
}
}
4、查詢
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//SQL
String sql = "select * from users where id =?";
ps = conn.prepareStatement(sql);
ps.setInt(1, 6);//傳遞引數
rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(conn, ps, rs);
}
}
}
5、防止SQL隱碼攻擊
public class SQL隱碼攻擊 {
public static void main(String[] args) {
login("' or'1=1","' or'1=1");
}
public static void login(String username, String password){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//PreparedStatement 防止SQL隱碼攻擊的本質,把傳遞進來的引數當做字串
// 假設其中存在跳脫字元,直接忽略,比如說'
String sql = "select * from users where name = ? and password = ?";
stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
rs = stmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("password"));
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.release(conn, stmt, rs);
}
}
}
使用IDEA連線資料庫
事務
程式碼實現
1、關閉自動提交,開啟事務conn.setAutoCommit(false);
2、一組事務執行完畢,提交事務
3、可以在catch語句中顯式的定義 回滾語句,但預設失敗就會回滾
public class 事務 {
public static void main(String[] args) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = JdbcUtils.getConnection();
con.setAutoCommit(false);// 關閉自動提交,開啟事務
String sql = "UPDATE account SET money = money - 100 where name = 'A'";
ps = con.prepareStatement(sql);
ps.executeUpdate();
//int i = 1/0; // 讓 事務 不能完成
sql = "UPDATE account SET money = money + 100 where name = 'B'";
ps = con.prepareStatement(sql);
ps.executeUpdate();
con.commit();// 業務完成 提交
}catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JdbcUtils.release(con, ps, rs);
}
}
}
資料庫連線池
資料庫連線 ---- 執行完畢 ---- 釋放
連線 ---- 釋放 十分浪費系統資源
池化技術:準備一些預先的資源,過來就連線預先準備好的
----- 開門 ------ 業務員:等待 ------ 服務 ------
若 常用連線數:10個
最小連線數:10個
最大連線數:15個 業務最高承載上限
等待超時:100ms
編寫連線池,實現一個介面 DataSource
開源資料來源實現
DBCP
C3P0
Druid:阿里巴巴
使用了這些資料庫連線池後,在專案開發中就不需要編寫連線資料庫的程式碼了
DBCP
需要的jar包
commons-dbcp-1,4.jar commons-pool-1.6.jar
工具類
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//建立資料來源 工廠模式 --->建立
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
//獲取連線資源
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();//從資料來源中獲取連線
}
//釋放連線資源
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
配置檔案
#連線設定
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456
#<!-- 初始化連線 -->
initialSize=10
#最大連線數量
maxActive=50
#<!-- 最大空閒連線 -->
maxIdle=20
#<!-- 最小空閒連線 -->
minIdle=5
#<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
maxWait=60000
#JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:【屬性名=property;】
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由連線池所建立的連線的自動提交(auto-commit)狀態。
defaultAutoCommit=true
#driver default 指定由連線池所建立的連線的只讀(read-only)狀態。
#如果沒有設定該值,則“setReadOnly”方法將不被呼叫。(某些驅動並不支援只讀模式,如:Informix)
defaultReadOnly=
#driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。
#可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
C3P0
需要的jar包
c3p0-0.9.5.5.jar 、mchange-commons-java-0.2.19.jar
工具類
public class JdbcUtils_C3P0 {
private static DataSource dataSource = null;
static {
try {
//建立資料來源 工廠模式 --->建立
dataSource = new ComboPooledDataSource("MySQL");//配置檔案寫法
}catch (Exception e){
e.printStackTrace();
}
}
//獲取連線資源
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();//從資料來源中獲取連線
}
//釋放連線資源
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--
c3p0的預設(預設)配置
如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource();"這樣寫就表示使用的是c3p0的預設(預設)-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquiredIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");"這樣寫就表示使用的是name是MySQL的配置-->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquiredIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
結論
無論使用什麼資料來源,本質還是一樣的,DataSource介面不會變,方法也不會變