JDBC

1、JDBC

1.1、简介

  • Sun 公司于 1996 年提供了一套访问数据库的标准API,即 JDBC,其全称为 Java Database Connectivity
  • JDBC是 Java 与数据库的接口规范,由 Java 语言编写的类和 接口组成。
  • 主流的数据库提供商均在自己的驱动中实现了 JDBC提供的接口,通过 JDBC 可以完成对不同种类的数据库的访问。

1.2、JDBC入门 一、持久化

  • 持久化是指将数据存储到可永久保存的存储设备中。
  • 持久化的主要应用场景是将内存中的对象存储在数据库、XML数据文件或其他种类的磁盘文件中。 同时,持久化也是将程序数据在瞬时状态和持久状态之间转换的机制,它的出现是为了弥补计算机内存的缺陷。
  • 内存过于昂贵,与磁盘、光盘相比,内存的价格要高很多,而且维持成本较高,因此, 内存资源是相对稀缺的。在程序运行过程中,因为内存容量限制,一些数据需要被持久 化到外部存储设备中。
  • 持久化有多种实现形式,在 Java 编程中,常见的持久化方式是将程序产生的数据存储
    到数据库中,而 JDBC则是实现这一过程的重要工具。

1.3、JDBC的概念

  • 它是一套用于执行 SQL 语句的 Java API,由一组用 Java 语言编写的类和接口组成,是 Java 程序访问数据库的标准 规范。

  • 通过 JDBC 提供的 API,应用程序可以连接到数据库,并使用 SQL 语句完成对数据库中数据的CUPD(插入、删除、更新、查询)等操作。

  • 有了 JDBC,开发人员无须为访问不同的数据库而编写不同的应用程序,只需要使用 JDBC编写一个通用程序即可。

    image-20211016152424660

  • 应用程序在使用 JDBC访问特定的数据库时,需要与不同的数据库驱动进行连接。 JDBC提供接口,而驱动是接口的实现,没有驱动将无法完成数据库连接。每个数据库提供商都需要提供自己的驱动,用来连接本公司的数据库

image-20211016152328051

1.4、JDBC的体系结构

JDBC API:面向程序,供 Java 程序开发人员使用。

JDBC Driver Manager:注册数据库驱动,供 Java 程序开发人员使用。

JDBC Driver API:面向数据库,供数据库厂商使用。

image-20211016152629635

其中,JDBC API 通过Driver Manager(驱动管理器)实现与数据库的透明连接,提供 获取数据库连接、执行 SQL语句、获得结果等功能。JDBC API 使开发人员获得了标准 的、纯 Java 的数据库程序设计接口,在 Java 程序中为访问任意类型的数据库提供支持。 JDBC Driver Manager(驱动管理器)为应用程序装载数据库驱动,确保使用正确的驱动来 访问每个数据源。JDBC Driver Manager 的一个特色功能是能够支持连接到多个异构数据库 的多个并发驱动程序。JDBC Driver API 提供了数据库厂商编写驱动程序时必须实现的接
口。

1.5、 JDBC的常用API

1.Driver

  • 接口 Driver 接口是所有JDBC驱动程序必须要实现的接口,该接口供数据库厂商使用。
  • 在编写 JDBC程序时,必须先装载特定数据库厂商的驱动程序,
  • 装载驱动程序通过 java.lang.Class 类中的静态方法 forName()实现

2.DriverManager 类

  • DriverManager 类用于加载 JDBC驱动并创建与数据库的连接

DriverManager 类的常用方法:

方法名称 功能
registerDriver(Driver driver) 注册数据库的驱动程序
getConnection (String url,String user,String password) 获取数据库连接

3.Connection接口

  • Connection 接口表示 Java 程序和数据库的连接,Java 程序和数据库的交互是通过 Connection 接口来完成的

Connection 接口的常用方:

方法名称 功能
createStatement() 创建向数据库发送 sql 的 Statement 对象
prepareStatement(String sql) 创建向数据库发送预编译 sql 的 PrepareSatement 对象
prepareCall(String sql) 创建执行存储过程的 CallableStatement 对象

4.Statement 接口

  • Statement 接口用于向数据库发送 SQL 语句

Statement 接口提供了三个执行 SQL 语句 的方法:

方法名称 功能
execute(String sql) 运行语句,返回是否有结果集
executeQuery(String sql) 运行 select 语句,返回 ResultSet 结果集
executeUpdate(String sql) 运行 insert/update/delete操作,返回更新的行数

5. PreparedStatement 接口

  • PreparedStatement 接口继承自 Statement 接口,用于执行预编译的 SQL 语句。

PreparedStatement 接口提供了一些对数据库进行基本操作的方法、

方法名称 功能
executeQuery() 运行 select 语句,返回 ResultSet 结果集
executeUpdate() 运行 insert/update/delete 操作,返回更新的行数
addBatch() 把多条 sql 语句放到一个批处理中
executeBatch() 向数据库发送一批 sql 语句执行

6. CallableStatement 接口

  • CallableStatement 接口继承自 PreparedStatement 接口,由 prepareCall()方法创建,用于 调用 SQL存储过程。

CallableStatement 接口提供了一些对数据库进行基本操作的方法,:

方法名称()
wasNull() 查询最后一个读取的 OUT参数是否为 SQL类型的 Null 值
setNull(String parameterName,int sqlType) 将指定参数设置为 SQL类型的NULL
getInt(int parameterIndex 以 Java 语言中 int 值的形式获取数据库中 Integer 类型参数的 值
setString(String parameterName,String x) 将指定参数设置为给定的 Java 类型的 String 值
registerOutParameter(int parameterIndex, int sqlType) 按顺序位置 parameterIndex 将 OUT参数注册为 SQL类型

7.ResultSet 接口

  • ResultSet 接口表示执行 select 查询语句获得的结果集,该结果集采用逻辑表格的形式进 行封装。

ResultSet 接口中提供了一系列操作结果集的方法:

方法名称 功能
getString(int index)、getString(String columnName) 获得在数据库里是 varchar、char 等类型的数据对 象
getFloat(int index)、getFloat(String columnName) 获得在数据库里是 Float 类型的数据对象
getDate(int index)、getDate(String columnName) 获得在数据库里是 Date 类型的数据
getBoolean(int index) 、 getBoolean(String columnName) 获得在数据库里是 Boolean 类型的数据
getObject(int index)、getObject(String columnName) 向数据库发送一批 sql 语句执行 next()
next() 移动到下一行
previous() 移动到前一行
absolute(int row) 移动到指定行
beforeFirst() 移动到ResultSet的最前面
afterLast() 移动到ResultSet的最后面

8、ResultSetMetaData 接口

  • ResultSetMetaData 接口用于获取关于 ResultSet 对象中列的类型和属性信息的对象。
方法名称 功能
getColumCount() 返回所有字段的数目
getColumName(int colum) 根据字段的索引值取得字段的名称
getColumType (int colum) 根据字段的索引值取得字段的类型

9、JDBC URL

  • JDBC URL提供了一种标识数据库的方法,它可以使JDBC程序识别指定的数据库并与之建立连接。
  • 大家在编写 JDBC程序时, 无须关注 JDBC URL的形成过程,只需使用与所用 的数据库一起提供的URL即可。

语法:

String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai" ;
格式
//mysql--3306
jdbc:mysql:[]//localhost:3306/test?参数名=参数值&参数名=参数值
协议 |子协议|	主机地址:端口		数据库
//oralce--1521
//jdbc:oracle:thin:@loaclhost:1521:sid

maxReconnectsautoReconnect 重试连接的次数 initialTimeoutautoReconnect 两次重连之间的时间间隔,单位:秒
connectTimeout socketTimeoutsocket
和数据库服务器建立 socket 连接时的超时,单位:毫秒。 0 表示永不 超时,适用于 JDK 1.4 及更高版本
操作(读写)超时,单位:毫秒。 0 表示永不超时

参数类型 参数名称
user 数据库用户名,用于连接数据库
password 用户密码,用于连接数据库
useUnicode 是否使用 Unicode 字符集,如果参数 characterEncoding设置为 gb2312 或 gbk,本参数值必须设置为 true
characterEncoding 当 useUnicode 设置为 true 时,指定字符编码。比如可设置为 gb2312、 gbk、utf8
autoReconnect 当数据库连接异常中断时,是否自动重新连接
autoReconnectForPools 是否使用针对数据库连接池的重连策略
failOverReadOnly 自动重连成功后,连接是否设置为只读
maxReconnectsautoReconnect 重试连接的次数
initialTimeoutautoReconnect 两次重连之间的时间间隔,单位:秒
connectTimeout 和数据库服务器建立 socket 连接时的超时,单位:毫秒。 0 表示永不 超时,适用于 JDK 1.4 及更高版本
socketTimeoutsocket 操作(读写)超时,单位:毫秒。 0 表示永不超时

2、第一个JDBC程序

创建数据库

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `id` int NOT NULL,
  `NAME` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `PASSWORD` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `email` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `birthday` date NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, 'zhansan', '123456', 'zs@sina.com', '1989-12-04');
INSERT INTO `users` VALUES (2, 'lishi', '123456', '.com', '2021-10-14');
INSERT INTO `users` VALUES (3, 'wangwu', '123456', 'com.com', '2021-10-13');

SET FOREIGN_KEY_CHECKS = 1;

映入jar包

可以用maven和导入jar包

maven:

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

Test:

package com.shumei.lis01;
import java.sql.*;
public class JDBCfirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");//固定写法
        //2.用户信息url
        String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai" ;


        String username="root";
        String password="123456";
        //3.连接 Connection代表数据库
        Connection connection = DriverManager.getConnection(url, username, password);
        //4.执行SQL对象 Statement执行SQL的对象
        Statement statement = connection.createStatement();
        //5.执行sql对象,返回存在可能结果集
        String sql= "select * from users";

        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            System.out.println("id="+resultSet.getObject("id"));
            System.out.println("name="+resultSet.getObject("name"));
            System.out.println("password="+resultSet.getObject("password"));
            System.out.println("email="+resultSet.getObject("email"));
            System.out.println("birthday="+resultSet.getObject("birthday"));
        }

        //6.释放缓存
        resultSet.close();
        statement.close();
        connection.close();
    }
}

测试总结:

  • 使用老版5.1 ,如果报错 ,改成Url后面那里改成useSSL=false;
  • 使用8.0新版,加载驱动那改成Class.forName(com.mysql.cj.jdbc.Driver);
  • ,然后url后面加一串&serverTimezone=Asia/Shanghai'

DriverManager

//1.加载驱动
//        DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");//固定写法
//2.用户信息url
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai" ;
//connection 代表数据库
//数据库设置自动提交
connection。setAutoCommit();
//事务提交
connection.commit();
//事务回滚
connection.rollback();

url

格式
//mysql--3306
jdbc:mysql:[]//localhost:3306/test?参数名=参数值&参数名=参数值
协议 |子协议|	主机地址:端口		数据库
//oralce--1521
//jdbc:oracle:thin:@loaclhost:1521:sid

Statement执行SQL对象 prepareStatement执行SQL对象

statement.executeQuery();//执行查询 返回结果集
statement.execute();//执行任何sql
statement.executeUpdate();//执行更新、插入、删除、返回一个受影响的行数
statement.executeBatch();//执行多个SQL

ResultSet查询到的结果集:封装了所有结果

释放资源

3、statement对象

代码实现

1、 提取工具类

package com.shumei.lis02.utlis;

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

public class jdbcUtils {
    private static String  dirver = null;
    private static String  url = null;
    private static String  username = null;
    private static String  password = null;
    static {
        try {
            //src下的都可以通过反射得到   类加载器 : getClassLoader()  获得具体资源  : getResourceAsStream()
            InputStream in = jdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            //拿到流
            Properties properties = new Properties();
            //加载流
            properties.load(in);
            //获取
            dirver = properties.getProperty("dirver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            //驱动只用加载一次
            Class.forName(dirver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //获取资源
    public  static Connection getConnction() throws SQLException {
       return DriverManager.getConnection(url, username, password);


    }
    //释放资源
    public  static void release(Connection conn, Statement st,ResultSet rs ){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

2、编写增删改查的方法,executeUpdate

package com.shumei.lis02;
import com.shumei.lis02.utlis.jdbcUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestUpdate {
    @Test
    public void Insert(){
        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;
        try {
           conn = jdbcUtils.getConnction();//获取数据库连接
            st=conn.createStatement();//获取SQL执行对象
            String sql="insert into users(id,name,password,email,birthday) value(4,'xiaowang','123456','198.qq.com','1988-11-22')";
            int i=   st.executeUpdate(sql);
            if (i>0){
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
        jdbcUtils.release(conn,st,rs);
      }
    }
    @Test
    public void update(){
        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = jdbcUtils.getConnction();//获取数据库连接
            st=conn.createStatement();//获取SQL执行对象
            String sql="update users set name='wangba',email='123@qq.com' where id='4'";
            int i=   st.executeUpdate(sql);
            if (i>0){
                System.out.println("修改成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            jdbcUtils.release(conn,st,rs);
        }
    }
    @Test
    public void delete(){
        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;
        try {
            conn = jdbcUtils.getConnction();//获取数据库连接
            st=conn.createStatement();//获取SQL执行对象
            String sql="delete from users where id='4'";
            int i=   st.executeUpdate(sql);
            if (i>0){
                System.out.println("删除成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            jdbcUtils.release(conn,st,rs);
        }
    }
}

3、查询executeQuery

    @Test
    public void Select(){
        Connection conn=null;
        Statement st=null;
        ResultSet rs=null;
        try {
           conn= jdbcUtils.getConnction();
            st = conn.createStatement();

            String sql="select * from users";

             rs = st.executeQuery(sql);//查询

            while (rs.next()){
                System.out.println(rs.getString("id"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("PASSWORD"));
                System.out.println(rs.getString("email"));
                System.out.println(rs.getString("birthday"));
            }

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

4、SQL注入问题

  • sql存在漏洞,对被攻击导致数据泄露
  • 原因在于SQL会被拼接 or

4、注意:关于工具类的一些问题

1.1、Could not initialize class XXX

原因:初始化的过程中执行静态代码块的过程中出现错误, 也就是说, 加载配置文件错误: 没有加载到指定路径的配置文件.

需要检查获取的方式有两种:

  • 注释的读取的配置文件db.properties应该在resources目录下
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
  • 读取的配置文件db.properties应该和MyJdbcUtils在同一个package下
InputStream in = JdbcUtils.class.getResourceAsStream("db.properties");

1.2、closing inbound before receiving peer's close_notify

  • MySQL在高版本需要指明是否进行SSL连接
  • 在配置连接中吧useSSL=flase就可以了

5、preparedstatement对象

  • Preparedstatement对象可以防止SQL注入

  • 防止SQL注入的本质:把传进来的参数当作字符,假设其中存有转义字符,像 ' 就会被直接转义

  1. 新增
@Test
public void Select(){
    Connection conn=null;
    PreparedStatement pstm=null;
    ResultSet rs=null;
    try{
        conn = jdbcUtils.getConnction();

        String sql  ="select * from users where id =?";

      pstm=  conn.prepareStatement(sql);

      pstm.setInt(1,1);

        rs = pstm.executeQuery();
        while (rs.next()){
            System.out.println(rs.getString("name"));
        }
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtils.release(conn,pstm,rs);
    }
}
  1. 删除
@Test
public void Delete(){
    Connection conn=null;
    PreparedStatement pstm  =null;
    try {
        conn = jdbcUtils.getConnction();
        //区别
        //使用 ? 占位符代替参数
        String sql="delete from users where id= ?";
        pstm =  conn.prepareStatement(sql);//预编译SQL,先编译,不执行
        //手动赋值参数
        pstm.setInt(1,4);
        //执行
        int i= pstm.executeUpdate();
        if(i>0){
            System.out.println("Finish!");
        }

    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtils.release(conn,pstm,null);
    }
}
  1. 更新
@Test
public void Update(){
    Connection conn=null;
    PreparedStatement pstm  =null;
    try {
        conn = jdbcUtils.getConnction();
        //区别
        //使用 ? 占位符代替参数
        String sql="update users set name =? where id =?";
        pstm =  conn.prepareStatement(sql);//预编译SQL,先编译,不执行
        //手动赋值参数
        pstm.setString(1,"小王八");
        pstm.setInt(2,1);
        //执行
        int i= pstm.executeUpdate();
        if(i>0){
            System.out.println("Finish!");
        }

    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtils.release(conn,pstm,null);
    }
}
  1. 查询
@Test
public void Insert(){
    Connection conn=null;
    PreparedStatement pstm  =null;
    try {
        conn = jdbcUtils.getConnction();
        //区别
        //使用 ? 占位符代替参数
        String sql="insert into users(id,name,password,email,birthday) value(?,?,?,?,?)";
        pstm =  conn.prepareStatement(sql);//预编译SQL,先编译,不执行
        //手动赋值参数
        pstm.setInt(1,4);
        pstm.setString(2,"狗狗");
        pstm.setString(3,"1234565");
        pstm.setString(4,"000.@qq.com");
        //注意: sql.Date 数据库  java.sql.Date()
        //      util.Date  java  new Date().getTime()获取时间戳
        pstm.setDate(5,new Date(new java.util.Date().getTime()));
        //执行
       int i= pstm.executeUpdate();
 
        if(i>0){
            System.out.println("Finish!");
        }

    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtils.release(conn,pstm,null);
    }
}

6、事务

ACID原则

原子性:要么都完成,要么都不完成

一致性:总数不变

隔离性:多个线程互不干扰

持久性:提交后不可逆,持久化到数据库中

隔离性遇到的问题:

脏读:一个事务读取了另外一个没有提交的事务

不可重复读:在同一个事务内,重复读取表中的数据,表数据改变

虚读(幻读):在同一个事务内,读取到了别人插入到数据,导致前后读出结果不一致

代码实现

1.开启事务: conn.setAutoCommit(false)默认自动提交

2.一组业务执行完毕,提交事务

3.可以在catch语句显示的定义回滚语句,但是默认失败就会回滚

7、数据库连接池

数据库连接---执行完毕---释放

连接---释放过程十分浪费系统资源

池化技术:准备一些预先的资源,过来就连接预先准备的

最小连接数:10

最大连接数:

等待超时:

编写连接池,实现一个接口DataSource

开源数据源实现

DBCP

C3P0

Druid:阿里巴巴

1、DBCP

1-0、通过配置文件创建BasicDataSource对象

1.1导入maven

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.9.0</version>
</dependency>

1.2、编写dbcp.properties

#连接基本配置
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/studentinfo?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
username=root
password=123456
#初始化连接
initialSize=10
#最大连接数量
maxActive=50
#最小空闲连接 
minIdle=5
#超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 
maxWait=600000

1.3、通过配置文件创建BasicDataSource对象

工具类:

package com.shumei.DBCP.utilts;

import com.shumei.lis02.utlis.jdbcUtils;
import org.apache.commons.dbcp2.BasicDataSourceFactory;

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

public class jdbcUtilts_Dbcp {
    //提升作用域
    public static DataSource dataSource=null;
    static {
        try {
            //src下的都可以通过反射得到   类加载器 : getClassLoader()  获得具体资源  : getResourceAsStream()
            InputStream in = jdbcUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
            //拿到流
            Properties properties = new Properties();
            //加载流
            properties.load(in);
            //创建数据源 工厂模式创建
           dataSource = BasicDataSourceFactory.createDataSource(properties);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取资源
    public  static Connection getConnction() throws SQLException {
        return dataSource.getConnection();
    }
    //释放资源
    public  static void release(Connection conn, Statement st, ResultSet rs ){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试:

  • 和正常的差不多
package com.shumei.DBCP.test;

import com.shumei.DBCP.utilts.jdbcUtilts_Dbcp;
import org.junit.Test;

import java.sql.*;

public class TestDbcp {
    @Test
    public void Select1(){
        Connection conn=null;
        PreparedStatement pstm=null;
        ResultSet rs=null;
        try {
            conn = jdbcUtilts_Dbcp.getConnction();//获取连接

            String sql="select * from users";

            pstm=  conn.prepareStatement(sql);//获取SQL执行对象

            rs = pstm.executeQuery();//提交

            while (rs.next()){
                System.out.println(rs.getString("name"));
                System.out.println(rs.getString("id"));
                System.out.println(rs.getString("email"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                jdbcUtilts_Dbcp.getConnction();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    @Test
    public void Select2(){

    }
}

1-1第二种:直接创捷BasicDataSource并设置属性

1.添加Maven依赖

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-dbcp2</artifactId>
    <version>2.9.0</version>
</dependency>

2.编写测试

@Test
public void Select2()throws SQLException{
    BasicDataSource dataSource = new BasicDataSource();
    // 基本四项设置
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/jdbcstudy?" +
            "characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC" +
            "&rewriteBatchedStatements=true");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    // 其他设置
    dataSource.setInitialSize(10);
    dataSource.setMinIdle(3);
    //获取连接
    Connection conn=dataSource.getConnection();
	//预编译sql
    String sql="select * from users";
   PreparedStatement pstm=  conn.prepareStatement(sql);//获取SQL执行对象
	//提交
   ResultSet rs = pstm.executeQuery();
    while (rs.next()){
        System.out.println(rs.getString("name"));
        System.out.println(rs.getString("id"));
        System.out.println(rs.getString("email"));
    }
	  // 关闭资源
        rs.close();
        pstm.close();
        dataSource.close();	
}

2、C3P0

1-0通过读取配置文件创建ComboPooledDataSource对象

  • 由于c3p0-config.xml是xml配置文件所以不需要通过类加载器引用

1.导入maven`

<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.5</version>
</dependency>

2.编写c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcsutdy?characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        <property name="checkoutTimeout">30000</property>
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
        <user-overrides user="test-user">
            <property name="maxPoolSize">10</property>
            <property name="minPoolSize">1</property>
            <property name="maxStatements">0</property>
        </user-overrides>
    </default-config>
    <!-- 命名的配置,指定时使用 -->
    <named-config name="Mysql">
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=UTF-8&amp;userSSL=false&amp;serverTimezone=GMT%2B8</property>
<!--        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>-->
        <property name="user">root</property>
        <property name="password">123456</property>
        <!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">20</property>
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">40</property>
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property>
    </named-config>
</c3p0-config> 

3.编写工具类

package com.shumei.DBCP_C3P0.utilts;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class jdbcUtilts_C3p0 {
    private static ComboPooledDataSource dataSource=new ComboPooledDataSource("Mysql");

    public  static Connection getConnction() throws SQLException {
        return dataSource.getConnection();
    }
    //释放资源
    public  static void release(Connection conn, Statement st, ResultSet rs ){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试:

@Test
public void Select1() throws SQLException {
    Connection conn=null;
    PreparedStatement pstm=null;
    ResultSet rs=null;
    try {
        conn = jdbcUtilts_C3p0.getConnction();

        //获取执行者对象
        String sql = "select * from users";
        //执行SQL语句
        pstm = conn.prepareStatement(sql);

        rs = pstm.executeQuery();
        //处理结果集
        while (rs.next()) {
            System.out.println(rs.getString("name"));
        }
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtilts_C3p0.release(conn,pstm,rs);
    }
}

问题:

  • 连接超时(java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.)

解决

1、很大程度上c3p0-config.xml配置文件有问题

可以看下url

<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=UTF-8&amp;userSSL=false&amp;serverTimezone=GMT%2B8</property>
  

 
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>
  

替换成

 <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?characterEncoding=UTF-8&amp;useSSL=false&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true</property>

1-1直接创建ComboPooledDataSource对象并设置属性

测试:

 @Test
    public void Select2() throws SQLException, PropertyVetoException {
        //创建核心
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 基本四项设置
        dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy?" +
                "characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC" +
                "&rewriteBatchedStatements=true");
        dataSource.setUser("root");
       dataSource.setPassword("123456");
        // 其他设置
        //初始化连接数
        dataSource.setInitialPoolSize(10);
        //最大连接数
        dataSource.setMaxPoolSize(20);
        //最小连接数
        dataSource.setMinPoolSize(3);
        Connection conn= dataSource.getConnection();

        //设置每次创建的连接数
        dataSource.setAcquireIncrement(3);
        //获取执行者对象
        String sql = "select * from users ";
        //执行SQL语句
        PreparedStatement pstm = conn.prepareStatement(sql);
        ResultSet rs = pstm.executeQuery(sql);
        //处理结果集
        while (rs.next()) {
            System.out.println(rs.getString("name"));
        }
        //关闭资源
        rs.close();
        pstm.close();
        conn.close();
        dataSource.close();
    }
}

3、Druid

  • 阿里巴巴开源平台的一个项目
  • 为监控而生的数据库连接池
  • 可以替换DBCP、C3P0
  • 和DBCP类似

Maven导入jar包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.6</version>
</dependency>

配置文件和dbcp通用

dirver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=123456

3.1、通过读取配置文件创建DruidDataSource对象

@Test
public void test() throws Exception {
    // getClassLoader()类加载器获取对象
    InputStream in =TestDruid.class.getClassLoader().getResourceAsStream("db.properties");
    //拿到流
    Properties properties = new Properties();
    //加载流
    properties.load(in);
    //使用DruidDataSourceFactory调用静态方法,dataSource
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    //获得连接
    Connection conn = dataSource.getConnection();
    String sql="select * from users  ";
    PreparedStatement pest = conn.prepareStatement(sql);
    ResultSet rs = pest.executeQuery();

    while (rs.next()){
        System.out.println(rs.getString("name")+rs.getString("age"));
    }
    rs.close();
    pest.close();
    conn.close();
}

3.2、直接创建DruidDataSource对象

@Test
public  void test2() throws SQLException {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/jdbcstudy?" +
            "characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC" +
            "&rewriteBatchedStatements=true");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    // 其他设置
    dataSource.setInitialSize(10);
    dataSource.setMinIdle(3);
    //获取连接
    DruidPooledConnection conn = dataSource.getConnection();
    String sql="select * from users";
    PreparedStatement pstm = conn.prepareStatement(sql);
    //提交
    ResultSet rs = pstm.executeQuery();
    while (rs.next()){
        System.out.println(rs.getString("name"));
        System.out.println(rs.getString("id"));
        System.out.println(rs.getString("email"));
    }
    // 关闭资源
    rs.close();
    pstm.close();
    dataSource.close();
}

3.3、创建工具类

和dbcp类似,只是工厂不同

工具类

package com.shumei.DBCP_C3P0.utilts;


import com.alibaba.druid.pool.DruidDataSourceFactory;

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

public class jdbcUtilts_Druid {
    private static DataSource dataSource=null;
    static {
        InputStream in = jdbcUtilts_Druid.class.getClassLoader().getResourceAsStream("db.properties");
        Properties properties = new Properties();
        try {
            properties.load(in);
             dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取资源
    public static Connection getConnction() throws SQLException{
        return dataSource.getConnection();
    }
 //释放资源
    public  static void release(Connection conn, Statement st, ResultSet rs ){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

测试:

@Test
public void test3(){
    //初始化
    Connection conn=null;
    PreparedStatement pstm =null;
    ResultSet rs=null;
    try{
         conn = jdbcUtilts_Druid.getConnction();//获取连接

        String sql="select * from users";
         pstm = conn.prepareStatement(sql);//获取执行对象

         rs= pstm.executeQuery();//提交

        while (rs.next()){
            System.out.println(rs.getString("name"));
            System.out.println(rs.getString("id"));
            System.out.println(rs.getString("email"));
        }
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }finally {
        jdbcUtilts_Druid.release(conn,pstm,rs);
    }
}

8、DBUtils工具类

  • Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能。

  • Dbutils:主要是封装了JDBC的代码,简化dao层的操作。
    作用:帮助java程序员,开发Dao层代码的简单框架。
    框架的作用:帮助程序员,提高程序的开发效率。
    出生:Dbutils是由Apache公司提供。

  • 主要有三个作用:

    • 写操作:对数据表的增删改只需要写SQL语句
    • 读操作:把结果集转为java常用集合类,方便对结果集的处理
    • 优化性能:可以使用数据源,JNDI,数据连接池等技术减少代码冗余

8.1、DBUtils核心成员

DBUtils是对jdbc的封装,所以他的类包围绕实现jdbc的功能来设计的

DBUtils提供了一系列的API

image-20211112163721364

  1. DBUtils类:

    • 主要为预载JDBC驱动,关闭资源等常规操作提供方法,
    • 它的方法一般是静态的,直接以类名调用即可

    DBUtils类的常用方法:

    方法 功能
    void close(Connection conn) 当连接不为Null时,关闭连接
    void close(Startement stat) 当声明不为Null时,关闭声明
    void close(ResultSet rs) 当结果集不为Null时,关闭结果集
    void closeQuietly(Connection conn) 当连接不为Null时,关闭连接,并隐藏一些在程序中抛出的SQL异常
    void closeQuietly(Startement stat) 当声明不为Null时,关闭声明,并隐藏一些在程序中抛出的SQL异常
    void closeQuietly(ResultSet rs) 当结果集不为Null时,关闭结果集,并隐藏一些在程序中抛出的SQL异常
    void commitAndCloseQuietly(Connection conn) 提交连接后关闭连接,并隐藏一些在程序中抛出的sql异常
    Boolean loadDriver(String driveClassName) 装载并注册jdbc驱动,如果成功就返回TRUE
  2. QueryRunner类:

    • 用于执行SQL语句,和jdbc中的PreparedStatement类似,封装了执行SQL语句的代码,线程安全。

    QueryRunner类常用方法:

    方法 功能
    Object query(Connection conn,String sql,ResultSetHandler rsh,Object[] params) 执行查询操作,需要传入Connection对象
    Object query(String sql,ResultSetHandler rsh,Object[] params) 执行查询操作
    Object query(Connection conn,String sql,ResultSetHandler rsh) 执行一个不需要替换参数的更新操作
    int update(Connection conn,String sql,Object[] params) 执行一个更新(插入,删除,修改
    int update(Connection conn,String sql) 执行一个不需要替换参数的更新操作
    int[] batch(Connection conn,String sql,Object[][] params) 批量添加,更改,删除
    int[] batch(String sql,Object[][] params) 批量添加,更改,删除
  3. ResultSetHandler接口

    • 用来处理查询之后获得的结果,为了音符各种各样的查询场景,DBUtlis提供了10余种该接口的实现

    实现类:

类名称 功能
ArrayHandler 将查询结果的第一行数据,保存到Object数组中
ArrayListHandler 将查询结果的每一行数据保存到Object数组中,然后将数据存入List集合
BeanHandler 将查询结果的第一行数据,封装到类对象中
BeanListHandler 将查询结果的每一行数据封装到javaBean中,然后再存入List集合
。。。

8.2、DBUtils实现DML、DQL/Dao封装操作

  1. 导入maven

    <dependency>
        <groupId>commons-dbutils</groupId>
        <artifactId>commons-dbutils</artifactId>
        <version>1.6</version>
    </dependency>
    
  2. 编写工具类

    package com.gdsdxy.utils;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class C3P0Utils {
        private static ComboPooledDataSource dataSource=new ComboPooledDataSource("gdsdxy");
        public static DataSource getDataSource(){
            return dataSource;
        }
        // 创建一个ThreadLocal对象,以当前线程作为key
        private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
        // 提供当前线程中的Connection
        public static Connection getConnection() throws SQLException {
            Connection conn = threadLocal.get();
            if (null == conn) {
                conn = dataSource.getConnection();
                threadLocal.set(conn);
            }
            return conn;
        }
        // 开启事务
        public static void startTransaction() {
            // 首先获取当前线程的连接
            try {
                Connection conn = getConnection();
                // 关闭事务自动提交
                conn.setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 提交事务
        public static void commit() {
            // 首先获取当前线程的连接
            Connection conn = threadLocal.get();
            if (null != conn) {
                // 提交事务
                try {
                    conn.commit();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        // 回滚事务
        public static void rollback() {
            // 首先获取当前线程的连接
            Connection conn = threadLocal.get();
            if (null != conn) {
                // 回滚事务
                try {
                    conn.rollback();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        // 关闭连接
        public static void close() {
            Connection conn = threadLocal.get();
            if (null != conn) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    threadLocal.remove();// 从当前线程移除连接,避免造成内存泄漏
                    conn = null;
                }
            }
        }
    }
    
  3. 编写pojo/bean/实体类

    自己加get/set/toString方法

    package com.gdsdxy.bean;
    
    public class Student {
        private  int sid;
        private  String sname;
        private String age;
        private  String course;
        public Student(){
    
        }
    
  4. 编写dao接口

    package com.gdsdxy.dao;
    
    import com.gdsdxy.bean.Student;
    import com.gdsdxy.utils.C3P0Utils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.BeanHandler;
    import org.apache.commons.dbutils.handlers.BeanListHandler;
    
    import java.sql.SQLException;
    import java.util.List;
    
    //增加
    public class StudnetDao {
        public  int insert(Student stu) throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "insert into student(sname,age,course) value(?,?,?)";
            Object[] params = new Object[]{stu.getSname(),stu.getAge(),stu.getCourse()};
            int count=queryRunner.update(sql,params);
            return  count;
        }
        public int update(Student stu) throws SQLException{
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql ="update student set  age= ? ,course=? where sname=?";
            Object[] params = new Object[]{stu.getAge(),stu.getCourse(),stu.getSname()};
            int count = queryRunner.update(sql,params);
            return count;
        }
        public int delete(Student stu) throws SQLException{
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql ="delete from student where sname= ?";
            Object[] params = new Object[]{stu.getSname()};
            int count = queryRunner.update(sql,params);
            return count;
        }
        public Student selectOne(String sid) throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student where sid=?";
           Object[] params= new Object[]{sid};
           Student newStu=queryRunner.query(sql,new BeanHandler<Student>(Student.class),params);
           return newStu;
        }
        public  List<Student> selectAll() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student";
            List<Student> list = (List<Student>)queryRunner.query(sql, new BeanListHandler(Student.class));
            return list;
        }
    }
    
  5. 测试:

    package com.gdsdxy;
    
    import com.gdsdxy.bean.Student;
    import com.gdsdxy.utils.C3P0Utils;
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.*;
    import org.junit.Test;
    
    import java.sql.Array;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class TestDBUtils {
        @Test
        public void testDBUtils_Insert() throws SQLException {
            QueryRunner queryRunner=new QueryRunner(C3P0Utils.getDataSource());
            String sql="insert into student(sname,age,course) values('lisi','25','Java')";
            int count =queryRunner.update(sql);
            if(count>0){
                System.out.println("添加成功");
            }
            else{
                System.out.println("添加失败");
            }
        }
        @Test
        public void testDBUtils_Update() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql="update student set age='20' where sname='lisi'";
            int count =queryRunner.update(sql);
            if(count>0){
                System.out.println("添加成功");
            }
            else{
                System.out.println("添加失败");
            }
        }
        @Test
        public void testDBUtils_Delete() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql="delete from student where sname='lisi'";
            int count =queryRunner.update(sql);
            if(count>0){
                System.out.println("添加成功");
            }
            else{
                System.out.println("添加失败");
            }
        }
        @Test
        public void testDBUtils_ArrayHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql="select * from student where sid=?";
            Object[] arr = queryRunner.query(sql, new ArrayHandler(), new Object[]{1});
            for(int i=0;i<arr.length;i++){
                System.out.println(arr[i]+",");
            }
            for (Object a : arr) {
                System.out.println(a);
            }
        }
        @Test
        public void testDBUtils_ArrayListHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student ";
            List<Object[]> list = queryRunner.query(sql, new ArrayListHandler());
    
            for(Object[] arr:list){
                for(int i=0;i< arr.length;i++){
                    System.out.print(arr[i]+",");
                }
            }
        }
        @Test
        public void BeanHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student where sid=?";
            Student student = (Student) queryRunner.query(sql, new BeanHandler(Student.class), new Object[]{2});
            System.out.println(" sname  "+student.getSname()+" sid  "+student.getSid()+" age  "+student.getAge()+" course "+ student.getCourse());
        }
        @Test
        public void BeanListHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student";
           ArrayList<Student> list= (ArrayList<Student>) queryRunner.query(sql, new BeanListHandler(Student.class));
            for (Student student : list) {
                System.out.println(student);
            }
        }
        @Test
        public void TestDBUtils_ColumnListHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student";
            Object sname = queryRunner.query(sql, new ColumnListHandler("course"));
            System.out.println(sname);
    
        }
        @Test
        public void TestDBUtils_ScalarHandler() throws SQLException {
            QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
            String sql = "select * from student where sid=?";
            String sname =(String) queryRunner.query(sql, new ScalarHandler("sname"), new Object[]{1});
            System.out.println(sname);
        }
    
    }
    

8.3、事务处理

  1. C3P0工具类

    代码中加入ThreadLocal类将Connection对象与线程绑定

    package com.gdsdxy.utils;
    import javax.sql.DataSource;
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    public class C3P0Utils {
       // 通过读取c3p0-config文件获取连接池对象,使用name值为gdsdxy的配置
       private static ComboPooledDataSource dataSource = new ComboPooledDataSource("gdsdxy");
       // 提供一个dataSource数据源
       public static DataSource getDataSource() {
          return dataSource;
       }
       // 创建一个ThreadLocal对象,以当前线程作为key
       private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
       // 提供当前线程中的Connection
       public static Connection getConnection() throws SQLException {
          Connection conn = threadLocal.get();
          if (null == conn) {
             conn = dataSource.getConnection();
             threadLocal.set(conn);
          }
          return conn;
       }
       // 开启事务
       public static void startTransaction() {
          // 首先获取当前线程的连接
          try {
             Connection conn = getConnection();
             // 关闭事务自动提交
             conn.setAutoCommit(false);
          } catch (SQLException e) {
             e.printStackTrace();
          }
       }
       // 提交事务
       public static void commit() {
          // 首先获取当前线程的连接
          Connection conn = threadLocal.get();
          if (null != conn) {
             // 提交事务
             try {
                conn.commit();
             } catch (SQLException e) {
                e.printStackTrace();
             }
          }
       }
       // 回滚事务
       public static void rollback() {
          // 首先获取当前线程的连接
          Connection conn = threadLocal.get();
          if (null != conn) {
             // 回滚事务
             try {
                conn.rollback();
             } catch (SQLException e) {
                e.printStackTrace();
             }
          }
       }
       // 关闭连接
       public static void close() {
          Connection conn = threadLocal.get();
          if (null != conn) {
             try {
                conn.close();
             } catch (SQLException e) {
                e.printStackTrace();
             } finally {
                threadLocal.remove();// 从当前线程移除连接,造成内存泄漏
                conn = null;
             }
          }
       }
       // 通过读取c3p0-config文件获取连接池对象,使用name值为gdsdxy的配置
       //private static ComboPooledDataSource dataSource = new ComboPooledDataSource("gdsdxy");
       // 提供一个dataSource数据源
       /*public static DataSource getDataSource() {
          return dataSource;
       }*/
    }
    
  2. 实体类

    package com.gdsdxy.bean;
    //公有类
    public class Student {
    	//私有属性
    	private String sname;
    	private String age;
    	private String course;
    	public Student() {
    		super();
    		// TODO Auto-generated constructor stub
    	}
    	public String getSname() {
    		return sname;
    	}
    	public void setSname(String sname) {
    		this.sname = sname;
    	}
    	public String getAge() {
    		return age;
    	}
    	public void setAge(String age) {
    		this.age = age;
    	}
    	public String getCourse() {
    		return course;
    	}
    	public void setCourse(String course) {
    		this.course = course;
    	}
    }
    
  3. 测试
    记得开启事务 C3P0Utils.startTransaction();

    ​ 默认为自动提交

    package com.gdsdxy;
    import java.sql.Connection;
    import java.sql.SQLException;
    import org.apache.commons.dbutils.QueryRunner;
    import com.gdsdxy.utils.C3P0Utils;
    public class TestPayment {
        public static void main(String[] args) {
          Connection conn = null;
          try {
             //开启事务
             C3P0Utils.startTransaction();
             conn = C3P0Utils.getConnection();
             QueryRunner queryRunner = new QueryRunner();
             //lilei的账户减去100元
             String sql1 = "update account set money = money-? where aname=?";
             queryRunner.update(conn, sql1, new Object[]{100,"lilei"});
             //shop的账户增加100元
             String sql2 = "update account set money = money+? where aname=?";
             queryRunner.update(conn, sql2, new Object[]{100,"shop"});
             //提交事务
             conn.commit();
             System.out.println("支付完毕");
          } catch (Exception e) {
             //如果有异常,回滚事务
             try {
                conn.rollback();
                System.out.println("支付失败");
             } catch (SQLException e1) {
                e1.printStackTrace();
             }
          } finally{
             //释放资源
             C3P0Utils.close();
          }
       }
    }
    
posted @ 2022-05-13 21:20  就叫树莓吧。  阅读(88)  评论(0)    收藏  举报