javaWeb学习第十天------连接池,dbUtil ,c3p0,dbcp,dbcp封装,事物管理,三层架构

连接池

什么是连接池

连接池的厂商创建的jar包

在这里插入图片描述

连接池的作用

管理连接, 避免反复来创建和销毁连接,

没有连接池的时候:
在这里插入图片描述
有连接池的时候:

在这里插入图片描述

连接池的种类

dbcp:

1.连接池的效率最高
2.是tomcat的内置连接池
3.一秒钟最多可以创建于管理1000个连接
4.安全性比较差==> 容易丢失数据 类似socket 的udp协议

c3p0 :

特点 数据不会丢失,安全性比较高,但是效率慢一点

druip

怎么使用连接池

例如:使用dbcp连接池(使用properties配置文件)

1.导入其jar包 并且数据库jar也需要最后添加依赖

在这里插入图片描述
2.获取DataSource 对象

BasicDataSourceFactory.createDataSource(pro);
第一种方式:通过反射来进行操作(配置文件和类在同一个目录,一般的配置文件都会放在src目录文件下)
InputStream rs = Test.class.getResourceAsStream("dbcpconfig.properties");
            Properties pro=new Properties();
            pro.load(rs);
//把properties内的配置加载到内存的流中
//使用读取配置文件的信息设置连接池的部分参数,并且获取数据库连接的信息参数,然后连接数据库,
// 因为连接池是第三方类库,我们要获取数据库连接需要通过 一个叫DataSource的类实现程序员于
// 连接数据库需要的连接对象,而DataSource 是由连接池厂商提供第三方jar包的内部类实现的,
// 是唯一获取数据库连接的对外类或者说对象,并不能直接new出来
// 不同连接池创建数据源的方式不一样,但是要使用连接池,就必须要有数据源(间接),获取连接
//加载的第三方的jar包就是加载的连接池,并且通过commons-dbcp包提供的类读取配置文件并配置了连接池commons-pool,并返回一个DataSource对象给外部使用者获取commons-pool内的连接
DataSource dataSource = BasicDataSourceFactory.createDataSource(pro);
dataSource.getConnection();//通过数据源获取连接
第二种方式:通过流进行读取(配置文件和src平级)
@Test
    public void test(){//使用流加载properties配置获取数据源
        try {
            FileInputStream input=new FileInputStream(new File("src/com/student/test/dbcpconfig.properties"));
            Properties pro=new Properties();
            pro.load(input);
            DataSource dataSource = BasicDataSourceFactory.createDataSource(pro);
            dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

配置文件:dbcpconfig.properties

配置文件的地址: http://commons.apache.org/proper/commons-dbcp/configuration.html

#连接设置 driverClassName不能更改更改后将不能被连接池识别
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/user_db
username=root
password=admin

#<!-- 初始化连接 开始会自动创建10个连接-->
initialSize=10

#最大连接数量连接
maxActive=50

#<!-- 最大空闲连接大于的会清除超出 -->
maxIdle=20

#<!-- 最小空闲连接 不够会自动加到最小值 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

例如使用:C3P0连接池:

1.导入jar
在这里插入图片描述
2.导入数据库的配置信息 (数据库的配置信息放在src下)

  • 文件的名称必须是c3p0-config 前缀
  • 可以是xml 文件 也可以是properties文件
  1. 获取DataSource 对象

    DataSource ds = new ComboPooledDataSource();    ==>c3p0.xml 默认的配置 <default-config>
    
第一种:加载默认配置的方式
public void c3p0Test(){//使用C3P0获取默认xml配置也可以使用properties
        try {//这里使用的是xml配置文件
            DataSource data= new ComboPooledDataSource();
            System.out.println(data.getConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
第二种:加载自定义配置的方式
public void c3p0Test2(){//获取自定义xml配置
        try {
            DataSource data= new ComboPooledDataSource("自定义的名字");
            System.out.println(data.getConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

c3P0的配置文件名:c3p0-config.xml(必须是有这个名,并且放置的位置必须是src目录下,不能放在包内)

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<!-- 默认配置,如果没有指定则使用这个配置 -->
	<default-config>
		<!-- 四项基本配置 -->
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/user_db</property>
		<property name="user">root</property>
		<property name="password">admin</property>
		
		<!-- 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
  			SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
		<property name="checkoutTimeout">30000</property>
		
		<!--隔多少秒检查连接池的空闲连接,0表示不检查-->
		<property name="idleConnectionTestPeriod">30</property>
		
		<!-- 初始化连接数 -->
		<property name="initialPoolSize">10</property>
		
		<!-- 连接的最大空闲时间,默认为0秒、不会关闭任何连接。设置30秒,30秒到期后,
			连接若未使用就会被关闭 -->
		<property name="maxIdleTime">30</property>
		
		<!-- 池中最多的连接存放数目 -->
		<property name="maxPoolSize">100</property>
		
		<!-- 池中最少的连接存放数目 -->
		<property name="minPoolSize">10</property>
                <!-- 池中Statement数目 -->   
		<property name="maxStatements">200</property>
		
	</default-config>
	<!-- 自定义命名的配置 -->
	<named-config name="自定义名字">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/user_db</property>
		<property name="user">root</property>
		<property name="password">admin</property>
                 <!--当连接池中连接都清除后,一次性创建5个连接 -->
		<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>

dbcp工具类的封装

作用:1.只实例化一个对象 ,2.配置文件值加载一次

实现方式:单例设置模式 (1.私有的属性 2.私有的构造 3.公有的对外方法)

public class DbcpUtils {
    //私有的属性
    private static DbcpUtils dbcpUtils;
    private DataSource dataSource;

    //私有的构造
    private DbcpUtils() {
        // 加载配置文件
        try {
            Properties properties  =  new Properties();
            //通过反射来加载配置文件来得到一个inputStream对象
            InputStream is  = DbcpUtils.class.getResourceAsStream("dbcpconfig.properties");
            properties.load(is);
            dataSource = BasicDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //提供对外的方法
     //锁方法保证只有一个线程能够进来
    //双重锁单例设置模式

     public   synchronized   static  DbcpUtils  getInstance(){
        if(dbcpUtils==null){
            // 同步代码块  第一个 保证多线程中只有一个线程访问这个class文件
             synchronized (DbcpUtils.class){
                   if(dbcpUtils ==null){
                       dbcpUtils = new DbcpUtils();
                   }
             }
        }

         return  dbcpUtils;
     }

     //提供连接的方法
    public Connection  getConnection(){
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  null;
    }

}

dbutils

其实就是对jdbc的增删查改的一个封装,简化代码 一般是与c3p0进行搭配

使用步骤:

1.导入相关的jar包

在这里插入图片描述

2.使用其核心的类

QueryRunner QueryRunner  qr  = new QueryRunner(); 

3.常规的方法 update(“sql语句”,“具体的值 ,一般使用object[] object 用来专参”) ,qr.query(sql, new BeanListHandler(User.class),|| “ 具体 的值”(一般使用object[] object 用来专参));
4.查询的接口类:

ResultSetHandler  :实现类

                  new BeanHandler<>() 查询的是单条对象   ==new BeanHandler<User>(User.class)

                new BeanListHandler<User>(User.class) 查询出所有对象

                 new MapHandler() 查询出第一行数据,把第一行数据封装成了一个map对象

                 new MapListHandler() 查询出的表中的数据,都封装成一个map对象 ==>也是一个集合,只是泛型是Map

                new ScalarHandler()查询总记录数 ==>必须用Long 类型来接收

dbutil 中的实体类要求:

  • 必须序列化 :implements Serializable
  • 必须是私有的属性 set get 方法
  • 必须给一个无参构造

dbUtil 和C3p0的结合使用:

插入一条数据:

 @Test
    public void insertUtilTest() {
        try {
            DataSource da = new ComboPooledDataSource();//使用c3p0获取数据源
            QueryRunner qr = new QueryRunner(da);//数据源对象存在了它的父类叫AbstractQueryRunner的一个final修饰的静态方法变量中作为参数
            //增删改都是这个方法
            String sql = "insert into user(uname,upwd) values(?,?)";
            Object[] objects = {"15", "16"};
            int unm = qr.update(sql, objects);//分两步,第一步会调用父类的prepareConnection()获取在父类中的数据源然后使用数据源获取连接对象,
            // 第二步然后执行一个重载update方法,这个重载的方法里面包含连接对象和传进来的参数,还有一个判断连接池时候关闭的Boolean
            //这个重载方法在使用完后,调用了close(conn)断开了数据库连接池(注意只是断开了连接)
            if (unm > 0) {
                System.out.println("成功");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

查询一条数据:

 @Test
    public void iselectUtilTest() {

        try {
            DataSource da = new ComboPooledDataSource();
            QueryRunner qr = new QueryRunner(da);
            //查询单条
            String sql = "select * from user where uid=?";//查询单条数据
            User user = qr.query(sql, new BeanHandler<User>(User.class), 6);
            //第二个参数。结合源码和讲解,这个是类似resultset的查询结果集,在resultset集合出现时会自动遍历结果resultset集,
            // 并返回转换为指定的类型数据的对象,作为返回结果,
            // 注:BeanHandler把查询的来ResultSet得能转化成各种类型并遍历,而原生的JDBC是不存在直接转换的,需要遍历resultSet集合
            // 然后把一条记录的数据逐一放入到指定的实体类的对应成员属性中,最后返回转载完的实体类,作为结果返回返回
            //通过对ResultSetHandler不同实现返回不同的结果
            System.out.println(user);
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

查询所有(list)

 @Test
    public void selectTest() {//查询所有
        try {
            DataSource da = new ComboPooledDataSource();
            QueryRunner qr = new QueryRunner(da);
            String sql = "select * from user";//查询的多条数据
            List<User> query = qr.query(sql, new BeanListHandler<User>(User.class));
            //new BeanListHandler<User>(User.class):设置指定,resultSet集遍历,并把里面的每条记录转换为user的list集合作为返回结果
            for (User usr : query) {
                System.out.println(usr);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

查询第一条数据(使用map)

 @Test
    public void selectmapTest() {
        try {
            DataSource da = new ComboPooledDataSource();
            QueryRunner qy = new QueryRunner(da);
            String sql = "select * from user";
            Map<String, Object> firstMap = qy.query(sql, new MapHandler());//只会把第一条数据读取出来,并放入一个人map集合里面
            System.out.println(firstMap.toString());//数据存储形式:键:值。键代表列名,键就是一条数据,对应的的值
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

查询所有(list的map集)

   @Test
    public void selectListMap() {
        try {
            DataSource da = new ComboPooledDataSource();
            QueryRunner qr = new QueryRunner(da);
            String sql = "select * from user";
            List<Map<String, Object>> list = qr.query(sql, new MapListHandler());//会把每一条数据装进一个map集合里面,形成一个list的map集合
            for (Map<String, Object> map : list) {
                for (String str : map.keySet()) {//一个map里面有多个数据
                    System.out.println(str + ":" + map.get(str));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

查询Count记录总数

// 查询出着一张表的总记录数
     @Test
    public  void  selectCount(){
        try {
            DataSource ds  = new ComboPooledDataSource();
            QueryRunner qr  = new QueryRunner(ds);
            String sql ="select count(1) from user";
            Long  count  = (Long) qr.query(sql,new ScalarHandler());
            System.out.println(Integer.parseInt(count+""));
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

事务的使用场景

保证一组sql语句同时执行成功==>c才能确定这次操作合理

例如:转账的过程,要确保两边的修改都成功
,如果有一方没有执行正确的操作,我们可以回退到上一个或者某个操作前的数据,

mysql 数据库中的事物

1.自动提交

2.手动提交

手动提交失败的处理流程

1.设置mysql 数据库为手动提交

set autocommit =0/1 ,1是设置为自动
2. start transaction 开启事物: 执行开始一次就会有一个事物被创建
3.执行sql操作
4.rollback :回滚(在当前事物设置回滚点,可以根据回滚的点回滚到指定的节点)
rollback to 节点名 : 回滚到具体某一步,
savepoint 节点名: 设置回滚点
5.commit 提交

事物处理流程原理图:

如果开启事务:给用户来创建一个临时的文件来保存数据,需要commit的时候才会进行提交(同步到数据库里) rollback 清空临时文件的所有数据

在这里插入图片描述

事务的四大原则(ACID)

原子性: 每一个事务都是最小的原子单位,不能进行再分割==>要么两条sql语句同时执行成功要么同时执行失败
一致性: 数据要么执行前的数据,要么是执行后的数据
隔离性 每一个事务都是相互隔离的,互不影响
持久性 只要commit以后,数据就保存到数据库了

三层架构

  • View层 =>视图 (控制台)
  • Service==>业务逻辑层
  • Dao层 ==>数据库层

在这里插入图片描述
具体项目:

  • 实体类的包 com.student.gjp.entity
  • 数据库的包 com.student.gjp.dao
  • 逻辑的包: com.student.gjp.service
  • 工具包:com.student.gjp.utils
  • 视图包 com.student.gjp.view
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值