第十一天:JDBC 连接池

1.JDBC(JAVA DATA BASE Connection):Java数据库连接

为什么会有JDBC的存在?是一种规范标准

1. 概念:Java DataBase Connectivity  Java 数据库连接, Java语言操作数据库

JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

以前在DOS窗口可视化工具操作数据库,现在想用JAVA程序去操作数据库。


2.使用JDBC操作数据库步骤:

1.导入依赖Jar包

2.注册驱动

Class.forName("com.mysql.jdbc.Driver")

3.获取数据库连接对象

DriverManager.getConnection()

4.通过数据连接对象获取执行sql语句的对象--获取sql语句执行平台

connection.createStatemen()

5.定义sql语句

String sql=" sql语句";

6.执行sql语句

statement.execute(sql);

7.释放连接资源

con.close();

statement.close()

例子:

//使用JDBC操作数据库步骤
        /*
        * 1.导入JDBC的相关Jar包(添加依赖关系)
        * 2.加载驱动(注册驱动)因为操作数据库的具体实现类是Driver类,目的是把Driver类加载进内存,加载字节码文件加载进内存
        * 3.建立连接(获取操作数据库的连接对象)----DriverManager 通过DriverManager.getConnection()
        * 4.通过数据库连接对象获取能够操作数据库的对象(获取能够执行sql语句的对象)--获取执行sql语句平台
        * 5.定义sql语句
        * 6。执行sql语句
        * 7.释放资源
        * */
//        1.导入JDBC的相关Jar包(添加依赖关系)
//        2.(注册驱动)
        Class.forName("com.mysql.jdbc.Driver");
//        3.建立连接(获取操作数据库的连接对象)----DriverManager 通过DriverManager.getConnection()
        Connection con = DriverManager.getConnection("Jdbc:mysql://localhost:3306/db5", "root", "root");
        //4.通过数据库连接对象获取能够操作数据库的对象(获取能够执行sql语句的对象)--获取执行sql语句平台
        Statement statement = con.createStatement();
//        5.定义sql语句
//           添加一条数据
        String sql="INSERT INTO `emp1`(`id`,`NAME`) VALUES(NULL,'王五');";//双引号里面不能放双引号,可以放单引号
//        6.执行sql语句
        statement.execute(sql);

优化之后:

代码:

ArrayList<Stu> stu = getStu();
        for (Stu stu1 : stu) {
            System.out.println(stu1);
        }
    }

    private static ArrayList<Stu> getStu() {
        //把stu对象放到ArrayList集合中去
        ArrayList<Stu> stus = new ArrayList<>();
        Connection con=null;
        Statement stat=null;
        ResultSet resultSet=null;
        try {
//            1.获取数据连接
             con = JDBCUtilDemo1.getConnection();
//            2.获取执行sql语句的平台(对象)
            stat = con.createStatement();
            //3定义sql语句
            String sql="SELECT * FROM stu1;";
            //4.执行sql语句  返回的是结果集 查询数据中的数据返回成一个结果集
        resultSet = stat.executeQuery(sql);
           //判断是否有下一个数据
//            boolean next = resultSet.next(); 当next为true时证明有下一条数据
            //得到下一个数据
            while(resultSet.next()) {
                int id = resultSet.getInt("id");//得到id字段
                String name = resultSet.getString("name");
                System.out.println(id+" "+name);
                //创建对象
                Stu stu = new Stu();
                stu.setId(id);
                stu.setName(name);
                //把对象添加到集合中去
                stus.add(stu);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtilDemo1.close(con,stat,resultSet);
        }
        return stus;
    }

JDBC的工具类:

代码:

public class JDBCUtilDemo1 {
    //提供一个获取连接对象的方法
    public static Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
        return con;
    }

    //关闭资源---有结果集(查询)
    public static  void close(Connection con, Statement stat, ResultSet res) {
        //释放资源
        if(con!=null){
            try {
                con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(stat!=null) {
            try {
                stat.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if(res!=null){
            try {
                res.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
    //关闭资源---没有结果集(增删改)
    public static void close(Connection con, Statement stat) {
        //释放资源
        if (con != null) {
            try {
                con.close();
                con=null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (stat != null) {
            try {
                stat.close();
                stat=null;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

结合实体类使用JDBC:

代码:

public static void main(String[] args) {
        ArrayList<Student> student = getStudent();
        //遍历集合
        for (Student student1 : student) {
            System.out.println(student);
        }
    }

    private static ArrayList<Student> getStudent() {
        ArrayList<Student> students = new ArrayList<>();
        try {
            Connection con = JDBCUtilDemo1.getConnection();
            Statement stat = con.createStatement();
            String sql="SELECT * FROM student WHERE NAME LIKE'%三%';";
            ResultSet resultSet = stat.executeQuery(sql);
            while (resultSet.next()){
                //得到数据表中的每一个字段
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                int math = resultSet.getInt("math");
                int english = resultSet.getInt("english");
                Student student = new Student();
                student.setId(id);
                student.setName(name);
                student.setAge(age);
                student.setMath(math);
                student.setEnglish(english);
                //把对象添加到集合中去
                students.add(student);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return students;
    }


细节:

static:静态的 被这个关键字修饰的会随着类的加载而加载

 

sql注入产生原因:

因为sql语句中存在字符串的拼接,只要给予特定的sql语句,会导致用户名与密码失效,这样的问题我们称之为sql注入

如何解决这个问题?

不使用字符串拼接,而是使用占位符 ? 进行赋值

占位符----占用位置

PreparedStatement:执行sql的对象

1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题

1. 输入用户随便,输入密码:a' or 'a' = 'a

2. sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'

 

2. 解决sql注入问题:使用PreparedStatement对象来解决

3. 预编译的SQL:参数使用?作为占位符

4. 步骤:

1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar

2. 注册驱动

3. 获取数据库连接对象 Connection

4. 定义sql

 

代码如下:

public static void main(String[] args)  {

         /*提供一个用户表  user
         * 登录案列
         *     键盘录入用户名与密码与数据中已存在的用户名与密码进行校验
         *     如果输入的用户名与密码存在,提示“登录成功”
         *     否则 提示  “登录失败”
         *
         * */
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入 用户名:");
        String username=sc.nextLine();
        System.out.println("请输入密码:");
        String password=sc.nextLine();

        boolean flag = login(username, password);
             if(flag)
                 System.out.println("登录成功");
             else
                 System.out.println("登录失败");

    }

    /**
     * 登录验证的方法

     * @return
     */
    public  static   boolean  login(String username,String password){

        try {
            //获取数据库连接对象
            Connection con = JDBCUtil.getConnection();

               //获取执行sql语句对象
//            Statement stat = con.createStatement();
            //定义sql语句
//            String sql="select * from user where username='"+username+"' and password='"+password+"'";
            /*sql注入产生原因:
            *   因为sql语句中存在字符串的拼接,只要给予特定的sql语句,会导致用户名与密码失效,这样的问题我们称之为sql注入
            *   如何解决这个问题?
            *      不使用字符串拼接,而是使用占位符 ?  进行赋值
            *          占位符----占用位置
            * */
//            String sql="select * from user where username='"+username+"' and password='88' or '1'='1'";
            String sql="select * from user where username=? and password=? ";
            System.out.println(2);
            //获取预编译对象  ---预编译sql语句,并对占位符进行赋值
            // 预编译---把sql语句执行一次,让sql不能再随意更改(防止字符串拼接)
            PreparedStatement pst =con.prepareStatement(sql);
            System.out.println(1);
            //给占位符赋值
              pst.setString(1,username);
              pst.setString(2,password);
            System.out.println(3);
               //再次真正执行sql
            ResultSet resultSet = pst.executeQuery();



            //执行sql语句
//            ResultSet resultSet = stat.executeQuery(sql);
               //进行判断 如果存在下一个元素,证明我们输入的用户名与密码与数据库中用户名和密码匹配
            //  resultSet.next()的返回值是boolean,如果  resultSet.next()结果为true,
            // 代表存在下一个元素,意味着我们输入的用户名与密码与数据库中用户名和密码匹配
            if(resultSet.next()){
                return true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

 

JDBC控制事务:

1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

2. 操作:

1. 开启事务

2. 提交事务

3. 回滚事务

3. 使用Connection对象来管理事务

* 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

* 在执行sql之前开启事务

* 提交事务:commit()

* 当所有sql都执行完提交事务

* 回滚事务:rollback()

* 在catch中回滚事务

 

2.连接池:是一个容器,用来存放数据库连接的容器

当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,访问数据库,用户访问玩之后,会将连接对象归还给容器。

为什么要学连接池?

连接池的好处(作用)是?

1. 节约资源

2. 用户访问高效(提高用户访问效率)

 


常见的连接池有:c3p0 Druid dbcp

实现:

1. 标准接口:DataSource   javax.sql包下的

1. 方法:

* 获取连接:getConnection()

* 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

 

2. 一般我们不去实现它,有数据库厂商来实现

1. C3P0:数据库连接池技术

2. Druid:数据库连接池实现技术,由阿里巴巴提供的

 

c3p0的使用:

1.导入依赖Jar包

2.导入配置文件(建议放在src下面)

3.创建连接对象(DateSource)

C3P0:数据库连接池技术

* 步骤:

1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,

* 不要忘记导入数据库驱动jar包

2. 定义配置文件:

* 名称: c3p0.properties 或者 c3p0-config.xml

* 路径:直接将文件放在src目录下即可。

 

3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

4. 获取连接: getConnection

* 代码:

 //1.创建数据库连接池对象

        DataSource ds  = new ComboPooledDataSource();

        //2. 获取连接对象

        Connection conn = ds.getConnection();

例子:

/*使用c3p0连接池操作数据库的步骤:
        *    1.要导入连接池jar包
        *      注意:使用连接池技术操作数据库也需要jdbc的jar
        *    2.导入配置文件
        *       配置文件要放在src下面(会自动加载配置文件中的内容)
        *
        *    3.创建连接池对象
        *       DateSource(接口)----ComboPooledDataSource
        *
        *    4.获取连接对象
        *
        * */
        //默认使用配置文件中的   <default-config>
        DataSource  ds=new ComboPooledDataSource();
        //获取连接对象
        Connection con = ds.getConnection();
        //操作数据库
        //定义sql语句
        String sql="select * from account where id=? or id=?";
        PreparedStatement pst = con.prepareStatement(sql);
               pst.setInt(1,1);
               pst.setInt(2,2);
        ResultSet res = pst.executeQuery();
             //遍历结果集
          while(res.next()){
              int id = res.getInt("id");
              String name = res.getString("name");
              double balance = res.getDouble("balance");
              System.out.println(id+"\t"+name+"\t"+balance);
          }

 

 Druid:数据库连接池实现技术,由阿里巴巴提供的

1. 步骤:

1. 导入jar包

2. 定义配置文件:

* 是properties形式的

* 可以叫任意名称,可以放在任意目录下

3. 加载配置文件。Properties

4. 获取数据库连接池对象:通过工厂来来获取  DruidDataSourceFactory

5. 获取连接:getConnection

例子:

/*使用Druid连接池操作数据库步骤
             1.导入jar包
             2.导入配置文件(可以放在项目的任意位置,但是建议放在src下面)
             3.创建连接池对象
               使用DataSource的工厂类   DruidDataSourceFactory
                   调用createDataSource创建连接池对象

               4.获取连接对象
        *
        *
        * */
        //创建流对象
      /*  InputStream  is=new FileInputStream
                ("druid.properties");*/
        InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");

        //创建Properties对象
        Properties  pt=new Properties();
        //加载配置文件
        pt.load(is);
//        3.创建连接池对象
        DataSource ds = DruidDataSourceFactory.createDataSource(pt);
//        4.获取连接对象
        Connection con = ds.getConnection();
        System.out.println(con);

        //执行sql语句


    }

 

Spring JDBC

* Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发

* 步骤:

1. 导入jar包

2. 创建JdbcTemplate对象。依赖于数据源DataSource

* JdbcTemplate template = new JdbcTemplate(ds);

 

3. 调用JdbcTemplate的方法来完成CRUD的操作

* update():执行DML语句。增、删、改语句

* queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合

* 注意:这个方法查询的结果集长度只能是1

* queryForList():查询结果将结果集封装为list集合

* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中

* query():查询结果,将结果封装为JavaBean对象

* query的参数:RowMapper

* 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装

* new BeanPropertyRowMapper<类型>(类型.class)

* queryForObject:查询结果,将结果封装为对象

* 一般用于聚合函数的查询

代码:

public static void main(String[] args) {
        /*JDBCTemplate:
        *    Spring对jdbc的一个封装,Spring为操作JDBC提供的一个小的框架
        *    目的:简化执行sql语句的代码书写。
        *    框架是什么?相当于一个半成品软件。
        *         Spring1框架----用来做数据库的添加操作---小的软件
        *         对数据库做 具体的添加操作时,基于 前面已经封装好的一个小的软件进行二次开发。
        *         使用JDBCTemplate的步骤:
        *               1.导入jar包。
        *               2.创建JDBCTemplate对象  ,依赖于连接池
        *           JDBCTemplate提供了很多方法,用来简化执行sql语句的书写
        *           update()----执行增删改语句
        *           Query()---将查询的结果封装成实体类(JAVABean)对象
        *           QueryForMap()---将查询的结果封装成map集合(只能查询一条数据)
        *           QueryForList()---将查询的结果封装成list集合(查询一条数据或多条数据)
        *           QueryForObject()----一般用于聚合函数的查询
        * */
        //先要获取连接池对象
        DataSource ds = DruidUtil.getDs();
//        2.创建JDBCTemplate对象  ,依赖于连接池

        JdbcTemplate jdbcTemplate = new JdbcTemplate(ds);
        String sql="insert into account values(?,?,?)";
        //  操作sql语句
        jdbcTemplate.update(sql,3,"老王",9000);

        //使用JDBCTemplate 往account 表中添加一条数据

    }

今日学习感受:学习java的路上虽然很长,但是累并快乐着,学习的东西虽然很多,但是大部分只要自己认真去学,还是可以学好的,希望自己继续坚持下去。最后一句话:生于忧患,死于安乐.