Java 之 JDBC

meils發表於2019-02-27

一、認識JDBC

JDBC是用於在Java語言程式設計中與資料庫連線的API.JDBC是一個規範,它提供了一整套介面,允許以一種可移植的訪問底層資料庫API。使用JDBC驅動程式來訪問資料庫,並用於儲存資料到資料庫中.

Java 之 JDBC

Java 之 JDBC

Java 之 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();
		
		
		
	}

}

複製程式碼

Java 之 JDBC

為什麼要釋放資源呢?

Java 之 JDBC

第四步 插入資料

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();
				}
			}
			
			
		}
		
	}

}

複製程式碼

第五步 查詢操作

Java 之 JDBC

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();
	}

}

複製程式碼

Java 之 JDBC

Java 之 JDBC

Java 之 JDBC

資料型別對照表:

Java 之 JDBC

上面我們基本學會了如何與資料庫打交道,但是這樣使用存在許多的弊端,比如:每一步操作都進行一次資料庫連線,造成浪費,所以我們在實際中要使用DAO思想來處理。

二、DAO設計

1、什麼是DAO

Java 之 JDBC

DAO(Data Access Object)資料儲存物件,介於業務邏輯層和持久層之間,實現持久化資料訪問。

不使用DAO的時候:

Java 之 JDBC

使用DAO的情況:

Java 之 JDBC

三、ORM對映關係

Java 之 JDBC

四、Domain

1、認識domain

Java 之 JDBC

2、domain類

Java 之 JDBC

3、儲存資料

Java 之 JDBC

4、獲取資料

Java 之 JDBC

五、DAO設計規範

Java 之 JDBC

案例

我們可以編寫一個DAO介面,定義了常用的資料庫操作方法,這時候我們同時會連線多個資料庫,比如是mysql 和 oracle ,我們可以分別實現oracleDao和mysqlDao兩個類,不同類裡面定義不同的運算元據庫的程式碼,實現的功能確實相同的。

Java 之 JDBC

所以面向介面程式設計是很重要的,也是一個很好的方式。

1、包命名規範

Java 之 JDBC

2、類命名規範

Java 之 JDBC

3、開發步驟

Java 之 JDBC

目錄如下

Java 之 JDBC

內容實現:

Java 之 JDBC

介面實現類的具體內容:

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();
			}
		}
	}
}

複製程式碼

專案github地址

3、DAO程式碼重構

Java 之 JDBC

4、Statement介面

Java 之 JDBC

Java 之 JDBC

1 Statement 是父介面,PreparedStatement 和 CallableStatement 是子介面。

2 Statement 用於java應用程式與資料庫之間的傳送資料,比如傳送sql語句過去,到資料庫執行操作。

3 Statement 用於通用的訪問,使用靜態sql,其實並不好,容易SQL隱碼攻擊

4 PreparedStatement 用於預編譯模版SQL語句,可以在執行的時候傳入引數

5 CallableStatement 訪問儲存過程的時候使用
複製程式碼

5、預編譯語句

Java 之 JDBC

防止SQL隱碼攻擊:

Java 之 JDBC

java JDBC DAO封裝教程

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、呼叫儲存過程

首先我們熟悉一下儲存過程

Java 之 JDBC

// 新建儲存過程
DELIMITER //
create PROCEDURE getStudent1(in n varchar(20))
BEGIN

	select * from student where name = n;
END //
DELIMITER ;

// 執行
call getStudent1('張錦傑');
複製程式碼

Java 之 JDBC
測試一下: (非常尷尬好像並沒有結果,也沒有報錯,不知道是什麼原因~~)

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;
複製程式碼

Java 之 JDBC
測試一下:

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、事物

Java 之 JDBC
例項:

Java 之 JDBC

首先在減少錢之前關閉自動提交事務,期間可以進行多個操作,此時的事務提交必須手動了,需要使用conn.commit();。如果在中間發生了異常,那麼就進行回滾,釋放資源。

9、批處理

Java 之 JDBC

Java 之 JDBC

Java 之 JDBC

通常情況下如果我們想要一次性執行許多條sql語句,我們都是一條執行完畢再執行下一條,當我們使用了批處理之後,我們就可以一次性執行多條語句,話費的事件將大大縮短。

10、將檔案存入資料庫

Java 之 JDBC

通常我們不會這麼做的,因為資料庫的空間是非常寶貴的,檔案較大,佔用的空間也較大,成本也就高了,假如我們需要存檔案,那麼就要選擇blob型別了,它是以二進位制的形式來存取的,可以存視訊、圖片、等多媒體資訊。

首先需要設定資料庫中的欄位型別為blob。
複製程式碼

儲存檔案到資料庫:

Java 之 JDBC

將資料庫中的檔案取出來:

Java 之 JDBC

11、獲取自動生成的主鍵id

需求分析:

我們可能回遇到這樣的情景,我們首先註冊資訊,填入使用者明和密碼後,註冊成功,此時的資料庫中的id是自動新增進去的,接下來回讓自己去完善自己的資訊,這就要需要我們剛才建立的id了,那麼如何返回id給我們下次使用呢?

兩種方式獲取:

1:

Java 之 JDBC

2:

Java 之 JDBC

相關文章