一、数据库驱动和JDBC

一个程序是不能直接连接数据库的,需要数据库驱动才行,这个数据库驱动由数据库厂商去提供。

一个程序如何去连接不同厂商生产的不同驱动都要程序员去学习,学习成本很大的!

没有什么是加一层解决不了的!

Sun公司提供JDBC!

程序员只需要去学习JDBC的接口就好了!

二、java连接数据库——第一个JDBC程序

2.1 新建一个maven项目,导入jar包

java连接mysql数据库需要3个jar包

  • java.sql (自带)

  • javax.sql (自带)

  • mysql-connector-java-5.1.47.jar(导入)mysql是5.0版本的就用5.0开头的,是8.0版本的就用8.0开头的


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

2.2 新建数据库


CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;

USE `jdbcStudy`;

CREATE TABLE `users`(
 `id` INT PRIMARY KEY,
 `NAME` VARCHAR(40),
 `PASSWORD` VARCHAR(40),
 `email` VARCHAR(60),
 birthday DATE
);

 INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES('1','zhangsan','123456','zs@sina.com','1980-12-04'),
('2','lisi','123456','lisi@sina.com','1981-12-04'),
('3','wangwu','123456','wangwu@sina.com','1979-12-04')

2.3 java程序连接数据库


import java.sql.*;

public class Demo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //加载驱动,抛出ClassNotFound的异常
        Class.forName("com.mysql.jdbc.Driver");

        //连接数据库 1)url/主机地址 2)用户名 3)密码
            //背过后面的一串参数【?useUnicode=true&characterEncoding=utf8&useSSL=true】
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "123456";
        Connection connection = DriverManager.getConnection(url, username, password); //获取数据库对象

        //获取执行SQL的对象
        Statement statement = connection.createStatement();

        //statement去执行SQL
        String sql = "SELECT * FROM users";
        ResultSet resultSet = statement.executeQuery(sql);
        while (resultSet.next()) {  //游标遍历
            System.out.print("id ="+ resultSet.getObject("id")+"  ");
            System.out.print("姓名 ="+ resultSet.getObject("NAME")+"  ");
            System.out.print("密码 ="+ resultSet.getObject("PASSWORD")+"  ");
            System.out.print("邮箱 ="+ resultSet.getObject("email")+"  ");
            System.out.println("生日 ="+ resultSet.getObject("birthday")+"  ");
        }

        //释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

执行结果
id =1  姓名 =zhangsan  密码 =123456  邮箱 =zs@sina.com  生日 =1980-12-04  
id =2  姓名 =lisi  密码 =123456  邮箱 =lisi@sina.com  生日 =1981-12-04  
id =3  姓名 =wangwu  密码 =123456  邮箱 =wangwu@sina.com  生日 =1979-12-04  

注意01:只有select用executeQuery(),返回查找的结果集;insert和delete以及update一律用executeUpdate(),返回变动的记录数


//返回查询的结果集
ResultSet resultSet = statement.executeQuery(sql);
//返回插入、修改、删除操作改变的记录数
int i = statement.executeUpdate(sql);
//执行任何sql语句,安全性差,一般不用
boolean ifSuccess = statement.execute(sql);

注意02:加载驱动有两种写法。


//写法(一) 不建议
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

//写法(二)
Class.forName("com.mysql.jdbc.Driver");

注意03:结果集ResultSet


//如果不知道属性是什么类型的数据,就用getObject()
resultSet.getObject("id");
//一般是知道属性类型的,直接指定类型
int name = resultSet.getInt("name");
String name1 = resultSet.getString("name");
Date name2 = resultSet.getDate("name");
boolean name3 = resultSet.getBoolean("name");
double name4 = resultSet.getDouble("name");

resultSet.next(); //游标遍历,移动到下一个
resultSet.beforeFirst(); //游标移动到最前面(比如已经遍历一遍了,此时游标指到最后一行,还想再遍历一遍
resultSet.afterLast(); //游标移动到最后面
resultSet.previous(); //游标移动到前一行
resultSet.absolute(row); //游标移动到指定行

2.4 把上面的代码封装一下

(1)配置文件

在上面的代码中,我们把mysql的登录信息直接写在代码里,这样是不好的,要解耦合到配置文件中。

我们在src文件夹下新建一个db.properties文件,注意等号左右不能有空格

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&userSSL=true
username=root
password=123456

(2)封装工具类

和数据库建立连接、和数据库断开连接的操作我们直接写成工具类。


package com.test.demo02;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class jdbcUtils {
    private static String driver=null;
    private static String url=null;
    private static String username=null;
    private static String password=null;

    //jdbc只需要加载一次,所以我们写在静态代码块里,
    static{
        try {
            //先读取配置文件
            //InputStream inputStream = jdbcUtils.class.getClassLoader().getResourceAsStream("E:\\Java Project\\connectMysql\\src\\db.properties");
            FileInputStream inputStream = new FileInputStream("E:\\Java Project\\connectMysql\\src\\db.properties");
            if(inputStream == null){
                System.out.println("null");
            }
            Properties properties = new Properties();
            properties.load(inputStream);
            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");
            System.out.println(driver+ " "+url+" "+username+" "+password);
            //加载jdbc
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    //连接数据库,返回数据库对象
    public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    //断开数据库连接,释放资源
    public static void closeConnection(Connection conn, Statement statement, ResultSet resultSet){
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(resultSet !=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

(3)增删改查.java

查找:


package com.test.demo02;

import java.sql.*;

public class QueryTest {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement =null;
        ResultSet resultSet = null;
        try {
            //建立数据库连接
            connection = jdbcUtils.getConnection();
            //执行sql
            statement = connection.createStatement();
            String sql = "SELECT * FROM users";
            resultSet = statement.executeQuery(sql);
            while(resultSet.next()){
                System.out.print("id ="+ resultSet.getInt("id")+"  ");
                System.out.print("姓名 ="+ resultSet.getString("NAME")+"  ");
                System.out.print("密码 ="+ resultSet.getString("PASSWORD")+"  ");
                System.out.print("邮箱 ="+ resultSet.getString("email")+"  ");
                System.out.println("生日 ="+ resultSet.getObject("birthday")+"  ");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {//关闭资源必须写在finally里
            //断开数据库连接,释放资源
            jdbcUtils.closeConnection(connection,statement,resultSet);
        }



    }
}

更新:


package com.test.demo02;

import java.sql.*;

public class UpdateTest {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement =null;
        ResultSet resultSet = null;
        int num = 0;
        try {
            //建立数据库连接
            connection = jdbcUtils.getConnection();
            //执行sql
            statement = connection.createStatement();
            //String sql = "SELECT * FROM users";
            String sql = "UPDATE users SET `NAME`='1月29' WHERE `id`=1";
            num = statement.executeUpdate(sql);
            if(num>0){
                System.out.println("更新成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {//关闭资源必须写在finally里
            //断开数据库连接,释放资源
            jdbcUtils.closeConnection(connection,statement,resultSet);
        }



    }
}

插入、删除都是同样的代码,不写了

三、Statement对象和PreparedStatement对象

3.1 SQL注入

web安全攻击的一种。举两个易于理解的例子

例(1)攻击者输入用“;”隔开的用户名,“;”后面跟着删除、批量插入等语句,就可以删库或者插入大量记录造成数据库崩溃

例(2)利用OR 1=1把条件变成true

改用户名时,系统要求我们输入旧的用户名,我们输入“' OR 1=1 OR'”,就可以把所有用户的名字都改成“笨蛋们”。同理,密码也可以这样改


String oldName = "' OR 1=1 OR'";
String newName = "笨蛋们";
String sql = "UPDATE users SET `NAME`='"+newName+"' WHERE `NAME`='"+oldName+ "'";

那么如何防止sql注入呢?就是要写一套程序去检查用户输入的SQL语句有没有以上“漏洞”,可以理解为编译器的语法分析,检查完后/过滤后再去执行SQL语句。

3.2 用PreparedStatement对象替代statement对象可以防止sql注入攻击

插入


package com.test.demo02;

import java.sql.*;

public class InsertTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pStatement =null;  //!!!
        ResultSet resultSet = null;
        int num = 0;
        try {
            //建立数据库连接
            connection = jdbcUtils.getConnection();
            //创建prepareStatement对象执行sql语句
            //String sql = "INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)";  //用占位符?替代将来用户传入的参数
            String sql = "insert into users values(?,?,?,?,?)";
            pStatement = connection.prepareStatement(sql); //预编译SQL,先写sql,不执行

            //手动给参数赋值 index指明第几个?(规定index从1开始)
            pStatement.setInt(1,6);
            pStatement.setString(2,"qinjiang");
            pStatement.setString(3,"123456");
            pStatement.setString(4,"885522@qq.com");
                        //注意:给mysql传时间时,要用java.sql.Date类,其构造方法的参数(时间戳)由Java.util.Date类的getTime方法提供
            pStatement.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

            //执行sql
            num = pStatement.executeUpdate(); //记得把参数去掉!!!
            if(num>0){
                System.out.println("插入成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {//关闭资源必须写在finally里
            //断开数据库连接,释放资源
            jdbcUtils.closeConnection(connection,pStatement,resultSet);
        }
    }
}

删除


package com.test.demo02;

import java.sql.*;

public class DeleteTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pStatement =null;  //!!!
        ResultSet resultSet = null;
        int num = 0;
        try {
            //建立数据库连接
            connection = jdbcUtils.getConnection();
            //创建prepareStatement对象执行sql语句
            String sql = "DELETE FROM users WHERE id=?";
            pStatement = connection.prepareStatement(sql); //预编译SQL,先写sql,不执行

            //手动给参数赋值 index指明第几个?(规定index从1开始)
            pStatement.setInt(1,5);
            
            //执行sql
            num = pStatement.executeUpdate(); //记得把参数去掉!!!
            if(num>0){
                System.out.println("删除成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {//关闭资源必须写在finally里
            //断开数据库连接,释放资源
            jdbcUtils.closeConnection(connection,pStatement,resultSet);
        }

    }
}

注意01

  • 下标从1开始

  • 赋值的时候不需要为字符串变量的两边加上’’,直接


ps.setString(1, “liguang”); 

因为PreparedStatement会为占位符?的两边自动加上单引号,这也是PreparedStatement防止SQL注入的本质

  • 占位符只能替换值,不能替换表名、字段名或者其他关键词。同样因为PreparedStatement会为占位符?的两边自动加上单引号,这样会使得SQL语句不可执行,比如使用将表名设置为占位符,数据库执行sql语句时,表名会用单引号引起来。

注意02

如果报出如下错误:


com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?,?,?,?,?)'

原因是:executeUpdate()方法没有去掉参数


num = pStatement.executeUpdate(sql); //这里没有去掉参数

因为PreparedStatement类是statement类的子类,PreparedStatement类executeUpdate()方法是无参方法,如果executeUpdate(sql)这样写,调用的是父类的有参方法。

3.3 PreparedStatement是如何防止sql注入的

其实我们上面已经讲了,PreparedStatement防止SQL注入的本质就是给参数的两边自动加上'',这样输入的一切东西都是字符串了

把上面那段sql注入的代码用preparedStatement修改,就失效了。


//创建prepareStatement对象执行sql语句
String oldName = "'' OR 1=1";
String newName = "笨蛋们";
String sql = "UPDATE users SET `NAME`=? WHERE `NAME`=?";

pStatement = connection.prepareStatement(sql); //预编译SQL,先写sql,不执行

//手动给参数赋值 index指明第几个?(规定index从1开始)
pStatement.setString(1,newName);
pStatement.setString(2,oldName);

//执行sql
num = pStatement.executeUpdate(); //记得把参数去掉!!!
if(num>0){
    System.out.println("修改成功!");
}

四、IDEA充当DBMS(替代sqlyog)

抛弃sqlyog,完全用伟大的IDEA!

如果提示时区问题,可以在Advanced里改成上海:

然后就连接成功了。注意,我们是用root这个用户登录的,如果此时sqlyog也登录了root用户或者java程序连接数据库时登录了root用户,此时会被强行断开,相当于被挤下线了。

但是此时我们还看不到都有哪些数据库,

把我们想要的模式导入进来

然后就能看见都有哪些表和字段了!

如何查看表?双击表!

如何修改属性?双击属性!

如何写SQL语句?

执行!

五、jdbc操作事务

5.1 转账成功的例子

在jdbcstudy数据库下执行如下代码:


/*创建账户表,用于jdbc事务的测试*/
CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name varchar(40),
    money float
);

/*插入测试数据*/
insert into account(id, name, money) VALUES(1,'A',1000);
insert into account(id, name, money) VALUES(2,'B',1000);
insert into account(id, name, money) VALUES(3,'C',1000);

新建了account表

A给B转账100元的代码:


package com.test.demo02;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TransactionTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //连接上数据库
            connection = jdbcUtils.getConnection();
            //关闭数据库事务自动提交,自动开启
            connection.setAutoCommit(false);

            String sql1 = "UPDATE account SET money=money-100 WHERE name='A'";
            preparedStatement = connection.prepareStatement(sql1);//预编译
            preparedStatement.executeUpdate();

            String sql2 = "UPDATE account SET money=money+100 WHERE name='B'";
            preparedStatement = connection.prepareStatement(sql2);//预编译
            preparedStatement.executeUpdate();

            //手动提交事务
            connection.commit();
            System.out.println("成功!");

        } catch (SQLException throwables) {
            try {
                //如果失败,就回滚
                connection.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            jdbcUtils.closeConnection(connection,preparedStatement,resultSet);
        }
    }
}

结果:

PS: 可以不在catch中手动写回滚,如果失败默认会回滚的

5.2 测试转账失败

在两个sql语句之间加一句错误代码。事务执行了A-100后会失败,然后回滚。


String sql1 = "UPDATE account SET money=money-100 WHERE name='A'";
preparedStatement = connection.prepareStatement(sql1);//预编译
preparedStatement.executeUpdate();

int x = 1/0;  //事务在这里会失败

String sql2 = "UPDATE account SET money=money+100 WHERE name='B'";
preparedStatement = connection.prepareStatement(sql2);//预编译
preparedStatement.executeUpdate();

查看结果:

转账是安全的!

六、数据库连接池

数据库连接池和线程池一样,都是池化技术,他们的思想也一样。

池化技术:数据库“连接-断开”以及线程“创建-销毁”的过程十分浪费资源,那我们就在池子中预先准备好“已经连接上的数据库”和“已经创建好的线程”。谁要用就去取,用完以后也不“断开数据库连接”或者“销毁线程”,而是再放回池子当中去。

假如连接池里一共有15个资源,池子可以设置两个参数:

最少连接数:平常池子中准备多少合适呢?可以设为10个,让其他5个先闲着。

最大连接数:高峰期,最多15个。

排队等待:如果15个连接都被占用了,那么第16个连接请求就要排队等待。

6.1 编写连接池

自己编写连接池的话需要实现DateSource接口,这里有别人写好的开源的连接池:

  • DBCP

  • C3P0

  • Druid:阿里巴巴写的

  • Hikari:Springboot默认集成的

  • 。。。大佬们不断推出更好的数据源

使用了连接池后,我们在程序中就不需要自己写连接-释放数据库的操作了。而是调用大佬给出的接口。

省去了如下jdbcUtils中我们自己读取properties配置文件的代码:



    static{
        try {
            //先读取配置文件
            //InputStream inputStream = jdbcUtils.class.getClassLoader().getResourceAsStream("E:\\Java Project\\connectMysql\\src\\db.properties");
            //FileInputStream inputStream = new FileInputStream("E:\\Java Project\\connectMysql\\src\\db.properties");
            //if(inputStream == null){
            //    System.out.println("null");
            //}
           // Properties properties = new Properties();
            properties.load(inputStream);
            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");
            System.out.println(driver+ " "+url+" "+username+" "+password);
            //加载jdbc
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

6.2 使用DBCP连接池

(1)导入jar包

需要导入两个包,这里我们导入老版本(现在已经推出新的了,像我们下面用的commons-pool-1.6.jar已经是2012年的了)

  • commons-dbcp-1.4.jar

  • commons-pool-1.6.jar


<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>

(2)编写properities配置文件

DBCP给我们提供了模板,里面的参数必须按照DBCP规定的写,不然DBCP读不出来

在src下新建dbcp.properties文件

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

(3)连接池工具类jdbcUtila_DBCP.java


package com.test.pool;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

public class jdbcUtils_DBCP {
    private static DataSource dataSource = null;
    //jdbc只需要加载一次,所以我们写在静态代码块里,
    static{
        try {
            //先读取配置文件
            FileInputStream inputStream = new FileInputStream("E:\\Java Project\\connectMysql\\src\\dbcp.properties");
            if(inputStream == null){
                System.out.println("null");
            }
            Properties properties = new Properties();
            properties.load(inputStream);

            //创建数据源  工厂模式
            dataSource = BasicDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //连接数据库,返回数据库对象
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection(); //数据源去获取连接,代替了原来我们用DriverManager.getConnection()
    }

    //断开数据库连接,实际上是放回连接池中?
    public static void closeConnection(Connection conn, Statement statement, ResultSet resultSet){
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(resultSet !=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

(4) 测试

测试代码只需要改两个地方,把工具类换成jdbcUtils_DBCP就行了


package com.test.pool;

import com.test.demo02.jdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UpdateTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pStatement =null;
        ResultSet resultSet = null;
        int num = 0;
        try {
            //不同之处(一),jdbcUtils_DBCP使用数据源建立数据库连接!!!
            connection = jdbcUtils_DBCP.getConnection();

            String oldName = "笨蛋们";
            String newName = "1月30";
            String sql = "UPDATE users SET `NAME`=? WHERE `NAME`=?";
            pStatement = connection.prepareStatement(sql);
            pStatement.setString(1,newName);
            pStatement.setString(2,oldName);
            num = pStatement.executeUpdate();
            if(num>0){
                System.out.println("修改成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {
            //不同之处(二) jdbcUtils_DBCP
            jdbcUtils_DBCP.closeConnection(connection,pStatement,resultSet);
        }
    }
}

6.3 使用C3P0连接池

(1)导入jar包


<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>mchange-commons-java</artifactId>
    <version>0.2.19</version>
</dependency>

(2)c3p0-config.xml配置文件

也是C3P0给定的模板

第一个是默认配置,后面可以自己加配置,用name区分

在src下新建c3p0-config.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--
c3p0的缺省(默认)配置
如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认)-->account
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">30</property>
    </default-config>


    <!--   新增配置
   在代码中"ComboPooledDataSource ds=new ComboPooledDataSource("Oracle");"这样写就表示使用的是name为Oracle的配置-->
    <name-config name="Oracle">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </name-config>

</c3p0-config>

xml不需要程序去读,会默认匹配

(3)连接池工具类

但是测试的时候getConnect一直出错,连接不上数据库,不知道为什么!


package com.test.pool;

import com.mchange.v2.c3p0.ComboPooledDataSource;

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

public class jdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource = null;
    static {
        //创建数据源 工厂模式
        dataSource = new ComboPooledDataSource(); //读取默认配置
        /**
         * 测试用
         */
        if(dataSource!=null){
            System.out.println("DataSource不是空的");
        }else{
            System.out.println("DataSource是空的!");
        }
    }

    public static Connection getConnection() throws SQLException {
        /**
         * 这里连接不上,不知道为什么!
         */
        Connection connection = dataSource.getConnection();
        /**
         * 测试用
         */
        if(connection != null){
            System.out.println("connection不是空的");
        }else{
            System.out.println("connection是空的!");
        }
        return connection;
    }

    //断开数据库连接,实际上是放回连接池中?
    public static void closeConnection(Connection conn, Statement statement, ResultSet resultSet) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (resultSet != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

(4)测试


package com.test.pool;

import com.test.demo02.jdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class InsertTest {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement pStatement =null;
        ResultSet resultSet = null;
        int num = 0;
        try {
            //不同之处(一),jdbcUtils_C3P0使用数据源建立数据库连接!!!
            connection = jdbcUtils_C3P0.getConnection();

            String oldName = "1月30";
            String newName = "有目标就可以奋战超过6小时";
            String sql = "UPDATE users SET `NAME`=? WHERE `NAME`=?";
            pStatement = connection.prepareStatement(sql);
            pStatement.setString(1,newName);
            pStatement.setString(2,oldName);
            num = pStatement.executeUpdate();
            if(num>0){
                System.out.println("修改成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();

        }finally {
            //不同之处(二) jdbcUtils_C3P0
            jdbcUtils_C3P0.closeConnection(connection,pStatement,resultSet);
        }
    }
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐