05-数据库_JDBC

目录

一,JDBC简介

1,简介

2,发展历史

二,JDBC标准流程

1,使用步骤*

2,配置lib

3,代码实现

三,增删改查

1,JDBC中常用的类型和方法

2,代码演示

四,dao概述与工厂设计模式

1,工厂方法设计模式 ( 静态工厂方法模式 )

2,DAO

五,DAO工厂

1,代码示例

六,预编译处理

1,SQL注入问题 *

2,解决SQL注入问题

2.1 PreparedStatement 预编译的SQL执行环境

2.2 代码展示

2.3 PreparedStatement与Statement谁的性能高?

3,预编译与否的性能对比

七,批处理

1,使用方法

1.1 Statement对象使用流程: 

1.2 PreparedStatement对象使用流程: 

2,代码

八,数据库连接池

1,连接池(DataSource)的使用 *

2,Properties 作为配置文件

2.1 文件中内容的格式: 

2.2 如何将文件 转换为 集合: 

3,常用连接池使用步骤

3.1 DBCP连接池的使用步骤 *

3.2 德鲁伊连接池的使用步骤 *

3.3 代码演示——DBCP连接池

3.3 代码演示——德鲁伊连接池(效果比其他连接池好)

4,连接池工具类

4.1 Druid


一,JDBC简介

1,简介

Java DataBase Connectivity Java数据库连接 

我们学习的技术是JDBC 不是 MYSQLJDBC 也不是 ORACLE JDBC 

JDBC是一套标准,是Java与各大数据库厂商共同定制的一套接口. 这套接口由各大数据库厂商进行了实现.

2,发展历史

自从Java语言于1995年5月正式公布以来,Java风靡全球。 

出现大量的用java语言编写的程序,其中也包括数据库应用程序。由于没有一个Java语言的数据库操作API,编程人员不得不在Java程序中加入C语言的ODBC函数调用。这就使很多Java的优秀特性无法充分 发挥,比如平台无关性、面向对象特性等。

随着越来越多的编程人员对Java语言的日益喜爱,越来越多的公司在Java程序开发上投入的精力日益增加,对java语言接口的访问数据库的API的要求越来越强烈。也由于ODBC的有其不足之处,比如它并不容易使用,没有面向对象的特性等等,SUN公司决定开发一Java语言为接口的数据库应用程序开发接口。 

在JDK1.x版本中,JDBC只是一个可选部件,到了JDK1.1公布时,SQL类包(也就是JDBCAPI)就成为 Java语言的标准部件。

 

二,JDBC标准流程

1,使用步骤*

1. 引入jar文件. 

2. 加载数据库驱动 (JavaSE项目中可以省略 , JavaWeb项目必须编写此步骤) Class.forName("com.mysql.jdbc.Driver"); 

3. 通过驱动管理器, 获取JDBC连接对象.

  • Connection conn = DriverManager.getConnection("数据库连接地址","帐号","密码");
  • // 数据库连接地址格式: 主协议:子协议://ip地址:端口号/数据库名称
  • // mysql的连接地址: jdbc:mysql://localhost:3306/java35
  • // oracle的连接地址: jdbc:oracle:thin:@localhost:1521:ORCL 

4. 通过连接对象, 创建SQL执行对象 (SQL执行环境) Statement state = conn.createStatement(); 

5. 通过SQL执行对象 ,执行SQL语句. state.execute(String sql语句); 

6. 释放资源

  • state.close(); 
  • conn.close();

2,配置lib

1,将需要的jar文件复制到lib中

2,打开file/Project Structure,其中Modules、Libraries原样如下:

3,配置Libraries

(记得apply进行保存)

4,配置Modules

(记得apply进行保存)

3,代码实现

1,实现基本的查询流程

package com.java.demo;

import java.sql.*;

public class Demo1 {
    public static void createTable() throws ClassNotFoundException, SQLException {
        //1.    加载数据库驱动 (可以省略的.  在JavaEE的web项目中,jar包不可以省略.)
        //      mysql6以下驱动:com.mysql.jdbc.Driver
        //      mysql6和6以上驱动:com.mysql.cj.jdbc.Driver
        Class.forName("com.mysql.jdbc.Driver");// 在mysql-connector-java-5.1.37-bin.jar中
        //2.    通过驱动管理器, 获取JDBC的连接对象
        //      连接地址格式:
        //           主协议:子协议://ip地址:端口号/数据库名称
        //           mysql:     jdbc:mysql://localhost:3306/test
        //           oracle:    jdbc:oracle:thin:@ip地址:1521/ORCL
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123");
        //3.    通过连接对象,创建SQL执行对象 (SQL执行环境)
        Statement state = conn.createStatement();
        //4.    通过SQL执行对象 执行SQL
        state.execute("create table person(id int,nickname varchar(32))");// 返回值不是成功或失败,true:查询语句,false:其他语句
        //5.    释放连接
        state.close();
        conn.close();
    }
}

2,添加测试方法

(需要提前引入jar包)

Alt+insert(右击也可找到)调出generate界面,选择Test选项

3,创建添加数据的代码

demo.java

package com.java.demo;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class Demo {
    public static void createTable() throws ClassNotFoundException, SQLException {
        //1.    加载数据库驱动 (可以省略的.  在JavaEE的web项目中,jar包不可以省略.)
        //      mysql6以下驱动:com.mysql.jdbc.Driver
        //      mysql6和6以上驱动:com.mysql.cj.jdbc.Driver
        Class.forName("com.mysql.jdbc.Driver");// 在mysql-connector-java-5.1.37-bin.jar中
        //2.    通过驱动管理器, 获取JDBC的连接对象
        //      连接地址格式:
        //           主协议:子协议://ip地址:端口号/数据库名称
        //           mysql:     jdbc:mysql://localhost:3306/test
        //           oracle:    jdbc:oracle:thin:@ip地址:1521/ORCL
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "2017217905");
        //3.    通过连接对象,创建SQL执行对象 (SQL执行环境)
        Statement state = conn.createStatement();
        //4.    通过SQL执行对象 执行SQL
        state.execute("create table person(id int,nickname varchar(32))");// 返回值不是成功或失败,true:查询语句,false:其他语句
        //5.    释放连接
        state.close();
        conn.close();
    }

    public static void insertData() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        state.execute("insert into person values(1,'张三')");
        state.close();
        conn.close();
    }
}

 

三,增删改查

1,JDBC中常用的类型和方法

1. DriverManager : 驱动管理器 

常用方法:

- 获取数据库连接: 

static Connection getConnection(String 数据库地址,String 账号 ,String 密 码)

2. Connection : 数据库连接对象 

常用方法:

- 创建SQL执行对象: 

Statement createStatement();

3. Statement : SQL执行对象 

常用方法: 

- 执行SQL语句(查询语句返回true, 其它语句返回false) 

boolean execute(String sql); 

- 执行DML语句(INSERT UPDATE DELETE) 和 DDL语句(create alter drop) (返回int值, 表示语句对数据库表格的影响行数 !) (通常我们认为 返回值>0 表示执行成功.) 

int executeUpdate(String sql); 

- 执行DQL语句 (select) 

ResultSet executeQuery(String sql);

4. ResultSet : 结果集对象 (指的是一个select语句的查询结果) 

常用方法: 

1. 控制游标移动的常用方法: 

// 作用: 控制游标向下一行移动. 
// 返回值: 移动成功返回true , 下一行不存在移动失败, 返回 false 
boolean next()
// 作用: 控制游标向上一行移动. 
// 返回值: 移动成功返回true , 上一行不存在移动失败, 返回 false 
boolean privious()
// 作用: 控制游标向指定行移动 
// 返回值: 移动成功返回true , 行不存在移动失败, 返回false 
boolean absolute(int 行号) //了解 
// 作用: 控制游标移动到第一行 
// 返回值: 移动成功返回true, 没有第一行数据返回false 
boolean beforeFirst() // 了解 
// 作用: 控制游标移动到最后一行 
// 返回值: 移动成功返回true, 没有最后一行数据返回false
boolean afterLast() // 了解 

2. 获取游标指向行的字段值的常用方法: 

// 根据字段名, 得到此字段的值 
XXX getXXX(String 列名) ***
// 根据字段的索引, 得到字段的值 , 索引从1开始
XXX getXXX(int 字段的索引) * 

2,代码演示

package com.java.demo;

import java.sql.*;

public class Demo1 {
    public static void createTable() throws ClassNotFoundException, SQLException {
        //1.    加载数据库驱动 (可以省略的.  在JavaEE的web项目中,jar包不可以省略.)
        //      mysql6以下驱动:com.mysql.jdbc.Driver
        //      mysql6和6以上驱动:com.mysql.cj.jdbc.Driver
        Class.forName("com.mysql.jdbc.Driver");// 在mysql-connector-java-5.1.37-bin.jar中
        //2.    通过驱动管理器, 获取JDBC的连接对象
        //      连接地址格式:
        //           主协议:子协议://ip地址:端口号/数据库名称
        //           mysql:     jdbc:mysql://localhost:3306/test
        //           oracle:    jdbc:oracle:thin:@ip地址:1521/ORCL
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123");
        //3.    通过连接对象,创建SQL执行对象 (SQL执行环境)
        Statement state = conn.createStatement();
        //4.    通过SQL执行对象 执行SQL
        state.execute("create table person(id int,nickname varchar(32))");// 返回值不是成功或失败,true:查询语句,false:其他语句
        //5.    释放连接
        state.close();
        conn.close();
    }

    public static void insertData() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        state.execute("insert into person values(1,'张三')");
        state.close();
        conn.close();
    }

    public static void insertPerson() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        int flag = state.executeUpdate("insert into person values(1,'张三'),(2,'李四'),(3,'王二麻子')");
        state.close();
        conn.close();
        System.out.println("返回:"+flag);
    }

    public static void deletePerson() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        int flag = state.executeUpdate("delete from person where id=1");
        state.close();
        conn.close();
        System.out.println("返回:"+flag);
    }

    public static void updatePerson() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        int flag = state.executeUpdate("update person set nickname='haha' where id=2");
        state.close();
        conn.close();
        System.out.println("返回:"+flag);
    }

    public static void selectPerson() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        ResultSet rs = state.executeQuery("select * from person");
        while(rs.next()){
            int id = rs.getInt("id");
            String nickname = rs.getString("nickname");
            System.out.println("id="+id+"\tnickname="+nickname);
        }
        rs.close();
        state.close();
        conn.close();
    }
}

 

四,dao概述与工厂设计模式

1,工厂方法设计模式 ( 静态工厂方法模式 )

工厂方法模式一种创建对象的模式. 

工厂方法模式基于"输入",应用在超类和多个子类之间的情况,这种模式将创建对象的责任转移到工厂类; 

工厂设计模式的优点: 

  • 1. 面向接口编程,体现了面向对象的思想 
  • 2. 降低了耦合, 将创建对象的工作转移到了工厂类(连接不同版本数据库时,SQL语句不一致导致的代码重构)

2,DAO

DAO(Data Access Object)是一个数据访问接口,数据访问:顾名思义就是与数据库打交道。夹在业务 逻辑与数据库资源中间。 

为了建立一个健壮的Java应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的 语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中, 当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个 特定的数据存储。

引入工厂方法后

DAO模式是标准的JavaEE设计模式之一.

开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分 开.一个典型的DAO实现有下列几个组件: 

  • 1. 一个DAO工厂类; 
  • 2. 一个DAO接口; 
  • 3. 至少一个实现DAO接口的具体类; 
  • 4. 数据传递对象(有些时候叫做Bean对象).

 

五,DAO工厂

1,代码示例

一个典型的DAO实现有下列几个组件: 

  • 1. 一个DAO工厂类; 
  • 2. 一个DAO接口; 
  • 3. 至少一个实现DAO接口的具体类; 
  • 4. 数据传递对象(有些时候叫做Bean对象).

依次设计代码如下:

1,一个DAO工厂类:UserDaoFactory

package com.java.demo3;

public class UserDaoFactory {
    public static BaseUserDao get(){
        return new MySqlUserDao();
    }
}

2,一个DAO接口:BaseUserDao

package com.java.demo3;

import java.util.List;

public interface BaseUserDao {
    /**
     *  用于向数据库xzk_user表格中插入一行数据
     * @param username  是要插入的账号
     * @param password  是要插入的密码
     * @return  结果, 增加成功返回true
     */
    boolean insert(String username,String password);

    /**
     *  用于从数据库xzk_user表格中查询一行数据
     * @param username  是要查询的条件1:账号
     * @param password  是要查询的条件2:密码
     * @return  结果, 查询成功返回true
     */
    boolean findByPassword(String username,String password);

    /**
     *  用于从数据库xzk_user表格中查询一行数据
     * @param username  是要查询的条件1:账号
     * @param password  是要查询的条件2:密码
     * @return  结果, 查询成功返回true
     */
    boolean findByPassword2(String username,String password);

    /**
     * 查询所有用户信息
     * @return 用户列表
     */
    List<User> findAll();
}

3,至少一个实现DAO接口的具体类:MySqlUserDao

package com.java.demo3;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class MySqlUserDao implements BaseUserDao{
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");// 编写一次即可,所以写在静态代码块中
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    @Override
    public boolean insert(String username, String password) {
        Connection conn = null;
        Statement state = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
            state = conn.createStatement();
            //insert into xzk_user values('username','password')    :   字符串的定义格式  字符串的表现格式
            int row = state.executeUpdate("insert into xzk_user values('" + username + "','" + password + "')");
            return row>0;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                state.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }


    @Override
    public boolean findByPassword(String username, String password) {
        Connection conn = null;
        Statement state = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
            state = conn.createStatement();
            //执行
            rs = state.executeQuery("select * from xzk_user where username='"+username+"' and password='"+password+"'");
            return rs.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                rs.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
            try {
                state.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
            try {
                conn.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
        }
        return false;
    }

    @Override
    public List<User> findAll() {
        List<User> data = new ArrayList<>();
        Connection conn = null;
        Statement state = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
            state = conn.createStatement();
            rs = state.executeQuery("select * from xzk_user");
            while(rs.next()){
                String username = rs.getString("username");
                String password = rs.getString("password");
                data.add(new User(username,password));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                state.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return data;
    }
}

4,数据传递对象(有些时候叫做Bean对象):User

package com.java.demo3;

import java.util.Objects;

public class User {
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(username, user.username) &&
                Objects.equals(password, user.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(username, password);
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User() {
    }
}

5,测试主函数:Main

package com.java.demo3;

import java.util.List;
import java.util.Scanner;

public class Main {
    static Scanner input = new Scanner(System.in);
    static BaseUserDao dao = UserDaoFactory.get();
    public static void main(String[] args) {
        System.out.println("欢迎来到某某软件");
        System.out.println("请选择:");
        System.out.println("1.注册\t\t2.登陆\t\t3.查看所有用户");

        String menu = input.nextLine();
        switch (menu){
            case "1":
                reg();
                break;
            case "2":
                login();
                break;
            case "3":
                showUsers();
                break;
        }
    }

    private static void showUsers() {
        List<User> data = dao.findAll();
        System.out.println("所有用户信息如下:");
        System.out.println(data);
    }

    private static void login() {
        System.out.println("请输入账号:");
        String username = input.nextLine();
        System.out.println("请输入密码:");
        String password = input.nextLine();
        boolean flag = dao.findByPassword(username, password);
        System.out.println(flag?"恭喜你,登陆成功":"很遗憾,登陆失败");
    }

    private static void reg() {
        System.out.println("请输入要注册的账号:");
        String username = input.nextLine();
        System.out.println("请输入要注册的密码:");
        String password = input.nextLine();
        boolean flag = dao.insert(username, password);
        System.out.println(flag?"恭喜你,注册成功":"很遗憾,注册失败");
    }
}

 

六,预编译处理

1,SQL注入问题 *

进行用户登录时, 输入不存在的帐号 和 如下的密码:

1' or '1'='1 

结果显示登录成功. 因为用户输入的密码, 与我们的查询语句拼接后, 使得我们的查询语句产生了歧义: 

原查询语句: 

select * from xzk_user where username='' and password='密码' 

拼接后:(可以看出and后面的条件,不论密码是多少,最终都会返回true)

select * from xzk_user where username='hahahaheiheihei' and password='1' or '1'='1'

2,解决SQL注入问题

我们可以将SQL语句与参数分离,将参数作为SQL的特殊部分进行预处理

2.1 PreparedStatement 预编译的SQL执行环境

内部实现原理: 

1. 将未拼接参数的SQL语句, 作为SQL指令, 先传递给数据库 进行编译. 

2. 再将参数传递给数据库, 此时传递的参数不会再作为指令执行, 只会被当作文本存在. 

操作流程与Statement基本一致: 

1. 如何得到一个PreparedStatement 对象?

PreparedStatement state = conn.prepareStatement("预编译的SQL语句"); 

2. 预编译的SQL语句如何编写 需要填充参数的位置, 使用?

代替即可! 例如:

select id from xzk_user where username=? and password=? 

3. 参数如何填充

// setXXX中XXX指的是数据类型
// 参数1: index : SQL语句中?的索引值 , 从1开始 
// 参数2: value : 填充的参数值. 
state.setXXX(int index,XXX value); 

4. 如何执行填充完毕参数的SQL

boolean execute();
int executeUpdate();
ResultSet executeQuery();

2.2 代码展示

重写MySqlUserDao中的findByPassword方法;

对比部分以注释的形式呈现

    @Override
    public boolean findByPassword(String username, String password) {
        Connection conn = null;
        
        // 之前:Statement state = null;
        PreparedStatement state = null;
        
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
            
            // 之前:state = conn.createStatement();
            // 参数: 预编译的SQL语句, 参数部分使用?替代.
            state = conn.prepareStatement("select * from xzk_user where username=? and password=?");
            
            // 向预编译的执行环境中, 加入参数的内容
            state.setString(1,username);
            state.setString(2,password);
            
            // 之前:rs = state.executeQuery("select * from xzk_user where username='"+username+"' and password='"+password+"'");
            // 执行
            rs = state.executeQuery();
            
            return rs.next();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            try {
                rs.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
            try {
                state.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
            try {
                conn.close();
            } catch (Exception throwables) {
                throwables.printStackTrace();
            }
        }
        return false;
    }

使用Statement

使用PreparedStatement

2.3 PreparedStatement与Statement谁的性能高?

看是什么数据库 

  • 在mysql中, preparedStatement原理是拼接SQL, 所以Statement性能高. 
  • 在Oracle中, preparedStatement原理是对SQL指令进行预处理, 再传递的参数不具备特殊含义.有更好 的SQL缓存策略,PreparedStatement高.

由于PreparedStatement可以防止SQL注入问题,所以推荐使用此方法

 

3,预编译与否的性能对比

 

七,批处理

将多条语句, 放到一起批量处理 . 

批处理的原理: 将多条SQL语句, 转换为一个SQL指令. 显著的提高大量SQL语句执行时的数据库性能. 

1,使用方法

1.1 Statement对象使用流程: 

1. 得到Statement对象

Statement state = conn.createStatement(); 

2. 将一条SQL语句, 加入到批处理中.

state.addBatch(String sql);

3. 执行批处理

state.executeBatch(); 

4. 清空批处理

state.clearBatch(); 

1.2 PreparedStatement对象使用流程: 

1. 得到PreparedStatement对象

PreparedStatement state = conn.prepareStatement("预编译的SQL"); 

2. 填充预编译的参数

state.setXXX(1,填充参数); 

3. 将一条填充完毕参数的SQL, 加入到批处理中.

state.addBatch(); 

4. 执行批处理

state.executeBatch(); 

5. 清空批处理

state.clearBatch();

2,代码

package com.java.demo5;

import java.sql.*;

public class Main {
    //statment
    public static void insert1_1() throws SQLException {

        for (int i=0;i<1000;i++) {
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
            Statement state = conn.createStatement();
            state.executeUpdate("insert into person values('admin','123"+i+"')");
            state.close();
            conn.close();
        }

    }
    //statement 批处理
    public static void insert1_2() throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        Statement state = conn.createStatement();
        for (int i=0;i<1000;i++) {
            //向批处理中 加入一条SQL
            state.addBatch("insert into person values('admin','123"+i+"')");
        }
        //执行批处理
        state.executeBatch();
        //清空批处理指令
        state.clearBatch();
        state.close();
        conn.close();
    }

    //PreparedStatement
    public static void insert2_1() throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        PreparedStatement state = conn.prepareStatement("insert into person values(?,?)");
        for (int i=0;i<10000;i++) {
            state.setString(1,"admin");
            state.setString(2,"123"+i);
            state.executeUpdate();
        }
        state.close();
        conn.close();
    }
    //PreparedStatement批处理
    public static void insert2_2() throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
        PreparedStatement state = conn.prepareStatement("insert into person values(?,?)");
        for (int i=0;i<10000;i++) {
            state.setString(1,"admin");
            state.setString(2,"123"+i);
            state.addBatch();
        }
        //执行批处理
        state.executeBatch();
        //清空批处理指令
        state.clearBatch();
        state.close();
        conn.close();
    }

}

 

八,数据库连接池

1,连接池(DataSource)的使用 *

连接池用于缓存连接! 当我们需要使用连接时, 可以不用再创建连接 ! 可以直接从连接池中获取连接. 

  • 当连接池中存在空闲连接时, 会将空闲连接给到程序使用. 
  • 当连接池中存在空闲连接时, 且连接池未满时 , 则创建连接提供给程序使用 ,并在程序使用完毕后, 缓存连接. 
  • 当连接池中存在空闲连接时, 且连接池已满时 , 则排队等候空闲连接的出现. 

注意:使用连接池中的连接对象操作数据库时, 操作完毕依然需要释放连接(调用close()). 

连接池中的连接在设计时, 使用了动态代理设计模式+装饰者设计模式 . 我们调用它的close方法, 代理没有关闭这个连接, 而是将连接重新放入了池中.

2,Properties 作为配置文件

Properties类 是Java中的Map集合的实现类. 

  • .properties文件 用于通过文件描述一组键值对! 
  • .properties文件 ,可以快速的转换为Properties类的对象. 

2.1 文件中内容的格式: 

  • 文件内容都是字符串 , 
  • 键与值之间通过等号连接 , 
  • 多个键值对之间换行分割. 

例如:

url=xxx 
user=xxx 
password=xxx 

2.2 如何将文件 转换为 集合: 

1. 创建Properties对象

Properties ppt = new Properties(); 

2. 创建一个字节输入流 , 指向.properties文件

InputStream is = new FileInputStream("文件地址"); 

3. 将字节输入流, 传递给properties对象, 进行加载.

ppt.load(is);

3,常用连接池使用步骤

3.1 DBCP连接池的使用步骤 *

1. 引入相关的jar文件

- dbcp.jar 
- poll.jar 

2. 将配置文件引入 

3. 将配置文件, 转换为Properties对象 

Properties ppt = new Properties(); 
ppt.load(配置文件的输入流); 

4. 通过连接池的工厂类(BasicDataSourceFactory)的创建连接池的方法(createDataSource()) 

DataSource ds = BasicDataSourceFactory.createDataSource(ppt); 

5. 从连接池中 获取连接对象 

Connection conn = ds.getConnection();

 

3.2 德鲁伊连接池的使用步骤 *

1. 引入相关的jar文件

- druid-1.0.9.jar 

2. 将配置文件引入 

3. 将配置文件, 转换为Properties对象 

Properties ppt = new Properties(); 
ppt.load(配置文件的输入流); 

4. 通过连接池的工厂类(DruidDataSourceFactory)的创建连接池的方法(createDataSource()) 

DataSource ds = DruidDataSourceFactory.createDataSource(ppt); 

5. 从连接池中 获取连接对象 

Connection conn = ds.getConnection();

3.3 代码演示——DBCP连接池

1,编写配置文件

dbcp.properties(因为编码问题出现乱码,只要关键地方没问题,其他影响不大)

#���ݿ����ӵ�ַ
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
#���ݿ��������ȫ��
driverClassName=com.mysql.jdbc.Driver
#���ݿ��ʺ�
username=root
#���ݿ�����
password=123
#��ʼ�����ӳ�ʱ,��������������
initialSize=5
#���ӳص������������
maxActive=20
#����ʱ�������������������
maxIdle=5
#����ʱ����������С��������
minIdle=5
#�ŶӵȺ�ij�ʱʱ��(����)
maxWait=3000

2,编写demo

package com.java.demo6;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class Demo {
//    DBCP
    public static void main(String[] args) throws Exception {
        //1.    引入jar文件
        //2.    将配置文件 properties文件 放到src文件夹下
        //3.    将properties文件 转换为Properties对象
        Properties ppt = new Properties();
        InputStream is = Demo.class.getClassLoader().getResourceAsStream("dbcp.properties");
        ppt.load(is);
        //4.    通过连接池的工厂类, 创建连接池
        DataSource dataSource = BasicDataSourceFactory.createDataSource(ppt);
        //5.    从池中获取一个连接
        Connection conn = dataSource.getConnection();
        Statement state = conn.createStatement();
        state.execute("insert into person values('zhangsan','lisi')");
        state.close();
        conn.close();
    }
}

3.3 代码演示——德鲁伊连接池(效果比其他连接池好)

1,编写配置文件

url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
username=root
password=123
#��������������url�Զ�ʶ����һ�����ɲ��䣬���������druid�����url�Զ�ʶ����Ӧ��driverClassName
driverClassName=com.mysql.jdbc.Driver
#��ʼ��ʱ�����������ӵĸ�������ʼ����������ʾ����init���������ߵ�һ�� getConnectionʱ
initialSize=5
#������ӳ�����
maxActive=10
#��С���ӳ�����
minIdle=5
#��ȡ����ʱ���ȴ�ʱ�䣬��λ���롣
maxWait=3000

2,编写demo

4,连接池工具类

之前编写代码时,下面一行代码反复出现,为了避免重复的工作,引入了连接池工具类

4.1 Druid

public class DruidUtil{ 
	private static DataSource data = null; 
	static {
		InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"); 
		Properties ppt = new Properties(); 
		try {
			ppt.load(is); 
			data = DruidDataSourceFactory.createDataSource(ppt); 
		} catch (Exception e) { 
			e.printStackTrace();
		} 
	}
	/**
	* 用于从DBCP连接池中 获取一个连接 
	* @return DBCP连接池中的一个连接对象. 
	*/ 
	public static Connection getConnection() { 
		try {
			return data.getConnection(); 
		} catch (SQLException e) { 
			e.printStackTrace(); 
			return null; 
		} 
	}
	/**
	* 用于释放连接 , 执行环境 , 结果集 等资源 
	* @param conn 要释放的连接资源 
	* @param state 要释放的执行环境资源 
	* @param result 要释放的结果集资源 
	*/ 
	public static void close(Connection conn,Statement state,ResultSet result) { 
		if(result != null) { 
			try {
				result.close(); 
			} catch (SQLException e) { 
				// TODO Auto-generated catch block 
				e.printStackTrace(); 
			} 
		}
		if(state != null) { 
			try {
				state.close(); 
			} catch (SQLException e) { 
				// TODO Auto-generated catch block 
				e.printStackTrace(); 
			} 
		}
		if(conn != null) { 
			try {
				conn.close(); 
			} catch (SQLException e) { 
				// TODO Auto-generated catch block 
				e.printStackTrace(); 
			} 
		} 
	} 
}

Demo

package com.java.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class Demo {
    public static void main(String[] args) {
        try {
            Connection conn = DruidUtil.getConnection();
            Statement state = conn.createStatement();
            state.execute("insert into person values('jinpingguo','123')");
            state.close();
            conn.close();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

章节汇总在这里(づ ̄3 ̄)づ╭❤~@&再见萤火虫&【05-数据库】


对学习Java感兴趣的同学欢迎加入QQ学习交流群:1126298731

有问题欢迎提问,大家一起在学习Java的路上打怪升级!(o゜▽゜)o☆[BINGO!]

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值