JDBC(java database connectivity)
面向接口開發思想
- java數據庫連接
- java語言和數據庫之間的鏈接(java提供的api),為多種數據庫提供統一的訪問
- 每個數據庫內部的操作方式都不一樣,我們不可能自己寫實現類操作數據庫,因為這是數據庫公司的內部機密,所以每個數據庫廠商都提供一套操作自己數據庫的實現類給我們調用
- 鏈接mysql需要用到mysql公司提供的mysql-connector-java-5.1.39-bin.jar文件(數據庫供應商寫好的)
- java提供數據庫操作的接口,供應商根據接口來進行實現操作數據庫,這樣,通過同一套接口,可以實現不同數據庫的操作,而不需要不同數據庫需要調用不同的api
- 需要加載驅動,驅動程序中的類會實現JDBC的接口,我們只需要學習接口就好(驅動就是接口的實現類)
JDBC開發步驟
- 注冊驅動:加載廠商實現jdbc接口的實現類
- 通過drivermanager(驅動管理者),調用registerDriver(Driver)
- Driver驅動接口類,對象在導入的驅動中
- 傳入mysql驅動程序中的Driver對象
- 獲取連接:鏈接到廠商的數據庫
- 獲得語句執行平臺:獲取操作數據庫的實現類(sql語句的執行者)
- 執行sql語句:操作數據庫
- 處理結果:得到結果
- 釋放資源:斷開連接
- 1,2,3,6都是固定的.只有4,5是開發人員可控的
- 因為加載的驅動是jar包,里面都是編譯后的class文件,點進入相應的類中是沒有源碼的,這時需要自己導入源碼,在下載官方的驅動包時有一個src文件夾,里面放的就是源碼,我們attach resource the src floder,如果選擇導入file,則源碼需要是以jar的形式提供的
import com.mysql.jdbc.Driver;
public static void main(String[] args) throws SQLException {
// 注冊驅動
DriverManager.registerDriver(new Driver());
}
- 在Driver類源碼中,調用了一段靜態代碼塊,注冊一次驅動,只要一加載類,就會調用
- 如果按照上面的寫法寫,就會注冊2次驅動,造成浪費
- 通過反射的方式把類加載進內存,這樣就可以只調用一次加載驅動
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
}
- 通過 DriverManager獲取鏈接,得到的鏈接對象是在驅動包中的實現類
//static Connection getConnection(String url, String user, String password)
//返回值是Connection接口的實現類,在mysql驅動程序
//url: 數據庫地址 jdbc:mysql://連接主機IP:端口號//數據庫名字
String url = "jdbc:mysql://localhost:3306/mybase";
//用戶名和密碼用自己的
String username="root";
String password="root";
Connection con = DriverManager.getConnection(url, username, password);
- 通過得到的連接(connection)對象,去獲取數據庫的操作對象Statement
- Statement制定int executeUpDate(string sql),僅限于執行insert,update,delete
- 通過SQLYog拼接sql語句
- 關閉資源
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JDBCDemo {
public static void main(String[] args) throws Exception {
//1.注冊驅動 反射技術,將驅動類加入到內容
//使用java.sql.DriverManager類靜態方法 registerDriver(Driver driver)
// Diver是一個接口,參數傳遞,MySQL驅動程序中的實現類
//DriverManager.registerDriver(new Driver());
//驅動類源代碼,注冊2次驅動程序
Class.forName("com.mysql.jdbc.Driver");
//2.獲得數據庫連接 DriverManager類中靜態方法
//static Connection getConnection(String url, String user, String password)
//返回值是Connection接口的實現類,在mysql驅動程序
//url: 數據庫地址 jdbc:mysql://連接主機IP:端口號//數據庫名字
String url = "jdbc:mysql://localhost:3306/mybase";
String user = "root";
String password = "root";
//3.獲得語句執行平臺, 通過數據庫連接對象,獲取到SQL語句的執行者對象
// con對象調用方法 Statement createStatement() 獲取Statement對象,將SQL語句發送到數據庫
// 返回值是 Statement接口的實現類對象,,在mysql驅動程序
Connection conn = DriverManager.getConnection(url,user,password);
Statement statement = conn.createStatement();
//4.執行sql語句
// 通過執行者對象調用方法執行SQL語句,獲取結果
// int executeUpdate(String sql) 執行數據庫中的SQL語句, insert delete update
// 返回值int,操作成功數據表多少行
int rows = statement.executeUpdate("INSERT INTO sort(sname,sprice,sdesc) VALUES('xx',50, 'xx');");
System.out.println(rows);
//6.釋放資源 一堆close()
statement.close();
conn.close();
}
}
public class JDBCDemo1 {
public static void main(String[] args) throws Exception{
//1. 注冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2. 獲取連接對象
String url = "jdbc:mysql://localhost:3296/mybase";
String username="root";
String password="123";
Connection con = DriverManager.getConnection(url, username, password);
//3 .獲取執行SQL 語句對象
Statement stat = con.createStatement();
// 拼寫查詢的SQL
String sql = "SELECT * FROM sort";
//4. 調用執行者對象方法,執行SQL語句獲取結果集
// ResultSet executeQuery(String sql) 執行SQL語句中的select查詢
// 返回值ResultSet接口的實現類對象,實現類在mysql驅動中
ResultSet rs = stat.executeQuery(sql);
//5 .處理結果集
// ResultSet接口方法 boolean next() 返回true,有結果集,返回false沒有結果集
while(rs.next()){
//獲取每列數據,使用是ResultSet接口的方法 getXX方法參數中,建議寫String列名
System.out.println(rs.getInt("sid")+" "+rs.getString("sname")+
" "+rs.getDouble("sprice")+" "+rs.getString("sdesc"));
}
rs.close();
stat.close();
con.close();
}
}
sql注入
- 登陸查詢
- SELECT * FROM 用戶表 WHERE NAME = 用戶輸入的用戶名 AND PASSWORD = 用戶輸的密碼
- 此時,當用戶輸入正確的賬號與密碼后,查詢到了信息則讓用戶登錄
- 但是當用戶輸入的賬號為XXX 密碼為:XXX’ OR ‘a’=’a時,則真正執行的代碼變為
- SELECT * FROM 用戶表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’
- 此時,上述查詢語句時永遠可以查詢出結果的。那么用戶就直接登錄成功了,顯然我們不希望看到這樣的結果,這便是SQL注入問題
select * from tbl_user where usr_name='xx' and usr_pwd='xx';
select * from tbl_user where usr_name='xx' and usr_pwd='xx or 1=1';
預編譯sql語句
- PrepareStatement接口預編譯SQL語句
# 使用PreparedStatement預處理對象時,建議每條sql語句所有的實際參數,都使用逗號分隔。
# String sql = "insert into sort(sid,sname) values(?,?)";;
# PreparedStatement預處理對象代碼:
# PreparedStatement psmt = conn.prepareStatement(sql)
//執行SQL語句,數據表,查詢用戶名和密碼,如果存在,登錄成功,不存在登錄失敗
String sql = "SELECT * FROM users WHERE username=? AND PASSWORD=?";
//調用Connection接口的方法prepareStatement,獲取PrepareStatement接口的實現類
//方法中參數,SQL語句中的參數全部采用問號占位符
PreparedStatement pst = con.prepareStatement(sql);
System.out.println(pst);
//調用pst對象set方法,設置問號占位符上的參數
pst.setObject(1, "username");
pst.setObject(2, "password");
//調用方法,執行SQL,獲取結果集
ResultSet rs = pst.executeQuery();
while(rs.next()){
System.out.println(rs.getString("username")+" "+rs.getString("password"));
}
rs.close();
pst.close();
con.close();
JDBCUtils(JSBC工具類)
- 簡化代碼,方便返回數據庫鏈接對象Connection和關閉資源
public class JDBCUtils {
//私有構造方法
private JDBCUtils(){}
private static Connection con ;
//加載驅動
static{
try{
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mybase";
String username="root";
String password="root";
con = DriverManager.getConnection(url, username, password);
}catch(Exception ex){
throw new RuntimeException(ex+"數據庫連接失敗");
}
}
//獲取鏈接
public static Connection getConnection(){
return con;
}
//關閉資源
public static void close(Connection con,Statement stat){
if(stat!=null){
try{
stat.close();
}catch(SQLException ex){}
}
if(con!=null){
try{
con.close();
}catch(SQLException ex){}
}
}
//關閉資源
public static void close(Connection con,Statement stat , ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException ex){}
}
close(conn,stat);
}
}
public class TestJDBCUtils {
public static void main(String[] args)throws Exception {
Connection con = JDBCUtils.getConnection();
PreparedStatement pst = con.prepareStatement("SELECT sname FROM sort");
ResultSet rs = pst.executeQuery();
while(rs.next()){
System.out.println(rs.getString("sname"));
}
JDBCUtils.close(con, pst, rs);
}
}
properties配置文件
- DBUtils類通過讀取配置文件去設定數據庫地址,數據庫用戶名密碼,驅動地址等信息
- 通常都存在配置文件中,方便后期維護,程序如果需要更換數據庫,只需要修改配置文件即可
- property文件建議放在src目錄下
- 假設現在項目開發完成了,并且測試完畢,要交付給用戶了,我們給用戶的是bin目錄下的class文件,不可能把整個工程都給用戶的(包含源碼)
- 文件的擴展名為property
- 內容為key=value的形式
- 如果再好一點,會放在遠程服務器上,讓其讀取配置
- property文件的編寫
properties文件的編寫(內容如下):
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3296/mybase
username=root
password=123
//獲得當前類的類加載器(負責加載類的對象)
ClassLoader loader = 當前類.class.getClassLoader();
//獲取文件的流對象
InputStrea, fis = loader.getRescoreAsStream(String path);//輸入文件名
Properties pro = new Properties();
pro.load(fis);
public class PropertiesDemo {
public static void main(String[] args) throws Exception{
//使用類的加載器
InputStream in = PropertiesDemo.class.getClassLoader().getResourceAsStream("database.properties");
System.out.println(in);
Properties pro = new Properties();
pro.load(in);
//獲取集合中的鍵值對
String driverClass=pro.getProperty("driverClass");
String url = pro.getProperty("url");
String username = pro.getProperty("username");
String password = pro.getProperty("password");
Class.forName(driverClass);
Connection con = DriverManager.getConnection(url, username, password);
System.out.println(con);
}
}