发表于: 2018-04-06 21:35:59
1 835
今天完成的事情:
1.继续完善学习数据库的连接(jdbc sql);
2.使用c3p0(单独使用类创建);
3.测试不关闭连接池,在main函数里循环调用1000次会出现什么情况;
4.测试db中断后的异常抓取。
1.学习更多的查询方法和其它增删改等
jdbc查询集合,总数,orderby dese等,这里就不写了
2.使用类创建数据连接池:
(可以直接使用xml文件,这里没有新建xml,直接使用的c3p0.properties.这样就需要一个一个get属性)
package mybatis.service;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
@Service
public class C3p0_Conn {
private static ComboPooledDataSource dataSource = null;
private static Properties properties = null;
// private static C3p0_Conn c3p0_conn;
static {
// c3p0_conn = new C3p0_Conn();
dataSource = new ComboPooledDataSource();
properties = new Properties();
try {
// properties.load(new FileInputStream("c3p0.properties"));
properties.load(C3p0_Conn.class.getClassLoader().getResourceAsStream("c3p0.properties"));
// System.out.print("\n\n===================\n" + properties.getProperty("driverClass") + "\n===================\n\n");
dataSource.setDriverClass(properties.getProperty("driverClass"));
dataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
dataSource.setUser(properties.getProperty("user"));
dataSource.setPassword(properties.getProperty("password"));
dataSource.setMaxPoolSize(Integer.parseInt(properties.getProperty("max_size")));
dataSource.setMinPoolSize(Integer.parseInt(properties.getProperty("min_size")));
dataSource.setInitialPoolSize(Integer.parseInt(properties.getProperty("initialPoolSize")));
dataSource.setMaxStatements(Integer.parseInt(properties.getProperty("max_statements")));
dataSource.setMaxIdleTime(Integer.parseInt(properties.getProperty("maxIdleTime")));
}catch (Exception e){
e.fillInStackTrace();
throw new ExceptionInInitializerError(e);
}
}
public Connection getConn(){
Connection conn = null;
try {
conn = dataSource.getConnection();
}catch (Exception e){
e.fillInStackTrace();
}
return conn;
}
public void closeConn(Connection conn){
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.不关闭连接池的情况下,在main函数里写1000次循环调用:
先测试循环‘关闭/连接’连接池5次:
public static void main(String[] args){
String sql = "select name from jnshu_user where id = ?";
C3p0_Conn c3p0_conn = new C3p0_Conn();
Connection conn = null;
PreparedStatement pstmt = null;
for (int i=0;i<5;i++){
try {
conn = c3p0_conn.getConn();
// System.out.print("\n测试 ==" + sql + "==测试\n");
pstmt = conn.prepareStatement(sql);
// pstmt = (PreparedStatement) c3p0_conn.getConn().prepareStatement(sql);
pstmt.setInt(1,i);
ResultSet resultSet = pstmt.executeQuery();
while (resultSet.next()){
logger.info("\n第" + (i+1) + "次查询,名字为:" + resultSet.getString("name") + "\n");
}
pstmt.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
logger.debug("\n查询数据库异常\n");
}finally {
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
循环‘关闭/连接’数据库,查询1000次(重复连接):
然后保持连接池连接再次测试:
第六次就结束了:
log调试信息:
[DEBUG] 2018-04-07 01:11:09,862 method:com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$DebugLogger.log(Slf4jMLog.java:204)
acquire test -- pool size: 6; target_pool_size: 7; desired target? 7
[DEBUG] 2018-04-07 01:11:09,862 method:com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$DebugLogger.log(Slf4jMLog.java:204)
获取测试——池大小:6
[DEBUG] 2018-04-07 01:14:54,771 method:com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$DebugLogger.log(Slf4jMLog.java:204)
acquire test -- pool is already maxed out. [managed: 10; max: 10]
[DEBUG] 2018-04-07 01:14:54,772 method:com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$DebugLogger.log(Slf4jMLog.java:204)
提示“池已经刷爆了……”
然后就是等待,控制台一会儿开始输出:
[DEBUG] 2018-04-07 01:17:07,825 method:com.mchange.v2.log.slf4j.Slf4jMLog$Slf4jMLogger$DebugLogger.log(Slf4jMLog.java:204)
BEGIN check for expired resources. [com.mchange.v2.resourcepool.BasicResourcePool@5a61f5df]
检查过期资源……
这是测试的配置,其余都是默认
#初始化获得的连接
initialPoolSize = 100
#最大连接数
max_size = 10
#最大的PreparedStatement的数量
max_statements = 10
#最小连接数
min_size = 1
#当连接池中的连接耗尽的时候c3p0一次同时获取的连接数
acquireIncrement = 10
#定义在从数据库获取新连接失败后重复尝试的次数
acquireRetryAttempts = 10
#检查连接池里空闲连接的间隔 秒
idleConnectionTestPeriod = 60
#最大空闲时间,N秒内未使用则连接被丢弃。若为0则永不丢弃
maxIdleTime = 60
#两次连接间隔时间 毫秒
acquireRetryDelay = 1000
#连接关闭是否将未提交操作回滚 默认false
autoCommitOnClose = false
连接池已经满了
如果不关闭连接池的话,连接满了,就只能等待连接断掉再继续获取新的连接。就是相当于把连接池的连接拿出来,然后不归还,连接池就爆满了,然后就没办法继续获取连接了。
修改最大连接数
#初始化获得的连接
initialPoolSize = 100
#最大连接数
max_size = 500
#最大的PreparedStatement的数量
max_statements = 10
#最小连接数
min_size = 1
#当连接池中的连接耗尽的时候c3p0一次同时获取的连接数
acquireIncrement = 50
然后第142次的时候开始报错:
提示:
acquire test -- pool size: 142; target_pool_size: 142; desired target? 143
获取测试——池大小:142;target_pool_size:142;期望的目标?143
An exception occurred while acquiring a poolable resource. Will retry.
在获取可配置资源时发生了异常。将重试。
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
数据源拒绝建立连接,来自服务器的消息:“太多连接,超过最大连接数”
重新关闭连接池,加大连接数,循环使用2s8ms。之前是40s
4.db断开连接后的异常抓取:
测试错误,错误代码行 resultSet为空集:
try {
conn = c3p0_conn.getConn();
// System.out.print("\n测试 ==" + sql + "==测试\n");
pstmt = conn.prepareStatement(sql);
// pstmt = (PreparedStatement) c3p0_conn.getConn().prepareStatement(sql);
pstmt.setInt(1,i);
ResultSet resultSet = pstmt.executeQuery();
while (resultSet.next()){
logger.info("\n第" + (i+1) + "次查询,名字为:" + resultSet.getString("name") + "\n");
}
pstmt.close();
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
logger.debug("\n查询数据库异常\n");
}finally {
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
异常抓取(截图时使用的System.out.print输出):
断开数据库异常:
@Test
public void testDBClose(){
Connection connection = null;
PreparedStatement pstmt = null;
PreparedStatement pstmt2= null;
ResultSet resultSet = null;
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://119.29.17.188/jnshu";
String user = "root";
String password = "root";
String sql = "insert into person (name,age,sex,pro) values (?,?,?,?)";
String sqlselect = "select * from person ";
try {
Class.forName(driver);
connection = DriverManager.getConnection(url,user,password);
pstmt = connection.prepareStatement(sql);
pstmt2=connection.prepareStatement(sqlselect);
for(int i=0;i<5;i++){
User us1 = new User();
us1.setName( i + "师兄");
us1.setAge(i);
us1.setSex(1);
us1.setPro((i+1) + "师兄");
pstmt.setString(1,us1.getName());
pstmt.setInt(2,us1.getAge());
pstmt.setInt(3,us1.getSex());
pstmt.setString(4,us1.getPro());
logger.info(String.valueOf(pstmt.executeUpdate()));
resultSet = pstmt2.executeQuery();
while (resultSet.next()){
logger.info("\n" + resultSet.getString("name") + "\n");
}System.out.print("\n=====================\n");
if (i==3){
connection.close();
}
}
if (connection != null){
connection.close();
}
pstmt.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
System.err.print("\n数据库断开连接\n");
e.printStackTrace();
}
}
异常提示:
关于插入百万数据:
这是之前插入的数据,今天查的一共409万2911条,未加索引,执行了大半天。嗯……不到一天。如果执行的时候还要继续加索引,时间会更长。但是相对的查询时间会更少。
明天计划的事情:
1.继续学习java基础和SQL语句
2.测试索引相关
3.配置日志问题,看能不能只输出重要的需要的信息
遇到的问题和收获:
1.prepareStatement的Updata方法和Query方法返回值的问题,ResultSet集合为空。
解决:正常使用就行了……
2.properties.load(C3p0_Conn.class.getClassLoader().getResourceAsStream("c3p0.properties"));
读取文件的问题,配置文件
解决:添加C3p0_Conn.class.getClassLoader() 或者使用xml在同级目录下配置
3.数据池的连接问题(c3p0一些属性)
4.查询返回值,同1
5.异常的处理 try/catch/throw/throws
评论