数据库概述 5-连接池

内容介绍


1 preparedStatement 预编译对象

2 数据库的连接池

3 动态代理

模拟用户登录功能

需求:
	我们在控制台输入用户名和密码,输入完用户名和密码后,获取输入的值,使用jdbc操作数据库,完成登录功能.
    找到了:登录成功   找不到:用户名或密码错误  
技术分析:
	jdbc
代码实现:
创建用户表:
    create table user (
      id int primary key auto_increment,
      name varchar(20),
      password varchar(20)
  );
  insert into user values(null,"tom","tom"),(null,"rose","rose"),(null,"jerry","jerry");

Statement编译对象:拼接什么样的sql就执行什么样的sql语句

问题:使用Statement对象来操作sql语句会有缺陷:会造成数据的安全隐患

比如登录中的sql拼接:select * from user where username=‘jack’ #’ and password=‘123’;

相当于注释掉了密码的校验,这种安全隐患我们称为:Sql注入

Sql注入:将用户输入的内容作为了sql语句的一部分 改变了原有sql语句的意义

解决:就不能使用当前的Statement对象来操作SQL语句了,得使用另一个对象–preparedStatement对象

PreparedStatement: 预编译对象

作用:也是用来执行sql语句的

语句执行者:Statement编译对象 preparedStatement预编译对象

区别:

Statement编译对象是有什么样的sql就执行什么样的sql语句,每次执行任何一条sql语句都得先让数据库去编译 其后才执行 如果执行一万条同样的查询语句 数据库要编译一万次 效率低

preparedStatement预编译对象是先将sql传递给数据库做预编译 其后拿着预编译结果传递参数执行sql,执行一万条同样的查询语句 数据库只编译一次 根据不同的参数做不用的执行

预编译的好处:

1 sql语法格式只需要编译一次,效率高

2 能让数据库提前知晓要执行的sql语句格式,只负责给数据库传参即可

语法格式:

Statement编译对象: select * from 表 where 字段1=值1 and 字段2=值2;

preparedStatement:select * from 表 where 字段1=? and 字段2=?;

?:占位符 所有的实际参数都用占位符替换了 不在是直接设值了
通过外部方法来设置实际参数的值:set字段类型(占位符的序号,要设置的值);
占位符的序号是从1开始的 
setString(1,'jack');
setString(2,'abcd/1234');

preparedStatement对象操作数据库的增删改查

使用步骤:

1.编写sql
String sql = "insert into user values(null,?,?..) ";
2.创建预编译对象–提前编译sql语句
​ PreparedStatement pst = conn.preparedStatement(sql);
3.设置具体的参数
​ pst.set字段类型(int a,值);
​ a: 第几个 ? (占位符) 默认从左向右第1个开始
4.执行sql即可
​ ResultSet rs = pst.executeQuery(); // 执行查询,返回 resultSet
​ int i = pst.executeUpdate(); // 执行 增 删 改 返回的是影响的行数

数据库连接池

概述

连接池:存放数据库连接的容器(集合)

连接池出现的目的

之前在使用jdbc操作数据库数据的时候,有一个步骤是获取连接(创建连接)
连接用完,还需要释放连接(销毁连接),这2个步骤太消耗资源了
创建连接=0.1
销毁连接=0.1
10000000*0.2=2000000
目标:想将获取连接和释放资源的这个时长缩短

用来优化jdbc的2个步骤的

1 优化的是jdbc的创建连接部分
2 优化的是jdbc的销毁连接部分

优化原理

在连接池一初始话的时候,就在容器中创建一定量的连接
当用户要连数据库的时候,就从容器中拿一个连接使用
使用完毕之后,不再是销毁,而是把使用后的连接还放回容器 供下一个用户去循环使用

ps:

在企业中使用的都是已经成熟并且性能很高的提供好的连接池:c3p0和druid(学习重点)

只要是直接研发连接池或者是别人研发连接池都需要先实现java提供的规则—DataSource接口

不论是哪个连接池都统一会有DataSource接口下的所有方法:

获取连接的方法(从连接池中获取): 连接池对象.getConnection() 
释放连接的方法(将连接归还给连接池): close() 
				只要当前要释放的连接是从连接池中拿的,当调用这个方法的时候是归还
				如果当前的要释放的连接不是从连接池中拿的,当调用这个方法的时候是销毁

实例:

// 语句执行者的演示:preparedStatement
public class Demo1 {

    @Test
    public void test1() throws Exception {
        // 到包
        // 加载驱动
        // 获取连接  (已经提前写好了JDBCUtils工具类)
        Connection connection = JDBCUtils.getConnection();
        // 获取语句执行者--preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement("select * from USER where name=? and password=?");
        // 设置值
        preparedStatement.setString(1,"jack");
        preparedStatement.setString(2,"111");
        // 执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
            int id = resultSet.getInt("id");
            System.out.println(id);
        }

        // 释放资源
        JDBCUtils.closeZY(resultSet,preparedStatement,connection);
    }

    @Test
    public void test2() throws Exception {

        Connection connection = JDBCUtils.getConnection();
        //String sql="insert into user values(null,?,?)";
        //String sql="delete from user where id=?";
        String sql="update user set name=? where id=?";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1,"jacks");
        preparedStatement.setInt(2,9);
        preparedStatement.executeUpdate();
        JDBCUtils.closeZY(null,preparedStatement,connection);


    }

}

 public class JDBCUtils {
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static  Connection getConnection() throws  SQLException {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db2", "root", "root");
        return connection;

    }

    public static void closeZY(ResultSet rs, Statement st, Connection con) {
        try {
            if(rs!=null){
                rs.close();
            }

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

        try {
            if(st!=null){
                st.close();
            }

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

        try {
            if(con!=null){
                con.close();
            }

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

    }

}

c3p0连接池的使用

硬编码方式(必须要写代码实现的方式)

配置文件方式(掌握)

硬编码方式开发步骤:
		 1 导包 c3p0-0.9.1.2.jar
		 2 创建连接池
		 3 告诉连接池要连接的数据库信息
		 4 (可选)连接池的参数配置
		 5 获取连接
public class Demo1 {


    public static void main(String[] args) throws Exception {
            // 1 导入c3p0的jar包
            // 2 创建连接池对象
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            // 了解: 连接池的配置
            comboPooledDataSource.setInitialPoolSize(10);  // 设置初始化连接池的数量
            comboPooledDataSource.setMaxPoolSize(20); //可以允许多少人访问数据
            comboPooledDataSource.setCheckoutTimeout(10000); //设置等待连接时间
            comboPooledDataSource.setMaxIdleTime(1000*60); //设置空闲时间回收连接池的连接
           // 3 告诉连接池要连那个数据库
        comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); // 告知使用那个数据库
        comboPooledDataSource.setJdbcUrl("jdbc:mysql:///db4"); // 告知数据库的位置
        comboPooledDataSource.setUser("root"); //告知数据库的用户名
        comboPooledDataSource.setPassword("root"); 告知数据库的密码
          // 4 从连接池中获取连接
        Connection connection = comboPooledDataSource.getConnection();

         // 操作数据库
        PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
            int id = resultSet.getInt("id");
            System.out.println(id);
        }

        //释放资源
        /*resultSet.close();
        preparedStatement.close();
        connection.close(); // 会将c3p0获取的连接归还给连接池*/

        JDBCUtils.closeZY(resultSet,preparedStatement,connection);


    }
}

配置文件方式(掌握)企业开发中我们配置文件会使用2种:.properties key=value .xml 层级关系
1 导包 c3p0-0.9.1.2.jar
2 在src下放一个配置文件
这个配置文件如果是xml的话,必须叫c3p0-config.xml 必须放在src下
这个配置文件如果是properties的话,必须叫c3p0.properties 必须放在src下
3 创建连接池获取连接
好处:只要连接池一创建 底层会自动去src下加载名字叫c3p0-config.xml或c3p0.properties文件
4 代码实现
1:创建c3p0的连接池: DataSource ds=new CombopooledDataSource()
使用配置文件默认的
DataSource ds=new CombopooledDataSource(“name名称”) 使用配置文件中带名称的
2:从连接池中获取连接: Connection con=ds.getConnection()
3:拿着连接去操作数据库: 略
4:归还连接给连接池: con.close()

// c3p0的配置文件方式
public class Demo2 {

    public static void main(String[] args) throws SQLException {
        // 1 导包
        // 2 在src下放入指定名称的配置文件
        // 3 创建连接池
        // 会自动去src下找指定名称的配置文件加载数据
        //ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource("mysql");
        // 获取连接
        Connection connection = comboPooledDataSource.getConnection();
        // 操作数据库
        PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()){
            int id = resultSet.getInt("id");
            System.out.println(id);
        }
        // 释放资源
        JDBCUtils.closeZY(resultSet,preparedStatement,connection);
    }
}

druid连接池的使用

配置文件方式(掌握)
1 导入1个jar包
druid-1.0.9.jar
2 存放配置文件
没有要求,可以是任何名称任何位置的properties文件即可(建议放入src下面)
原因:因为不会自动帮你去加载配置文件,需要自己手动去加载配置文件
3 代码实现
1:创建properties对象加载配置文件
InputStream is=类名.class.getClassLoad.getResourceAsStream();
Properties properties= new Properties();
properties.load(is);
2: 创建druid的连接池
DataSource ds=DruidDataSourceFactory.createDataSource(properties对象)
3: 获取连接
Connection con=ds.getConnection()
4: 拿着连接去操作数据库: 略
5:归还连接给连接池: con.close()

public class Demo {
        public static void main(String[] args) throws Exception {
            // 配置文件方式
            // 1 导入druid包
            // 2 在src下有一个数据库的配置信息文件  此文件可以为任意名称
            // 3 创建druid的连接  由derid的工厂生产出来的
            Properties properties = new Properties();
            // 目标:将src下druid.properties资源文件转换成流  jdK:类加载器
            // 怎么获取到类加载  每个类的字节码文件对象有个方法可以获取类加载器
            /*Class clazz=Demo.class;
            ClassLoader classLoader = clazz.getClassLoader();
            InputStream is = classLoader.getResourceAsStream("druid.properties");*/
    
            // 将src指定资源转换成流
            InputStream is = Demo.class.getClassLoader().getResourceAsStream("druid.properties");
            properties.load(is);
            DataSource ds = DruidDataSourceFactory.createDataSource(properties);
            // 4 从druid中获取连接
            Connection connection = ds.getConnection();
            // 5 操作数据库
            PreparedStatement preparedStatement = connection.prepareStatement("select * from user");
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                System.out.println(id);
            }
            // 6 释放资源
            JDBCUtils.closeZY(resultSet,preparedStatement,connection);
        }
    
    
        @Test
        public  void save() throws Exception {
    
            Connection connection = JDBCUtils.getConnection();  //创建连接 == 从连接池中获取连接
    
            // 获取preparedStatement操作数据库
            String sql="insert into user values(null,?,?)";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"bbb");
            preparedStatement.setString(2,"666");
            preparedStatement.executeUpdate();
    
    
            JDBCUtils.closeZY(null,preparedStatement,connection); // 归还
    
        }
    }

自定义工具类(jdbcUtils)的增强

1 定义一个连接池(c3p0或druid)
2 提供获取连接的方法 (连接得是从连接池中拿的)
3 提供一个获取连接池的方法(直接返回连接池)--->jdbcTemplate工具类要用
4 提供释放资源的方法
// jdbc的工具类
        public class JDBCUtils {
        
            private static DataSource dataSource=null;
        static {
            try {
                Properties properties = new Properties();
                InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
                properties.load(is);
                dataSource = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 获取连接
        public static Connection getConnection() throws Exception {
            // 从连接池中获取连接
            Connection connection = dataSource.getConnection();
            return  connection; // 来源于连接池
        }
    
    
        // 释放资源
        public static void closeZY(ResultSet rs, Statement statement, Connection connection){
    
            // 关闭resultSet
            try {
                if(rs!=null){
                    rs.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
            // 关闭statement
            try {
                if(statement!=null){
                    statement.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
            // 关闭connection
            try {
                if(connection!=null){
                    connection.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
    
    
        }
    
    }

动态代理

作用:用来增强一个对象的方法 (框架的底层用了很多的动态代理来增强方法业务)

代理的概念:
	   代理对象:增强对象
	   被代理对象:要被增强的对象

要使用jdk提供的动态代理增强一个对象的方法有条件:
必须得知道要被代理的对象是谁 被代理的对象必须得有接口
java:面向接口 先有接口后有类

使用jdk提供的动态代理:什么包都不用导 都提供好了

jdk提供工具API: newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 	             会返回一个指定接口下的代理类的代理对象
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值