JDBC
JAVA Database Connectivity java 數(shù)據(jù)庫連接
- 為什么會出現(xiàn)JDBC
SUN公司提供的一種數(shù)據(jù)庫訪問規(guī)則、規(guī)范, 由于數(shù)據(jù)庫種類較多,并且java語言使用比較廣泛,sun公司就提供了一種規(guī)范,讓其他的數(shù)據(jù)庫提供商去實(shí)現(xiàn)底層的訪問規(guī)則。 我們的java程序只要使用sun公司提供的jdbc驅(qū)動(dòng)即可。
使用JDBC的基本步驟
-
注冊驅(qū)動(dòng)
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
-
建立連接
//DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
//2. 建立連接 參數(shù)一: 協(xié)議 + 訪問的數(shù)據(jù)庫 , 參數(shù)二: 用戶名 , 參數(shù)三: 密碼。
conn = DriverManager.getConnection("jdbc:mysql://localhost/student", "root", "root"); -
創(chuàng)建statement
//3. 創(chuàng)建statement , 跟數(shù)據(jù)庫打交道,一定需要這個(gè)對象
st = conn.createStatement(); -
執(zhí)行sql ,得到ResultSet
//4. 執(zhí)行查詢 , 得到結(jié)果集
String sql = "select * from t_stu";
rs = st.executeQuery(sql); -
遍歷結(jié)果集
//5. 遍歷查詢每一條記錄
while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); int age = rs.getInt("age"); System.out.println("id="+id + "===name="+name+"==age="+age); } 釋放資源
if (rs != null) {
try {
rs.close();
} catch (SQLException sqlEx) { } // ignore
rs = null;
}
...
JDBC 工具類構(gòu)建
- 資源釋放工作的整合
- 驅(qū)動(dòng)防二次注冊
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Driver 這個(gè)類里面有靜態(tài)代碼塊,一上來就執(zhí)行了,所以等同于我們注冊了兩次驅(qū)動(dòng)。 其實(shí)沒這個(gè)必要的。
//靜態(tài)代碼塊 ---> 類加載了,就執(zhí)行。 java.sql.DriverManager.registerDriver(new Driver());
最后形成以下代碼即可。
Class.forName("com.mysql.jdbc.Driver");
-
使用properties配置文件
-
在src底下聲明一個(gè)文件 xxx.properties ,里面的內(nèi)容吐下:
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/student?useSSL=false&serverTimezone=GMT%2B8&
name=root
password=root 在工具類里面,使用靜態(tài)代碼塊,讀取屬性
-
代碼如下
static{
try {
//1. 創(chuàng)建一個(gè)屬性配置對象
Properties properties = new Properties();
InputStream is = new FileInputStream("jdbc.properties"); //對應(yīng)文件位于工程根目錄
//使用類加載器,去讀取src底下的資源文件。 后面在servlet //對應(yīng)文件位于src目錄底下
//InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
//導(dǎo)入輸入流。
properties.load(is);
//讀取屬性
driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
name = properties.getProperty("name");
password = properties.getProperty("password");
} catch (Exception e) {
e.printStackTrace();
}
}
?
數(shù)據(jù)庫的CRUD sql
-
insert(增)
1.INSERT INTO t_stu (NAME , age) VALUES ('wangqiang',28) 2.INSERT INTO t_stu VALUES (NULL,'wangqiang2',28) // 1. 獲取連接對象 conn = JDBCUtil.getConn(); // 2. 根據(jù)連接對象,得到statement st = conn.createStatement(); //3. 執(zhí)行添加 String sql = "insert into t_stu values(null , 'aobama' , 59)"; //影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗 int result = st.executeUpdate(sql); if(result >0 ){ System.out.println("添加成功"); }else{ System.out.println("添加失敗"); } -
delete(刪)
DELETE FROM t_stu WHERE id = 6
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對象,得到statement
st = conn.createStatement();
//3. 執(zhí)行添加
String sql = "delete from t_stu where name='aobama'";
//影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);
if(result >0 ){
System.out.println("刪除成功");
}else{
System.out.println("刪除失敗");
}
-
query(查)
SELECT * FROM t_stu
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對象,得到statement
st = conn.createStatement();
// 3. 執(zhí)行sql語句,返回ResultSet
String sql = "select * from t_stu";
rs = st.executeQuery(sql);
// 4. 遍歷結(jié)果集
while (rs.next()) {
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(name + " " + age);
}
-
update(改)
UPDATE t_stu SET age = 38 WHERE id = 1;
// 1. 獲取連接對象
conn = JDBCUtil.getConn();
// 2. 根據(jù)連接對象,得到statement
st = conn.createStatement();
//3. 執(zhí)行添加
String sql = "update t_stu set age = 26 where name ='qyq'";
//影響的行數(shù), ,如果大于0 表明操作成功。 否則失敗
int result = st.executeUpdate(sql);
if(result >0 ){
System.out.println("更新成功");
}else{
System.out.println("更新失敗");
}
使用單元測試,測試代碼
定義一個(gè)類, TestXXX , 里面定義方法 testXXX.
-
添加junit的支持。
右鍵工程 --- add Library --- Junit --- Junit4
-
在方法的上面加上注解 , 其實(shí)就是一個(gè)標(biāo)記。
@Test
public void testQuery() {
...
} 光標(biāo)選中方法名字,然后右鍵執(zhí)行單元測試。 或者是打開outline視圖, 然后選擇方法右鍵執(zhí)行。
Dao模式
Data Access Object 數(shù)據(jù)訪問對象
- 新建一個(gè)dao的接口, 里面聲明數(shù)據(jù)庫訪問規(guī)則
/**
* 定義操作數(shù)據(jù)庫的方法
*/
public interface UserDao {
/**
* 查詢所有
*/
void findAll();
}
- 新建一個(gè)dao的實(shí)現(xiàn)類,具體實(shí)現(xiàn)早前定義的規(guī)則
public class UserDaoImpl implements UserDao{
@Override
public void findAll() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
//1. 獲取連接對象
conn = JDBCUtil.getConn();
//2. 創(chuàng)建statement對象
st = conn.createStatement();
String sql = "select * from t_user";
rs = st.executeQuery(sql);
while(rs.next()){
String userName = rs.getString("username");
String password = rs.getString("password");
System.out.println(userName+"="+password);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, st, rs);
}
}
}
-
直接使用實(shí)現(xiàn)
@Test
public void testFindAll(){
UserDao dao = new UserDaoImpl();
dao.findAll();
}
Statement安全問題
- Statement執(zhí)行 ,其實(shí)是拼接sql語句的。 先拼接sql語句,然后在一起執(zhí)行。
String sql = "select * from t_user where username='"+ username +"' and password='"+ password +"'";
UserDao dao = new UserDaoImpl();
dao.login("admin", "100234khsdf88' or '1=1");
SELECT * FROM t_user WHERE username='admin' AND PASSWORD='100234khsdf88' or '1=1'
前面先拼接sql語句, 如果變量里面帶有了 數(shù)據(jù)庫的關(guān)鍵字,那么一并認(rèn)為是關(guān)鍵字。 不認(rèn)為是普通的字符串。
rs = st.executeQuery(sql);
PrepareStatement
該對象就是替換前面的statement對象。
- 相比較以前的statement, 預(yù)先處理給定的sql語句,對其執(zhí)行語法檢查。 在sql語句里面使用 ? 占位符來替代后續(xù)要傳遞進(jìn)來的變量。 后面進(jìn)來的變量值,將會被看成是字符串,不會產(chǎn)生任何的關(guān)鍵字。
String sql = "insert into t_user values(null , ? , ?)";
ps = conn.prepareStatement(sql);
//給占位符賦值 從左到右數(shù)過來,1 代表第一個(gè)問號, 永遠(yuǎn)你是1開始。
ps.setString(1, userName);
ps.setString(2, password);
?
總結(jié):
JDBC入門
抽取工具類 ###
-
Statement CRUD ###
演練crud
-
Dao模式 ###
聲明與實(shí)現(xiàn)分開
-
PrepareStament CRUD ###
預(yù)處理sql語句,解決上面statement出現(xiàn)的問題
作業(yè):
1. dao里面聲明 增刪查改, 以及登錄的方法
登錄方法 :
要求,成功后返回該用戶的所有信息。 字段不限。
查詢:
如果是findAll. 肯定是返回一個(gè)集合 List<User>
增加 & 刪除 & 更新
返回影響的行數(shù)即可 int類型