BD1 - Java 3-4 JDBC - 配置文件 连接池

此心不动,随机而动

Java第12天上午

上午主要复习了JDBC

详细内容可参见:
7.21 JDBC 学习总结

以下总结补充:

JDBC用途

使用JDBC来操作数据库用到的类:


遍历数据库的大致步骤:


连接数据库的大致步骤

不遍历的话 则:


步骤

PreparedStatement优势绝不仅仅是更灵活的参数化查询
请参见:PreparedStatement VS Statement

上午完成的经典代码:(遍历数据)

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
            
            // 第三步 创建数据库的连接
            conn = DriverManager.getConnection(url, user, password);
            // 第四步 创建一个statement对象
            stmt = conn.createStatement();
            // 第五步 执行sql语句
            rs = stmt.executeQuery("select * from student");
            // 第六步 循环遍历处理结果
            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();
            }
        }
    }
}

上午完成的经典代码:(插入数据)

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
            
            // 第三步 创建数据库的连接
            conn = DriverManager.getConnection(url, user, password);
            // 第四步 创建一个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配置文件

在上午代码基础上 我们考虑进一步优化代码结构

给定这样的数据库:


数据库

先来看之前创建连接的结构:

// 第一步 先加载注册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";
// 第三步 创建数据库的连接
conn = DriverManager.getConnection(url, user, password);

可见 我们每创建一个连接 就需要重现以上代码

并且在开发时 有些参数是经常改变的
比如操作数据库时 我们可能连接本地的数据库 那么IP 、数据库名称、表名称和数据库主机等信息是我们本地的。

要使得操作数据的模块具有通用性,那么以上信息就不能写死在程序里。通常我们的做法是用配置文件来解决

关于更多java配置文件说明 请看:.properties Java 配置文件

所以先来新建一个properties (Java配置文件):
先右击src文件夹 新建一个File

配置文件 - 新建一个File

选File 再点击Next:


File

File名称设置为:db.properties


db.properties

db.properties 文件新建成功:


新建成功

可以点击右边的Add在弹窗中输入key - value 数据:


输入key - value 数据

比如 我们输入 user - root 点击 Finish:


输入-1
输入-2

点击左下角的Source:


输入-3

即我们也可以在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
新建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 中间的 静态代码块 完成 :

  • 获取配置文件的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中普通代码块,构造代码块,静态代码块区别及代码示例

3 createConnection 方法:(创建数据库的连接)

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

其中,我们以后可这样创建连接:

conn = JdbcUtil.createConnection();

(即利用JdbcUtil中的方法创建连接)

其中,我们也可以这样关闭资源:

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文件 可见成功打印:


运行结果

连接池

我们来考虑下通过配置文件创建连接的性能,在JdbcUtil类的createConnection()方法中利用系统的currentTimeMillis()函数获取前后用时:


获取前后用时

运行可见用时476ms:
(不同电脑性能有差异,您的时间可能不同)


QQ图片20170807211826.png

476ms已经不算少了 试想如果创建多个Connection 那么用时会很长,足以严重影响性能。

所以,我们提出连接池概念:

更多连接池概念请见:
1 - Java连接池详解
2 - 几个主流的Java连接池整理

一下不理解很正常,先有个概念:池技术是为了优化服务器应用程序的性能、提高程序执行效率和降低系统资源开销。

考虑下连接池的设计:
连接池(connection pool)

  • 使用集合 将Connection对象放入List中,反复使用
  • 连接池的初始化
    • 事先放入多个连接对象
  • 从连接池中获取连接对象
    • 如果池中无可用连接,则创建一个新的
    • 如果池中有可用连接,则将池中最后一个返回,同时,将该连接从池中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;
    // 最大连接数
    private static final int POOL_MAX_SIZE = 100;
    // 最小连接数
    private static final int POOL_MIN_SIZE = 10;
    
    public DBConnPool(){
        initPool();
    }
    
    // 初始化连接池 让池中的连接数达到最小值
    public void initPool(){
        if(pool == null){
            pool = new ArrayList<Connection>();
        }
        while(pool.size() < POOL_MIN_SIZE){
            pool.add(JdbcUtil.createConnection());
            System.out.println("初始化池,池中连接数:"+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);
        }
    }
}

注意:


初始化连接池

在此初始化方法中 循环add 以让池中的连接数达到最小值

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并不是真的关掉 而是放回池:


close 放回池
拓展阅读:

Java中Synchronized的用法


世界上所有的追求都是因为热爱
一枚爱编码 爱生活 爱分享的IT信徒
— hongXkeX

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,548评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,069评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,985评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,305评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,324评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,030评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,639评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,552评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,081评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,194评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,327评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,004评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,688评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,188评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,307评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,667评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,337评论 2 358

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,681评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,654评论 18 399
  • 本文包括传统JDBC的缺点连接池原理自定义连接池开源数据库连接池DBCP连接池C3P0连接池Tomcat内置连接池...
    廖少少阅读 16,751评论 0 37
  • “《情书》是由岩井俊二自编自导的的日本纯爱电影,由中山美穗、丰川悦司、柏原崇主演,于1995年3月25日首映。电影...
    ConnecToMe阅读 293评论 4 4
  • tribbie阅读 305评论 4 7