一、認識JDBC
JDBC
是用於在Java
語言程式設計中與資料庫連線的API
.JDBC
是一個規範,它提供了一整套介面,允許以一種可移植的訪問底層資料庫API
。使用JDBC驅動程式
來訪問資料庫,並用於儲存資料到資料庫中.
解釋上面兩幅圖:
java應用程式通過JDBC API首先連線到JDBC Driver,這些JDBC驅動器都是由各大資料庫廠家針對JDBC提供的,我們可以在網上下載jar包來使用,然後通過JDBC驅動器就能連線到我們的資料庫了。
第一步 新增驅動
1.在專案當中建立一個資料夾為lib
2.把Mysql驅動包複製到該資料夾下
3.builder path 編譯路徑
複製程式碼
第二步 連線到資料庫
package con.meils.jdbc.conn;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionClass {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// TODO Auto-generated method stub
// 1、載入驅動
// 把com.mysql.jdbc.Driver這份位元組碼載入進JVM
// 當一份位元組碼載入進JVM的時候,就會執行位元組碼檔案中的靜態程式碼塊
// 這裡載入該位元組碼之後會例項化一個驅動器
Class.forName("com.mysql.jdbc.Driver");
// 2、連線
String url = "jdbc:mysql://localhost:3306/mytest";
String username = "root";
String password = "zjj19970517";
Connection connection = DriverManager.getConnection(url, username, password);
// 3、驗證連線
System.out.println(connection); // 如果有輸出,表明連線成功
}
}
複製程式碼
第三步 運算元據庫建立表
package con.meils.jdbc.ddl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class CreateTable {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 1\載入驅動
// 把com.mysql.jdbc.Driver這份位元組碼載入進JVM
// 當一份位元組碼載入進JVM的時候,就會執行位元組碼檔案中的靜態程式碼塊
// 這裡載入該位元組碼之後會例項化一個驅動器
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jdbc_db";
String username = "root";
String password = "zjj19970517";
// 2\ 連線資料庫
Connection connection = DriverManager.getConnection(url, username, password);
// 3\建立sql語句
String sql = "create table stu (id int , name varchar(20), age int)";
// 4\執行sql語句
Statement st = connection.createStatement();
int row = st.executeUpdate(sql);
// 5\釋放
st.close();
connection.close();
}
}
複製程式碼
為什麼要釋放資源呢?
第四步 插入資料
package con.meils.jdbc.dml;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class InsertClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
// ================ 插入資料 ================
Connection conn = null;
Statement st = null;
try {
// 1、載入驅動
Class.forName("com.mysql.jdbc.Driver");
// 2、建立連線
String url = "jdbc:mysql://localhost:3306/mytest";
String user = "root";
String password = "zjj19970517";
conn = DriverManager.getConnection(url, user, password);
// 3、建立sql語句
String sql = "insert into stu values(1, 'zjj', 20)";
st = conn.createStatement();
// 4、執行語句
int row = st.executeUpdate(sql);
System.out.println(row);
}catch (Exception e) {
e.printStackTrace();
} finally {
// 5、釋放
if(st!=null) {
try {
st.close();
}catch (Exception e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
複製程式碼
第五步 查詢操作
package con.meils.jdbc.dql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class QueryClass {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
// TODO Auto-generated method stub
// ================ 查詢資料 ================
// 1\載入驅動
// 把com.mysql.jdbc.Driver這份位元組碼載入進JVM
// 當一份位元組碼載入進JVM的時候,就會執行位元組碼檔案中的靜態程式碼塊
// 這裡載入該位元組碼之後會例項化一個驅動器
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mytest";
String username = "root";
String password = "zjj19970517";
// 2\ 連線資料庫
Connection connection = DriverManager.getConnection(url, username, password);
// 3\建立sql語句
String sql = "select count(*) as total from stu"; // 查詢一共有幾行資料
// 4\執行sql語句
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
if(rs.next()) {
int count = rs.getInt("total");
System.out.println(count); // 1
}
// 5\釋放
st.close();
connection.close();
}
}
複製程式碼
資料型別對照表:
上面我們基本學會了如何與資料庫打交道,但是這樣使用存在許多的弊端,比如:每一步操作都進行一次資料庫連線,造成浪費,所以我們在實際中要使用DAO思想來處理。
二、DAO設計
1、什麼是DAO
DAO(Data Access Object)資料儲存物件,介於業務邏輯層和持久層之間,實現持久化資料訪問。
不使用DAO的時候:
使用DAO的情況:
三、ORM對映關係
四、Domain
1、認識domain
2、domain類
3、儲存資料
4、獲取資料
五、DAO設計規範
案例
我們可以編寫一個DAO介面,定義了常用的資料庫操作方法,這時候我們同時會連線多個資料庫,比如是mysql 和 oracle ,我們可以分別實現oracleDao和mysqlDao兩個類,不同類裡面定義不同的運算元據庫的程式碼,實現的功能確實相同的。
所以面向介面程式設計是很重要的,也是一個很好的方式。
1、包命名規範
2、類命名規範
3、開發步驟
目錄如下
內容實現:
介面實現類的具體內容:
package com.meils.jdbc.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.meils.jdbc.dao.IStudentDao;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
/**
* 實現DAO介面的類
* @author apple
*
*/
public class StudentDaoImpl implements IStudentDao{
@Override
/**
* 儲存學生
* @param stu
*/
public void save(Student stu) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement ps = null;
try {
// 連線資料庫
conn = JdbcUtil.getConnection();
String sql = "insert into student (name, age) values (? , ?)";
// 建立預編譯
ps = conn.prepareStatement(sql);
ps.setString(1, stu.getName());
ps.setInt(2, stu.getAge());
// 執行更新
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public void delete(int id) {
Connection conn = null;
PreparedStatement ps = null;
try {
// 連線資料庫
conn = JdbcUtil.getConnection();
String sql = "delete from student where id = ?";
// 建立預編譯
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
// 執行更新
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public void update(int id, Student stu) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "update student set name=?, age=? where id = ? ";
ps = conn.prepareStatement(sql);
ps.setString(1, stu.getName());
ps.setInt(2, stu.getAge());
ps.setInt(3, id);
// 執行
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, ps, null);
}
}
@Override
public Student findOne(int id) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
// sql語句
String sql = "select * from student where id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
// 執行
rs = ps.executeQuery();
if (rs.next()) {
// 儲存資料
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
return stu;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 銷燬
JdbcUtil.close(conn, ps, rs);
}
return null;
}
@Override
public List<Student> findAll() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
st = conn.createStatement();
String sql = "select * from student ";
rs = st.executeQuery(sql);
List<Student> list = new ArrayList<Student>();
while (rs.next()) {
Student stu = new Student();
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
stu.setId(rs.getInt("id"));
list.add(stu);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, st, rs);
}
return null;
}
}
複製程式碼
編寫測試類:
package com.meils.jdbc.dao.test;
import java.util.List;
import org.junit.Test;
import com.meils.jdbc.dao.IStudentDao;
import com.meils.jdbc.dao.impl.StudentDaoImpl;
import com.meils.jdbc.domain.Student;
/**
* StudentDao測試類
* @author apple
*/
public class StudentDaoTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
@Test
public void save() {
Student stu = new Student();
stu.setName("張偉");
stu.setAge(21);
IStudentDao dao = new StudentDaoImpl();
dao.save(stu);
}
@Test
public void delete() {
IStudentDao dao = new StudentDaoImpl();
dao.delete(4);
}
@Test
public void update () {
Student stu = new Student();
stu.setName("mmmmm");
stu.setAge(16);
IStudentDao dao = new StudentDaoImpl();
dao.update(5, stu);
}
@Test
public void findOne() {
IStudentDao dao = new StudentDaoImpl();
Student stu = dao.findOne(5);
System.out.println(stu);
}
@Test
public void findAll() {
IStudentDao dao = new StudentDaoImpl();
List<Student> allStu = dao.findAll();
System.out.println(allStu);
}
}
複製程式碼
JDBC工具類:
package com.meils.jdbc.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* JDBC 工具類
* @author apple
*
*/
public class JdbcUtil {
// 配置資訊
public static String driverName = "com.mysql.jdbc.Driver";
public static String url = "jdbc:mysql://localhost:3306/mytest";
public static String userName = "root";
public static String password = "zjj19970517";
static {
try {
// 載入驅動,因為是在static塊中,所以只會載入一次
Class.forName(JdbcUtil.driverName);
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 連線資料庫
* @return 返回連線物件
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection(JdbcUtil.url, JdbcUtil.userName, JdbcUtil.password);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 關閉連線,並釋放資源
* @param conn
* @param st
* @param rs
*/
public static void close(Connection conn, Statement st, ResultSet rs) {
if(conn!=null) {
try {
conn.close();
}catch(Exception e) {
e.printStackTrace();
}
}
if(st!=null) {
try {
st.close();
}catch(Exception e) {
e.printStackTrace();
}
}
if(rs!=null) {
try {
rs.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
複製程式碼
3、DAO程式碼重構
4、Statement介面
1 Statement 是父介面,PreparedStatement 和 CallableStatement 是子介面。
2 Statement 用於java應用程式與資料庫之間的傳送資料,比如傳送sql語句過去,到資料庫執行操作。
3 Statement 用於通用的訪問,使用靜態sql,其實並不好,容易SQL隱碼攻擊
4 PreparedStatement 用於預編譯模版SQL語句,可以在執行的時候傳入引數
5 CallableStatement 訪問儲存過程的時候使用
複製程式碼
5、預編譯語句
防止SQL隱碼攻擊:
6、通過DB類來運算元據庫
JDBC的另一種封裝方法:
package com.meils.jdbc.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class MysqlDB {
Connection conn = null; // 建立連線物件
Statement st = null; // 建立編譯語句物件
PreparedStatement ps = null; // 建立預編譯語句物件
ResultSet rs1 = null; // 結果集
// 配置資訊
// 驅動名稱
private static final String driverName = "com.mysql.jdbc.Driver";
// 資料庫的地址
private static final String URL = "jdbc:mysql://localhost:3306/mytest";
// 資料庫登入使用者名稱
private static final String userName = "root";
// 資料庫登入密碼
private static final String pwd = "zjj19970517";
/**
* 連線資料庫
* @return
*/
public Connection getConnection() {
try {
Class.forName(driverName);
this.conn = DriverManager.getConnection(URL, userName, pwd);
System.out.println("連線成功");
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 建構函式
public MysqlDB() {
this.getConnection();
}
/**
* 查詢
* @param sql sql語句,完整的語句,查詢一般比較安全
* @return
*/
public ResultSet query(String sql) {
try {
this.st = this.conn.createStatement();
this.rs1 = this.st.executeQuery(sql);
return rs1;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* 更新
* @param sql // 預編譯sql語句
* @param args // 引數陣列
*/
public void update(String sql, String [] args) {
try {
this.ps = this.conn.prepareStatement(sql);
for (int i = 0 ; i < args.length ; i++) {
this.ps.setString(i+1, args[i]);
}
this.ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
this.close();
}
}
/**
* 刪除
* @param sql
* @return
*/
public int delete(String sql){
try {
this.st = this.conn.createStatement();
int num = this.st.executeUpdate(sql);
return num;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
this.close();
}
return 0;
}
/**
* 釋放資源
*/
public void close () {
try {
if(rs1!=null) {
rs1.close();
}
if(st!=null) {
st.close();
}
if(ps!=null) {
ps.close();
}
if(conn!=null) {
conn.close();
}
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
複製程式碼
測試以下:
package com.meils.jdbc.db;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
// Conn();
delete();
}
// 測試連線
public static void Conn() {
MysqlDB m = new MysqlDB();
}
// 測試查詢
public static void queryTest() {
MysqlDB m = new MysqlDB();
String sql = "select * from student";
ResultSet result = m.query(sql);
System.out.println(result);
try {
while (result.next()) {
System.out.println(result.getString("name"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
m.close();
}
}
// 更新
public static void update() {
MysqlDB m = new MysqlDB();
String sql = "update student set name = ? where id = ?";
String [] args = {"梅子111", "7"};
m.update(sql, args);
}
// 刪除
public static void delete() {
MysqlDB m = new MysqlDB();
String sql = "delete from student where id = 8";
System.out.println(m.delete(sql));
}
}
複製程式碼
7、呼叫儲存過程
首先我們熟悉一下儲存過程
// 新建儲存過程
DELIMITER //
create PROCEDURE getStudent1(in n varchar(20))
BEGIN
select * from student where name = n;
END //
DELIMITER ;
// 執行
call getStudent1('張錦傑');
複製程式碼
測試一下: (非常尷尬好像並沒有結果,也沒有報錯,不知道是什麼原因~~)
package com.meils.jdbc.dao.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
public class ProductTest {
public static void main(String[] args) {
CallableStatement cstmt = null;
try {
//1.連線
Connection conn = JdbcUtil.getConnection();
//2.
CallableStatement cs = conn.prepareCall("{ call getStu(?)}");
//3.設定引數
cs.setString(1, "張錦傑");
//4.執行
ResultSet rs = cs.executeQuery();
if(rs.next()) {
Student stu = new Student();
stu.setId(rs.getInt("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
System.out.println(stu);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
複製程式碼
帶有引數和輸出的儲存過程
// 帶有引數和輸出的儲存過程
DELIMITER //
CREATE PROCEDURE getName ( IN i INT, OUT n VARCHAR ( 50 ) ) BEGIN
SELECT NAME INTO
n
FROM
student
WHERE
id = i;
END // DELIMITER;
call getName(1, @name);
select @name;
複製程式碼
測試一下:
package com.meils.jdbc.dao.test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import com.meils.jdbc.domain.Student;
import com.meils.jdbc.utils.JdbcUtil;
public class ProductTest {
public static void main(String[] args) {
CallableStatement cstmt = null;
try {
//1.建立連線
Connection conn = JdbcUtil.getConnection();
//2.建立預編譯語句
CallableStatement cs = conn.prepareCall("{ call getName(?,?)}");
//3.設定引數
cs.setInt(1, 1);
//4.設定輸出引數
cs.registerOutParameter(2, Types.VARCHAR);
//5.執行
cs.execute();
//6.獲取到輸出的引數
String name = cs.getString(2);
System.out.println(name); // 張錦傑
} catch (Exception e) {
e.printStackTrace();
}
}
}
複製程式碼
8、事物
例項:首先在減少錢之前關閉自動提交事務,期間可以進行多個操作,此時的事務提交必須手動了,需要使用conn.commit();
。如果在中間發生了異常,那麼就進行回滾,釋放資源。
9、批處理
通常情況下如果我們想要一次性執行許多條sql語句,我們都是一條執行完畢再執行下一條,當我們使用了批處理之後,我們就可以一次性執行多條語句,話費的事件將大大縮短。
10、將檔案存入資料庫
通常我們不會這麼做的,因為資料庫的空間是非常寶貴的,檔案較大,佔用的空間也較大,成本也就高了,假如我們需要存檔案,那麼就要選擇blob型別了,它是以二進位制的形式來存取的,可以存視訊、圖片、等多媒體資訊。
首先需要設定資料庫中的欄位型別為blob。
複製程式碼
儲存檔案到資料庫:
將資料庫中的檔案取出來:
11、獲取自動生成的主鍵id
需求分析:
我們可能回遇到這樣的情景,我們首先註冊資訊,填入使用者明和密碼後,註冊成功,此時的資料庫中的id是自動新增進去的,接下來回讓自己去完善自己的資訊,這就要需要我們剛才建立的id了,那麼如何返回id給我們下次使用呢?
兩種方式獲取:
1:
2: