4、数据库连接池

数据库连接池

  • 连接池的相关概念
  • c3p0连接池
  • Druid连接池
  • jdbcTemplate

一、连接池的相关概念

1.1、什么是连接池?

  一个存放数据库连接对象的容器(集合),每次程序需要访问数据库时,就会来连接池拿走一个连接对象,用完再“归还”。用于节约资源,提高程序的效率。

1.2、连接池的作用

  在不使用连接池的情况下,每当程序需要访问数据库,都必须先创建连接对象,当访问完成以后,为了避免内存溢出,所以又得将连接对象销毁(conn.close()),当访问量比较大大时,这种方式会给CPU造成极大的压力。
  解决思路:创建几个静态连接对象,由这几个连接对象交替去访问数据库。避免了频繁的创建、销毁连接对象操作。
  连接池的本质:就是一个预先存放了一些连接对象的容器(集合),每当程序需要访问数据库时,就会从容器中拿走一个连接对象,用完以后又还回来,避免了频繁的创建、销毁连接对象的操作,大大提高了程序的效率。

1.3、来由

  Java官方很清楚连接池的重要性,所以向外提供了一个接口(javax.sql.DataSource)方便程序员在项目中引入、使用连接池 。
  连接池的实现原理并不复杂,所以有很多的厂商、技术大佬开发了各种连接池,常用的连接池有C3P0、Druid。一个由MySQL官方提供,一个由阿里巴巴开发的。没个连接池内部都处理了Connection的colse()方法,使其不会释放连接池对象,而是归还连接池对象。
  javax.sql.DataSource接口中的方法:getConnection():获取数据库连接对象,每一个连接池都必须实现这个方法。

二、c3p0连接池

  C3P0是一个开源的jdbc连接池,由MySQL官方提供,用的人还是蛮多的。它实现了数据源和jndi绑定,支持jdbc3规范和jdbc2的标准扩展。c3p0是异步操作的,缓慢的jdbc操作通过帮助进程完成。扩展这些操作可以有效的提升性能。目前使用它的开源项目有Hibernate,Spring等。c3p0有自动回收空闲连接功能。

2.1、配置文件说明

  总共由两种配置文件,c3p0-config.xml和c3p0.properties。因为xml用的比较多,所以这里只讨论第一种。
  xml配置文件必须放到src目录下,文件名最好不要改,要改的话也不能用底杠,只能用中杠。

<?xml version="1.0" encoding="UTF-8"?><!--version:版本号   encoding:字符编码-->
<c3p0-config>
    <!--默认的连接池-->
    <default-config>
        <!--数据库连接参数-->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&amp;characterEncoding=utf-8</property>
        <property name="user">root</property>
        <property name="password">duanhui0</property>
        <!--连接池参数-->
        <property name="initolPoolSize">5</property><!--初始化连接数-->
        <property name="maxPoolSize">10</property><!--最大连接数-->
        <property name="chockoutTimeout">3000</property><!--等待时间3秒-->
    </default-config>
    
    <!--可选的连接池-->
    <named-config name="linux">
        <!--数据库连接参数-->
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://192.168.198.129:3306/test1</property>
        <property name="user">root</property>
        <property name="password">duanhui0</property>
        <!--连接池参数-->
        <property name="initolPoolSize">5</property><!--初始化连接数-->
        <property name="maxPoolSize">10</property><!--最大连接数-->
        <property name="chockoutTimeout">3000</property><!--等待时间3秒-->
    </named-config>
</c3p0-config>

2.2、使用步骤

  1. 导入两个jar包到项目中:c3p0-0.9.5.2.jar和mchange-commons-java-0.2.11.jar

    记得Add as library

  2. 定义配置文件:src/c3p0-config.xml

  3. 创建核心对象————连接池对象:ComboPooledDataSource

    DataSource ds = new ComboPooledDataSource();
    /**
     * 关于ComboPooledDataSource类,其实有两个构造方法。
     * 无参构造:new ComboPooledDataSource()用于创建默连接池(<default-config>)的对象。
     * 有参构造:new ComboPooledDataSource(String name)用于创建指定连接池的对象,参数决定了具体创建哪个
     * 连接池的对象。比如:new ComboPooledDataSource("linux")就是创建<named-config name="linux">连接池
     * 的连接对象。
     */
    
  4. 获取数据库连接对象:getConnection()

    Connection conn = ds.getConnection();
    
  5. 有了数据库连接对象,就相当于拥有了一整个世界了,就可以拿着这个去各种揉躏数据库了。

  6. 归还数据库连接对象(毕竟连接池中的连接对象也是有限的)

    conn.close();
    

三、Druid连接池

3.1、配置文件说明

  c3p0不同的是,Druid连接池只有一种配置文件:druid.properties

# 数据库连接4要素
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&characterEncoding=utf-8
username=root
password=duanhui0
# 初始化连接数
initialSize=5
# 最大连接数
maxActive=10
# 获取连接时的最大等待时间3秒
maxWait=3000
# 最大连接池数量
maxIdle=8
# 最小连接池数量
minIdle=3

3.2、使用步骤

  1. 将jar包导入到项目中:druid-1.0.9.jar

    记得Add as library

  2. 定义配置文件:druid.properties

  3. 读取配置文件

    Properties pro = new Properties();
    FileInputStream input = new FileInputStream("src/resources/druid.properties");
    pro.load(input);
    input.close();
    
  4. 获取连接池对象:DataSource

    DataSource source = DruidDataSourceFactory.createDataSource(pro);
    
  5. 获取数据库连接对象:getConnection()

    Connection conn = source.getConnection();
    
  6. 有了数据库连接对象,就相当于拥有了一整个世界了,就可以拿着这个去各种揉躏数据库了。

  7. 释放资源

    conn.close();
    

3.3、定义工具类

  1. 定义一个utils类

  2. 提供静态代码块加载配置文件,初始化连接池对象

  3. 对外提供方法:

    • 获取连接池对象:
    • 获取DB连接对象:
    • 释放资源:
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    import javax.sql.DataSource;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    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 JDBCutils {
        //成员变量
        private static DataSource ds;
    
        static{
            //1、加载配置文件
            Properties properties = new Properties();
            try {
                InputStream input = new FileInputStream("src/resources/druid.properties");
                properties.load(input);
                input.close();
                ds = DruidDataSourceFactory.createDataSource(properties);
            } catch (FileNotFoundException e) {
                System.out.println("配置文件路径错误");
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 方法一:获取连接池对象
        public static DataSource getDateSource(){
            return ds;
        }
        //方法二:获取数据库连接对象
        public static Connection getConnection() throws SQLException {
            Connection connection = ds.getConnection();
            return connection;
        }
        //方法三:释放资源
        public static void colse(Statement statement,Connection connection){
            colse(null,statement,connection);
        }
        //重载方法三
        public static void colse(ResultSet result,Statement statement, Connection connection){
            if (result != null){
                try {
                    result.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
  4. 编写测试类进行测试

    @Test
    public void test(){
    	Connection conn = null;
    	PreparedStatement pps = null;
    	try {
                conn = JDBCutils.getConnection();
                String sql = "insert into test1 values(null,?)";
                pps = conn.prepareStatement(sql);
                pps.setString(1,"testUtil");
                int result = pps.executeUpdate();
                System.out.println(result);
    	} catch (SQLException e) {
                e.printStackTrace();
    	}finally {
                JDBCutils.colse(pps,conn );//释放资源
    	}
    }
    

四、jdbcTemplate

  Spring框架对jdbc进行了简单的封装,并提供了jdbcTemplate对象简化jdbc操作。

4.1、使用步骤

  1. 导入Spring框架相关jar包

    • commons-logging-1.2.jar
    • spring-beans-5.1.10.RELEASE.jar
    • spring-core-5.1.10.RELEASE.jar
    • spring-jdbc-5.1.10.RELEASE.jar
    • spring-tx-5.1.10.RELEASE.jar
  2. 创建jdbcTemplate对象

    jdbcTemplate template = new jdbcTemplate(JDBCutils.getDateSource());//JDBCutils为上面的工具类
    
  3. 编写SQL

    String sql = "insert into test1 values(null,?)";
    
  4. 调用jdbcTemplate的方法执行SQL并返还结果

    1. update():执行DML语句

    2. queryForMap():将结果封装到map集合。查询结果只能有一条记录,key=字段名,value=字段值

    3. queryForList():将结果封装到List集合。将每一条记录封装成一个Map,再将Map保存进List集合。

    4. query():将结果封装成JavaBean对象

    参数:sql, 值1,值2,…,new BeanPropertyRowMapper<javaBean>(javaBean全类名.class)

    返回值:List<JavaBean> list

    1. queryForObject():将查询结果封装成对象,一般用于聚合函数的查询。

    参数:sql4, 值1,值2,…,引用数据类型.class

    返回值:引用数据类型(如:Long、Integer等)

    int count = template.update(sql,"template");//返回值是受影响的行数,“template”用于补全SQL
    

4.2、经典案例

  1. 添加一条记录
  2. 查询该记录,封装为List集合
  3. 修改该记录
  4. 查询该记录,封装为Map集合
  5. 删除该记录
  6. 查询所有的记录,封装为Emp对象的List集合
@Test//测试CRUD
public void test2(){
    //InputStream input ;
    //input = JDBCUtils.class.getClassLoader().getResourceAsStream("resources/druid.properties");
	JdbcTemplate template = new JdbcTemplate(JDBCutils.getDateSource());
	//1、添加一条数据
	String sql1 = "insert into employee values(3,?,?,?)";
	int insert = template.update(sql1,"袁树",21,10000.0);
	System.out.println(insert==1?"添加成功":"执行失败");
	//2、查询id=3的记录,并将查询结果封装到Map集合
	String SQL1 = "select * from employee where id = ?";
	Map<String,Object> map = template.queryForMap(SQL1,3);//只能用于查询一条记录
	System.out.println(map);
	//3、修改一条数据
	String sql2 = "update employee set salary=? where id = 3";
	int update = template.update(sql2,15000);
	System.out.println(update==1?"修改成功":"执行失败");
	//4、查询所有记录,并将查询结果封装到List集合
	String SQL2 = "select * from employee";
	List<Map<String, Object>> list = template.queryForList(SQL2);
	System.out.println(list);
	//5、删除一条数据
	String sql3 = "delete from employee where id = ?";
	int delete = template.update(sql3,3);
	System.out.println(delete==1?"删除成功":"执行失败");
	//6、查询所有记录,
	String SQL3 = "select * from employee";
	List<Employee> list2 = template.query(SQL3, new RowMapper<Employee>() {
		@Override
		public Employee mapRow(ResultSet resultSet, int i) throws SQLException {
		Employee em =  new Employee();
		em.setId(resultSet.getInt("id"));
		em.setName(resultSet.getString("name"));
		em.setAge(resultSet.getInt("age"));
		em.setSalary(resultSet.getDouble("salary"));
		return em;
		}
	});
	System.out.println(list2);
	//7、查询总记录数
	String sql4 = "select count(*) from employee";
	Long count = template.queryForObject(sql4,Long.class);
	System.out.println(count);
}

4.3、surprize

@Test//简化查询结果转Javabean的步骤
public void test3(){
	JdbcTemplate template = new JdbcTemplate(JDBCutils.getDateSource());
	String sql = "select * from employee";
    //一步到位
	List<Employee> list = template.query(sql, new BeanPropertyRowMapper<Employee>(Employee.class));
	System.out.println(list);
}

​ 对于javabean中的类,成员方法不要用基本数据类型,因为基本类型无法接收null,如果数据库中有null值,那么在你接收的时候就很容易bug了。

https://zhidao.baidu.com/question/1387795592417884260.html
关于queryRunner类的方法-参数介绍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值