概念
- 之前操作數據(客戶端工具)
登錄到服務器(mysql -u root -p root)
編寫sql的語句
發(fā)送sql語句到數據庫服務器執(zhí)行
- jdbc
使用java代碼(程序)操作數據庫(發(fā)送sql語句),的技術就是jdbc技術
- 使用jdbc執(zhí)行sql的前提
登錄數據庫的服務器(連接數據庫服務器)
1.數據庫的IP地址
2.端口
3.數據庫的用戶名/密碼
image.png
image.png
jdbc的接口在哪里:
java.sql.*
javax.sql.*
代碼詳情
package cn.persistXl.jdbc;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* jdbc鏈接數據庫
* @author persistXL
* @data 2018/4/29 14:51
*/
public class TestJdbc {
//鏈接數據庫的url
private String url = "jdbc:mysql://localhost:3306";
private String user = "root";
private String password = "root";
/**
* 包括兩部分 jdbc協議:數據庫子協議:主機:端口/需要鏈接的數據庫
*/
/**
*
* 第一種相連接數據庫的方法
* @throws Exception
*/
@Test
public void test() throws Exception {
//創(chuàng)建驅動程序類對象
Driver driver = new com.mysql.jdbc.Driver();
//設置一個Properties
Properties properties = new Properties();
properties.setProperty("user", user);
properties.setProperty("password", password);
//鏈接數據庫,返回鏈接對象
Connection conn = driver.connect(url,properties);
System.out.println(conn);
}
/**
* 使用驅動管理器類鏈接數據庫
* 第二種鏈接數據庫的方法
*/
@Test
public void test1() throws SQLException {
//注冊驅動程序(可注冊多個驅東程序)
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
//鏈接到具體的數據庫
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
/**
*最終的簡潔版本
*/
@Test
public void test2() throws SQLException {
/* Driver driver = new com.mysql.jdbc.Driver();
//注冊驅動程序(可注冊多個驅東程序)
DriverManager.registerDriver(driver);*/
//通過字節(jié)碼對象的方式加載靜態(tài)代碼塊啼肩,從而注冊驅動程序
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//鏈接到具體的數據庫
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
}
- 常用的方式
public class TestJdbc {
//鏈接數據庫的url
private String url = "jdbc:mysql://localhost:3306";
private String user = "root";
private String password = "root";
/**
* 包括兩部分 jdbc協議:數據庫子協議:主機:端口/需要鏈接的數據庫
*/
@Test
public void test2() throws SQLException {
/* Driver driver = new com.mysql.jdbc.Driver();
//注冊驅動程序(可注冊多個驅動程序)
DriverManager.registerDriver(driver);*/
//通過字節(jié)碼對象的方式加載靜態(tài)代碼塊栗涂,從而注冊驅動程序
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//鏈接到具體的數據庫
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
}
}
JDBC接口的核心的API
java.sql.* 和 javax.sql.*
|---Driver 接口:表示java驅動程序接口曹货,所有的具體的數據庫廠商要來實現此接口
|-- connect(url,properties):連接數據庫的方法
url : 連接數據庫的URL
URL語法:jsbc協議:數據庫子協議://主機:端口/數據庫
user:數據庫的用戶名
password:數據庫用戶密碼
|--DriverManager 類:驅動管理器蚊俺,用于管理所有的注冊的驅動程序
|--registerDriver(driver):注冊驅動類對象
|--Connection getConnection(url,user,password); 獲取連接對象
|-- Connection接口:表示Java程序和數據庫的連接對象
|--Statement createStatement();創(chuàng)建一個Statement對象
|--PreparedStatement preparedStatement(String sql);創(chuàng)建PreparedStatement對象
|- CallableStatement prepareCall(String sql) 創(chuàng)建CallableStatement對象
|- Statement接口: 用于執(zhí)行靜態(tài)的sql語句
|- int executeUpdate(String sql) : 執(zhí)行靜態(tài)的更新sql語句(DDL,DML)
|- ResultSet executeQuery(String sql) :執(zhí)行的靜態(tài)的查詢sql語句(DQL)
|-PreparedStatement接口:用于執(zhí)行預編譯sql語句
|- int executeUpdate() : 執(zhí)行預編譯的更新sql語句(DDL邑闺,DML)
|-ResultSet executeQuery() : 執(zhí)行預編譯的查詢sql語句(DQL)
|-CallableStatement接口:用于執(zhí)行存儲過程的sql語句(call xxx)
|-ResultSet executeQuery() : 調用存儲過程的方法
|- ResultSet接口:用于封裝查詢出來的數據
|- boolean next() : 將光標移動到下一行
|-getXX() : 獲取列的值
使用Statement執(zhí)行sql語句
- 執(zhí)行DDL語句(創(chuàng)建表)
package cn.persistXl.statement;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author persistXL
* @data 2018/4/29 16:57
*/
public class StatementTest {
private String url = "jdbc:mysql://localhost:3306/jdbc";
private String user = "root";
private String password = "root";
/**
*
* 執(zhí)行DDL語句
*/
@Test
public void test(){
int count = 0;
Connection conn = null;
Statement stmt = null;
try {
//連接數據庫,注冊驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接對象
conn = DriverManager.getConnection(url, user, password);
//創(chuàng)建statement對象
stmt = conn.createStatement();
//準備sql
String sql = "CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20),gender VARCHAR(4))";
//發(fā)送sql語句并執(zhí)行,得到返回的結果
count = stmt.executeUpdate(sql);
//輸出
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally {
//關閉連接(順序:先打開都關閉)
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- 執(zhí)行DML語句(操作表內容)
package cn.persistXl.statement;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @author persistXL
* @data 2018/4/29 18:06
*/
/**
* 使用statement執(zhí)行DML語句
*/
public class DmlTest {
/**
* 增加
*/
private String url = "jdbc:mysql://localhost:3306/jdbc";
private String name = "root";
private String password = "root";
@Test
public void testInsert() throws SQLException{
Connection conn = null;
Statement stmt = null;
try {
//注冊驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接對象
conn = DriverManager.getConnection(url, name, password);
//創(chuàng)建Statement對象
stmt = conn.createStatement();
//準備sql語句
String sql = "insert into student(name,gender) VALUES ('zhangsan','nan')";
//執(zhí)行sql
int count = stmt.executeUpdate(sql);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testUpdate() throws SQLException{
Connection conn = null;
Statement stmt = null;
try {
//注冊驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取連接對象
conn = DriverManager.getConnection(url, name, password);
//創(chuàng)建Statement對象
stmt = conn.createStatement();
//準備sql語句
String sql = "UPDATE student SET gender='nv' WHERE id='1'";
//執(zhí)行sql
int count = stmt.executeUpdate(sql);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- 創(chuàng)建公共的 db.properties
作用:當連接的數據庫不是MySQL時在這里修改棕兼,當訪問的數據庫需要改變時在這里修改
url=jdbc:mysql://localhost:3306/day17
user=root
password=root
driverClass=com.mysql.jdbc.Driver
- 抽取公共類(JdbcUtil)
package cn.persistXl.util;
/**
* @author persistXL
* @data 2018/4/29 18:27
*/
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* jdbc 的工具類
*/
public class JdbcUtil {
private static String url = null;
private static String name = null;
private static String password = null;
private static String driverClass = null;
/**
* 靜態(tài)代碼塊(只加載一次)
*/
static {
try {
//讀取db.properties文件
Properties props = new Properties();
/**
* . 代表java命令運行的目錄
* 在java項目下陡舅,. java命令的運行目錄從項目的根目錄開始
* 在web項目下, . java命令的而運行目錄從tomcat/bin目錄開始
* 所以不能使用點.
*/
//FileInputStream in = new FileInputStream("./src/db.properties"); //若使用java項目時沒有問題伴挚,若使用web項目時文件的路徑就有問題
/**
* 使用類路徑的讀取方式
* / : 斜杠表示classpath的根目錄
* 在java項目下靶衍,classpath的根目錄從bin目錄開始
* 在web項目下,classpath的根目錄從WEB-INF/classes目錄開始
*/
InputStream in = JdbcUtil.class.getResourceAsStream("/db.properties");
//加載文件
props.load(in);
//讀取信息
url = props.getProperty("url");
name = props.getProperty("user");
password = props.getProperty("password");
driverClass = props.getProperty("driverClass");
//注冊驅動程序
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
System.out.println("驅動程序注冊失敗");
}
}
/**
* 抽取獲取連接對象的方法
*/
public static Connection getConnection() {
try {
Connection conn = DriverManager.getConnection(url, name, password);
return conn;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 釋放資源的方法
*/
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection conn, Statement stmt) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- 執(zhí)行DQL語句(查詢)
package cn.persistXl.statement;
/**
* @author persistXL
* @data 2018/4/29 19:50
*/
import cn.persistXl.util.JdbcUtil;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* 使用statement執(zhí)行DQL語句(查詢語句)
*/
public class InsertTest {
@Test
public void inseret(){
Connection conn = null;
Statement stmt = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//創(chuàng)建statement
stmt = conn.createStatement();
//準備sql
String sql = "SELECT * FROM student";
//執(zhí)行sql
ResultSet rs = stmt.executeQuery(sql);
//移動光標
boolean flag = rs.next();
if (flag) {
//取出列的值(根據索引值)
/*
int id = rs.getInt(1);
String name = rs.getString(2);
String gender = rs.getString(3);
System.out.println(id+name+gender);
*/
//根據列的名稱
/*
int id = rs.getInt("id");
String name = rs.getString("gender");
String gender = rs.getString("name");
System.out.println(id+name+gender);
*/
//遍歷結果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("gender");
String gender = rs.getString("name");
System.out.println(id+name+gender);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用PreparedStatement執(zhí)行sql
package cn.persistXl.PreparedStatement;
import cn.persistXl.util.JdbcUtil;
import org.junit.Test;
import java.sql.*;
/**
* @author persistXL
* @data 2018/4/29 20:26
*/
/**
* 使用PreparedStatement執(zhí)行sql語句
*/
public class PreparedStatementTest {
/**
* 增加
*/
@Test
public void InsertTest(){
Connection conn = null;
PreparedStatement stmt = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "insert into student (name,gender) values (?,?)";
//?表示一個參數占位符
//執(zhí)行預編譯sql語句(檢查語法)
stmt = conn.prepareStatement(sql);
//設置參數值
stmt.setString(1,"李四");
stmt.setString(2,"男");
//發(fā)送參數茎芋,執(zhí)行sql
stmt.executeUpdate();
System.out.println(stmt);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt);
}
}
/**
* 修改
*/
@Test
public void UpdateTest(){
Connection conn = null;
PreparedStatement stmt = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "UPDATE student SET name=? WHERE id=?";
//?表示一個參數占位符
//執(zhí)行預編譯sql語句(檢查語法)
stmt = conn.prepareStatement(sql);
//設置參數值
stmt.setString(1,"王五");
stmt.setInt(2,2);
//發(fā)送參數颅眶,執(zhí)行sql
stmt.executeUpdate();
System.out.println(stmt);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt);
}
}
/**
* 刪除
*/
@Test
public void DeleteTest(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "DELETE FROM student WHERE id=?";
//?表示一個參數占位符
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt, rs);
}
}
/**
* 查詢
*/
@Test
public void SelectTest(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備預編譯sql
String sql = "select * from student";
//預編譯
stmt = conn.prepareStatement(sql);
//執(zhí)行sql
rs = stmt.executeQuery();
boolean flag = rs.next();
System.out.println(flag);
if (flag) {
//便利rs
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
System.out.println(id + "," + name + "," + gender);
}
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt, rs);
}
}
}
兩種方式的登錄的比較
package cn.persistXl.PreparedStatement;
/**
* @author persistXL
* @data 2018/4/29 21:38
*/
import cn.persistXl.util.JdbcUtil;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
/**
* 模擬用戶登錄
*/
public class Index {
//模擬用戶輸入
private String name = "admin";
private String password = "admin";
/**
* statement存在sql注入風險
*/
/* @Test
public void idnex(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//創(chuàng)建statement
stmt = conn.createStatement();
//準備sql
String sql = "select * from user where name = '"+name+"' and password = '"+password+"'";
//執(zhí)行sql
rs = stmt.executeQuery(sql);
if (rs.next()) {
//登錄成功
System.out.println("登錄成功");
} else {
//登錄失敗
System.out.println("登錄失敗");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt, rs);
}
}*/
@Test
public void idnex(){
/**
* PreparedStatement有效預防sql注入
*
*/
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "select * from user where name =? and password = ?";
//創(chuàng)建sql預編譯
stmt = conn.prepareStatement(sql);
//設置參數
stmt.setString(1, name);
stmt.setString(2, password);
//執(zhí)行sql
rs = stmt.executeQuery();
if (rs.next()) {
//登錄成功
System.out.println("登錄成功");
} else {
//登錄失敗
System.out.println("登錄失敗");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtil.close(conn, stmt, rs);
}
}
}
//statement登錄時存在sql被注入的風險,PrepareStatement則不存在
PreparedStatement vs Statment
1)語法不同:PreparedStatement可以使用預編譯的sql田弥,而Statment只能使用靜態(tài)的sql
2)效率不同: PreparedStatement可以使用sql緩存區(qū)涛酗,效率比Statment高
3)安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入偷厦。
推薦使用PreparedStatement
CallableStatement執(zhí)行存儲過程
/**
* 使用CablleStatement調用存儲過程
* @author APPle
*
*/
public class Demo1 {
/**
* 調用帶有輸入參數的存儲過程
* CALL pro_findById(4);
*/
@Test
public void test1(){
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "CALL pro_findById(?)"; //可以執(zhí)行預編譯的sql
//預編譯
stmt = conn.prepareCall(sql);
//設置輸入參數
stmt.setInt(1, 6);
//發(fā)送參數
rs = stmt.executeQuery(); //注意: 所有調用存儲過程的sql語句都是使用executeQuery方法執(zhí)行I烫尽!沪哺!
//遍歷結果
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
System.out.println(id+","+name+","+gender);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
JdbcUtil.close(conn, stmt ,rs);
}
}
/**
* 執(zhí)行帶有輸出參數的存儲過程
* CALL pro_findById2(5,@NAME);
*/
@Test
public void test2(){
Connection conn = null;
CallableStatement stmt = null;
ResultSet rs = null;
try {
//獲取連接
conn = JdbcUtil.getConnection();
//準備sql
String sql = "CALL pro_findById2(?,?)"; //第一個沈自?是輸入參數酌儒,第二個辜妓?是輸出參數
//預編譯
stmt = conn.prepareCall(sql);
//設置輸入參數
stmt.setInt(1, 6);
//設置輸出參數(注冊輸出參數)
/**
* 參數一: 參數位置
* 參數二: 存儲過程中的輸出參數的jdbc類型 VARCHAR(20)
*/
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
//發(fā)送參數,執(zhí)行
stmt.executeQuery(); //結果不是返回到結果集中忌怎,而是返回到輸出參數中
//得到輸出參數的值
/**
* 索引值: 預編譯sql中的輸出參數的位置
*/
String result = stmt.getString(2); //getXX方法專門用于獲取存儲過程中的輸出參數
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
JdbcUtil.close(conn, stmt ,rs);
}
}
}
總結
JDBC的五部曲
//獲取連接
Connection conn = JdbcUtil.getConnection();
//準備sql
String sql = "";
//創(chuàng)建PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(sql);
//設置參數值
stmt.setString(1,"");
//發(fā)送參數籍滴,執(zhí)行sql
stmt.executeUpdate();
//關閉連接(finally內關閉)
JdbcUtil.close(conn, stmt); || JdbcUtil.close(conn, stmt, rs);