关于一天的学习c3p0(bug)的收获

在GitHub上找了download了一个学生成绩管理系统的javaweb项目作为学习借鉴使用。原作者用到了c3p0技术,于是我就去网上找了一些博客准备自己配一配。首先是配置问题。

我用的是mysql8.0,在配置上和8.0以下的有些区别。我将先后贴出两者的配置方法,然后总结区别所在。

本文介绍以下三点(全部读完费时大概半小时,大家可根据需要读)

1、什么是数据库连接池以及为什么用数据库连接池

2、怎么使用连接池

3、在使用c3p0时遇到的沙雕错误(使用一定要注意的点)

1、首先,什么是数据库连接池以及为什么用数据库连接池(c3p0是数据库连接池技术的一种)

一般我们在项目中操作数据库时,都是每次需要操作数据库就建立一个连接,操作完成后释放连接。因为jdbc没有保持连接的能力,一旦超过一定时间没有使用(大约几百毫秒),连接就会被自动释放掉。而每次新建连接都需要140毫秒左右的时间,所以耗费时间比较多。若使用C3P0连接池来池化连接,随时取用,则平均每次取用只需要10-20毫秒。这在高并发随机访问数据库的时候对效率的提升有很大帮助。

这项技术能明显提高对数据库操作的性能。

2、怎么使用连接池

数据库连接池只改变获取数据库连接的方式,mysql增删查改的操作不变。下面讲讲使用c3p0获取数据库连接的三步

1、导入必须的三个jar包

扫描二维码关注公众号,回复: 8817783 查看本文章

(怎么导请另行搜索) (以下版本为我测试可用的版本)

怎么下载到需要的jar包可看我的另一篇文章(/xyx 还没写,后面推出)

(1)c3p0-0.9.5.2   (c3p0的jar包)

(2)mysql-connector-java-8.0.11  (jdbc驱动包)

(3)mchange-commons-java-0.2.11 (缺少这个包会报错)

2、在src目录下新建一个xml文件  c3p0-config.xml 

注意,必须是这个文件名(因为c3p0的代码实现中默认指定了读取该路径下的该名字的文件,使用其他路径或其他名字,都会出现找不到文件的错误)。

3、将c3p0-config.xml 的文件内容换成如下代码

mysql 8.0以下版本用这个

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>    
    <default-config>    
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>    <!-- jdbc协议地址 -->
            <property name="driverClass">com.mysql.jdbc.Driver</property>             <!-- 驱动 -->
            <property name="user">root</property>                                     <!-- 数据库的用户名  -->
            <property name="password"></property>                                     <!-- 数据库密码 ,若没有密码,该项可省略 -->     
    </default-config>    
</c3p0-config>

mysql 8.0及以上用这个

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--连接池名字-->
    <default-config>    
        <!--数据路连接用户名-->
        <property name="jdbc.user">root</property>
        <!--数据库密码-->
        <property name="password">hy981201</property>
        <!--数据库驱动-->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!--数据库URL-->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/ssms?characterEncoding=UTF-8</property>
    </default-config>    
</c3p0-config>

其中,以下几个property为最基本的(必须在文件中写),其他的可不写(会采用默认配置)

对比8.0分界的两个不同的配置文件可知,改变主要在driverClassjdbcUrl上,大家根据自己的mysql版本配置就行了

----------------------------------------------以下为基于c3p0编写的DBUtil工具类和测试--------------------------------------------

编写DBUtil类和某个测试类(这里我用UserDao类,实现对User对应表的增删查改)

DBUtil.java

package c3p0;

import java.sql.ResultSet;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.PreparedStatement;
import java.sql.Connection;

public class DBUtil {
	private static ComboPooledDataSource comboPooledDataSource = null;
	// 数据库连接池初始化(只做一次)
	static {
		// 读取c3p0的xml配置文件创建数据源,c3p0的xml配置文件c3p0-config.xml必须放在src目录下
        //默认会找 xml 中的 default-config 分支
		comboPooledDataSource = new ComboPooledDataSource();
	}

	/**
	 * 从数据源中获取数据库的连接
	 * @return Connection
	 */
	public static Connection getConnection() {
		try {
			return comboPooledDataSource.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("连接异常");
			return null;
		}
	}

	/**
	 * 释放资源,将数据库连接还给数据库连接池
	 * @param conn
	 * @param ps
	 * @param rs
	 */
	public static void closeDB(ResultSet rs, PreparedStatement ps,Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (ps != null) {
					ps.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					if (conn != null) {
						conn.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void closeDB(PreparedStatement ps, Connection conn) {
		try {
			if (ps != null) {
				ps.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void closeDB(Connection conn) {
		try {
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

UserDao.java(建议自己编写)

package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;

import util.DBUtil;


public class UserDao {
	public static void main(String[] args) {
		String id = "201750080317";
		String pwd = "981201";
//		new UserDao().add(id,pwd);
//		new UserDao().modify(id, pwd);
		new UserDao().remove(id);
//		new UserDao().find(id);
		System.out.println("操作成功");
	}
	
	/**
	 * 在数据库中加入一个记录
	 * @param id
	 * @param pwd
	 * @throws SQLException
	 */
	public void add(String id,String pwd){
		//数据库连接
		Connection conn = DBUtil.getConnection();
//		System.out.println("debug3");

		//准备要执行的sql语句
		String sql = "INSERT INTO `成员口令` (`账号`, `成员密码`) VALUES (?,?)";
		//获取sql语句的执行器对象
		PreparedStatement pstm;
		try {
			pstm = conn.prepareStatement(sql);
			//设置参数
			pstm.setString(1, id);
			pstm.setString(2, pwd);
			//执行sql语句
			pstm.executeUpdate();
			//释放
			DBUtil.closeDB(pstm,conn);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void modify(String id,String pwd){
		//数据库连接
		Connection conn = DBUtil.getConnection();
		//准备要执行的sql语句
		String sql = "UPDATE `成员口令` SET `成员密码`=? WHERE (`账号`=?)";
		//获取sql语句的执行器对象
		PreparedStatement pstm;
		try {
			pstm = conn.prepareStatement(sql);
			//设置参数
			pstm.setString(1, pwd);
			pstm.setString(2, id);
			//执行sql语句
			pstm.executeUpdate();
			//释放
			DBUtil.closeDB(pstm,conn);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public void remove(String id){
		//数据库连接
		Connection conn = DBUtil.getConnection();
		//准备要执行的sql语句
		String sql = "DELETE FROM `成员口令` WHERE (`账号`=?)";
		//获取sql语句的执行器对象
		PreparedStatement pstm;
		try {
			pstm = conn.prepareStatement(sql);
			//设置参数
			pstm.setString(1, id);
			//执行sql语句
			pstm.executeUpdate();
			//释放
			DBUtil.closeDB(pstm,conn);
		} catch (SQLException e) {
			e.printStackTrace();
		}		
	}
	
	public List<String> find(String id){
		List<String> pwds = new LinkedList<String>();
		//数据库连接
		Connection conn = DBUtil.getConnection();
		//准备要执行的sql语句
		//一定注意sql语句不要出一点点错
		String sql = "SELECT * FROM `成员口令` WHERE (`账号` = ?)";
		//获取sql语句的执行器对象
		PreparedStatement pstm;
		try {
			String t;
			pstm = conn.prepareStatement(sql);
			pstm.setString(1, id);
			ResultSet rs = pstm.executeQuery();
			while(rs.next()){
				t = rs.getString(2);
				System.out.println(t);
				pwds.add(t);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return pwds;	
	}
}

User对应的表

--------------------------------------------------工具类和测试结束--------------------------------------------------------------------------------

3、在使用c3p0时遇到的沙雕错误(使用一定要注意的点)

1、c3p0-config.xml文件一定放在src根目录下,否则会找不到

2、c3p0-config.xml中,字母该小写的一定小写,c3p0的’0‘是数字0,不是字母O,不按这个名字写会找不到

3、c3p0-config.xml中的配置文件一定不能有一点点的错误,否则数据库连接会出现异常

(我在配置的时候就把driver打成了drive,再加上我错误的着错误方法,在正确拼写这个问题上卡了一天)

同时,推荐一种弱智查错方式:以前c语言老师告诉我debug从最上面的error找起,从今天起,我将告诉我自己,debug从最上面的warn找起,一个warn可能就会使项目异常,然后整个项目跑不起来。

4、在一天的debug途中,有文章提到上面导入的jar包版本不对,出现找不到驱动的错误。我推荐的三个版本的jar包经过我的测试,没有问题,如果是出现找不到的jar包的错误,可以尝试换成我推荐的版本的jar包试试。

发布了43 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Hitmi_/article/details/93403586