此心不動税稼,隨機而動
Java第12天上午
上午主要復習了JDBC
詳細內容可參見:
7.21 JDBC 學習總結
以下總結補充:
使用JDBC來操作數(shù)據(jù)庫用到的類:
遍歷數(shù)據(jù)庫的大致步驟:
不遍歷的話 則:
PreparedStatement優(yōu)勢絕不僅僅是更靈活的參數(shù)化查詢
請參見:PreparedStatement VS Statement
上午完成的經(jīng)典代碼:(遍歷數(shù)據(jù))
import java.sql.*;
public class TestJDBC {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
String Driver = "com.mysql.jdbc.Driver";
// 對應 第二步
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
try{
// 第一步 先加載注冊JDBC的驅動類
Class.forName(Driver);
// 第二步 提供JDBC連接的url
// 第三步 創(chuàng)建數(shù)據(jù)庫的連接
conn = DriverManager.getConnection(url, user, password);
// 第四步 創(chuàng)建一個statement對象
stmt = conn.createStatement();
// 第五步 執(zhí)行sql語句
rs = stmt.executeQuery("select * from student");
// 第六步 循環(huán)遍歷處理結果
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getString("birth").subSequence(0, 4));
}
} catch(ClassNotFoundException s){
s.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} finally {
// 第七步 關閉JDBC對象
try {
if(rs != null) {
rs.close();
}
if(stmt != null)(
stmt.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
上午完成的經(jīng)典代碼:(插入數(shù)據(jù))
import java.sql.*;
public class TestDML {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
String Driver = "com.mysql.jdbc.Driver";
// 對應 下面第二步
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
try{
// 第一步 先加載注冊JDBC的驅動類
Class.forName(Driver);
// 第二步 提供JDBC連接的url
// 第三步 創(chuàng)建數(shù)據(jù)庫的連接
conn = DriverManager.getConnection(url, user, password);
// 第四步 創(chuàng)建一個statement對象
//pstmt = conn.prepareStatement("insert into student values(7,'你好','男',17)");
pstmt = conn.prepareStatement("insert into student values(?,?,?,?,?)");
pstmt.setInt(1, 0);
pstmt.setString(2, "王33");
pstmt.setString(3, "男");
pstmt.setInt(4, 25);
pstmt.setString(5, "2017");
pstmt.executeUpdate();
} catch(ClassNotFoundException s){
s.printStackTrace();
} catch (SQLException e){
e.printStackTrace();
} finally {
// 第七步 關閉JDBC對象
try {
if(pstmt != null) {
pstmt.close();
}
if(conn != null) {
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
下午主要學習了配置文件和連接池
Java配置文件
在上午代碼基礎上 我們考慮進一步優(yōu)化代碼結構
給定這樣的數(shù)據(jù)庫:
先來看之前創(chuàng)建連接的結構:
// 第一步 先加載注冊JDBC的驅動類
String Driver = "com.mysql.jdbc.Driver";
Class.forName(Driver);
// 第二步 提供JDBC連接的url
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
// 第三步 創(chuàng)建數(shù)據(jù)庫的連接
conn = DriverManager.getConnection(url, user, password);
可見 我們每創(chuàng)建一個連接 就需要重現(xiàn)以上代碼
并且在開發(fā)時 有些參數(shù)是經(jīng)常改變的
比如操作數(shù)據(jù)庫時 我們可能連接本地的數(shù)據(jù)庫 那么IP 、數(shù)據(jù)庫名稱棚点、表名稱和數(shù)據(jù)庫主機等信息是我們本地的舔琅。
要使得操作數(shù)據(jù)的模塊具有通用性碗硬,那么以上信息就不能寫死在程序里扛或。通常我們的做法是用配置文件來解決
關于更多java配置文件說明 請看:.properties Java 配置文件
所以先來新建一個properties (Java配置文件):
先右擊src文件夾 新建一個File
選File 再點擊Next:
File名稱設置為:db.properties
db.properties 文件新建成功:
可以點擊右邊的Add在彈窗中輸入key - value 數(shù)據(jù):
比如 我們輸入 user - root 點擊 Finish:
點擊左下角的Source:
即我們也可以在Source中直接輸入:(推薦做法)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/itcast
user=root
password=root
(左邊是key 右邊是value)
輸入結果如圖:
即目前我們成功把:
// 第一步 先注冊加載JDBC的驅動類
String Driver = "com.mysql.jdbc.Driver";
Class.forName(Driver);
// 第二步 提供JDBC連接的url
String url = "jdbc:mysql://localhost:3306/itcast";
String user = "root";
String password = "root";
信息寫到了 配置文件中
下面我們來看如何調用配置信息:
同樣在 src 目錄下 新建一個 JdbcUtil 類:
直接給出 JdbcUtil.java 代碼:
import java.io.IOException;
import java.util.Properties;
import java.sql.*;
public class JdbcUtil {
private static String driver;
private static String url;
private static String uesrname;
private static String password;
static {
try{
Properties p = new Properties();
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
driver = p.getProperty("driver");
url = p.getProperty("url");
uesrname = p.getProperty("user");
password = p.getProperty("password");
Class.forName(driver);
}catch(IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection createConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url, uesrname, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn, Statement stat,ResultSet rs) {
try {
if(rs != null){
rs.close();
}
if(stat != null){
stat.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
代碼說明:
1 4個成員變量分別用來接收 從配置文件讀到的內容
即
private static String driver;
private static String url;
private static String uesrname;
private static String password;
對應配置文件中 左邊的4個key:
2 中間的 靜態(tài)代碼塊 完成 :
-
獲取配置文件的value:
獲取配置文件的value 注冊加載JDBC的驅動類:
Class.forName(driver);
注意
Properties p = new Properties();
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
load方法可以從 .properties屬性文件(這里是db.properties) 對應的文件輸入流中绵咱,加載屬性列表到Properties類對象(這里是p),即通過對上面的 properties 文件進行裝載來獲取該文件中的所有鍵 - 值對熙兔。以供 getProperty ( String key) 來搜索悲伶。
另外Thread.currentThread().getContextClassLoader().getResourceAsStream() 請看:讀取配置文件Properties的一種方案
另外補充:
Java中普通代碼塊,構造代碼塊黔姜,靜態(tài)代碼塊區(qū)別及代碼示例
3 createConnection 方法:(創(chuàng)建數(shù)據(jù)庫的連接)
public static Connection createConnection(){
Connection conn = null;
try {
conn = DriverManager.getConnection(url, uesrname, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
下面測試
在src 下新建一個Test.java文件:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
conn = JdbcUtil.createConnection();
String sql = "select * from student";
try{
stat = conn.createStatement();
rs = stat.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.close(conn, stat, rs);
}
}
}
其中拢切,我們以后可這樣創(chuàng)建連接:
conn = JdbcUtil.createConnection();
(即利用JdbcUtil中的方法創(chuàng)建連接)
其中,我們也可以這樣關閉資源:
JdbcUtil.close(conn, stat, rs);
即利用JdbcUtil中的close()方法關閉資源
JdbcUtil中的close()方法:
public static void close(Connection conn, Statement stat,ResultSet rs) {
try {
if(rs != null){
rs.close();
}
if(stat != null){
stat.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
運行一下Test.java文件 可見成功打痈殉场:
連接池
我們來考慮下通過配置文件創(chuàng)建連接的性能,在JdbcUtil類的createConnection()方法中利用系統(tǒng)的currentTimeMillis()函數(shù)獲取前后用時:
運行可見用時476ms:
(不同電腦性能有差異五慈,您的時間可能不同)
476ms已經(jīng)不算少了 試想如果創(chuàng)建多個Connection 那么用時會很長纳寂,足以嚴重影響性能。
所以泻拦,我們提出連接池概念:
更多連接池概念請見:
1 - Java連接池詳解
2 - 幾個主流的Java連接池整理
一下不理解很正常毙芜,先有個概念:池技術是為了優(yōu)化服務器應用程序的性能、提高程序執(zhí)行效率和降低系統(tǒng)資源開銷争拐。
考慮下連接池的設計:
連接池(connection pool)
- 使用集合 將Connection對象放入List中腋粥,反復使用
- 連接池的初始化
- 事先放入多個連接對象
- 從連接池中獲取連接對象
- 如果池中無可用連接,則創(chuàng)建一個新的
- 如果池中有可用連接架曹,則將池中最后一個返回隘冲,同時,將該連接從池中remove绑雄,表示正在使用
- 關閉連接
- 不是真正的關閉展辞,而是將用完的放回去
新建一個com.pool包 在包下新建 DBConnPool.java:
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import com.hkj.JdbcUtil;
public class DBConnPool {
// 連接對象
private static List<Connection> pool;
// 最大連接數(shù)
private static final int POOL_MAX_SIZE = 100;
// 最小連接數(shù)
private static final int POOL_MIN_SIZE = 10;
public DBConnPool(){
initPool();
}
// 初始化連接池 讓池中的連接數(shù)達到最小值
public void initPool(){
if(pool == null){
pool = new ArrayList<Connection>();
}
while(pool.size() < POOL_MIN_SIZE){
pool.add(JdbcUtil.createConnection());
System.out.println("初始化池,池中連接數(shù):"+pool.size());
}
}
// 從池取最后一個連接
public synchronized Connection getConnection(){
Connection conn = null;
int last_index = 0;
if(pool.size() == 0) {
pool.add(JdbcUtil.createConnection());
}
last_index = pool.size()-1;
conn = pool.get(last_index);
pool.remove(last_index);
return conn;
}
// 將連接池放回池中
public synchronized void close(Connection conn){
if(pool.size() >= POOL_MAX_SIZE){
try {
if(conn != null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
pool.add(conn);
}
}
}
注意:
在此初始化方法中 循環(huán)add 以讓池中的連接數(shù)達到最小值
TestPool.java代碼:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.pool.DBConnPool;
public class TestPool {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
DBConnPool dbpool = new DBConnPool();
conn = dbpool.getConnection();
String sql = "select * from student";
try{
stat = conn.createStatement();
rs = stat.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString("name"));
System.out.println(rs.getInt("age"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
dbpool.close(conn);
}
}
}
主要代碼——新建連接池對象:
DBConnPool dbpool = new DBConnPool();
利用連接池對象的getConnection()獲取一個連接:
conn = dbpool.getConnection();
利用連接池對象的close()將連接池放回池中:
dbpool.close(conn);
一定注意 close并不是真的關掉 而是放回池:
拓展閱讀:
世界上所有的追求都是因為熱愛
一枚愛編碼 愛生活 愛分享的IT信徒
— hongXkeX