IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 事务JDBC封装工具类Druid-连接池技术Dbutils -> 正文阅读

[大数据]事务JDBC封装工具类Druid-连接池技术Dbutils

事务

什么是事务?

在实际的开发过程中,一个业务操作如:转账,往往是要多次访问数据库才能完成的。转
账是一个用户扣钱,另一个用户加钱。如果其中有一条 SQL 语句出现异常,这条 SQL 就可能执行失败;
事务执行是一个整体,所有的 SQL 语句都必须执行成功。如果其中有 1 SQL 语句出现异常,则所有的SQL 语句都要回滚,整个业务执行失败;

手动提交事务

MYSQL 中可以有两种方式进行事务的操作:
  1. ?手动提交事务
  2. ?自动提交事务

手动提交事务的sql语句

开启事务? ?? start transaction;
提交事务? ?? commit;

回滚事务? ?? rollback;

手动提交事务使用过程:?

执行成功的情况: 开启事务 ---> 执行多条 SQL 语句 ---> ? 成功提交事务
执行失败的情况: 开启事务 ---> ? 执行多条 SQL 语句 ---> ? 事务的回滚

自动提交事务

?MySQL 默认每一条 DML(增删改)语句都是一个单独的事务,每条语句都会自动开启一个事务,语句执行完毕 自动提交事务,MySQL 默认开始自动提交事务;

取消自动提交

查看 MySQL 是否开启自动提交事务
@@ 表示全局变量, 1 表示开启, 0 表示关闭
取消自动提交事务
执行更新语句,使用 SQLYog 查看数据库,发现数据并没有改变
在控制台执行 commit 提交任务

事务原理

事务开启之后 , 所有的操作都会临时保存到事务日志中 , 事务日志只有在得到 commit 命令才会同步到数据表中,其他任何情况都会清空事务日志(rollback ,断开连接 )

事务的步骤:?

  1. 客户端连接数据库服务器,创建连接时创建此用户临时日志文件
  2. 开启事务以后,所有的操作都会先写入到临时日志文件中
  3. 所有的查询操作从表中查询,但会经过日志文件加工后才返回
  4. 如果事务提交则将日志文件中的数据写到表中,否则清空日志文件。

回滚点 ?

在某些成功的操作完成之后,后续的操作有可能成功有可能失败,但是不管成功还是失败,前面操作都已经成 功,可以在当前成功的位置设置一个回滚点。可以供后续失败操作返回到该位置,而不是返回所有操作,这个点称之 为回滚点。

回滚点的操作语句?

设置回滚点 ????????savepoint 名字
回到回滚点 ????????rollback to 名字

?注意事项:设置回滚点可以让我们在失败的时候回到回滚点,而不是回到事务开启的时候。

事务的四大特性 ACID ?

原子性( Atomicity
每个事务都是一个整体,不可再拆分,事务中所有的 SQL 语句要么都执行成功, 要么都失败。
一致性( Consistency
事务在执行前数据库的状态与执行后数据库的状态保持一致。如:转账前 2 个人的 总金额是 2000 ,转账后 2 个人总金额也是 2000
隔离性( Isolation
事务与事务之间不应该相互影响,执行时保持隔离的状态。
持久性( Durability
一旦事务执行成功,对数据库的修改是持久的。就算关机,也是保存下来的。

事务的隔离级别

事务在操作时的理想状态: 所有的事务之间保持隔离,互不影响。因为并发操作,多个用户同时访问同一个 数据。可能引发并发访问的问题:

脏读 ??????????????
一个事务读取到了另一个事务中尚未提交的数据
不可重复读 ??????
?????????
一个事务中两次读取的数据 内容 不一致,要求的是一个事务中多次读取时数据是一致的,这 是事务 update 时引发的问题
幻读
一个事务中两次读取的数据的 数量 不一致,要求在一个事务多次读取的数据的数量是一致
的,这是 insert delete 时引发的问题

MySQL 数据库有四种隔离级别

上面的级别最低,下面的级别最高。表示会出现这种问题,表示不会出现这种问题。

注意:?隔离级别越高,性能越差,安全性越高

MySQL 事务隔离级别相关的命令

查询全局事务隔离级别
select @@tx_isolation;
设置事务隔离级别,需要退出 MySQL 再重新登录才能看到隔离级别的变化
set global transaction isolation level? 级别字符串

JDBC:Java database? connectivity(Java数据库连接)

?JDBC的本质

???Java连接数据库
? 由数据库厂商提供的数据库jar包,实现了sun提供的接口的实现类
? Java.sql.Driver 驱动接口------------>com.mysql.jdbc.Driver
? java.sql.Connection 数据库连接接口--------->com.mysql.jdbc.ConnectionImpl
? 只需要导入数据库厂商提供的jar包
? jar包的名字: mysql-connection-Java.版本号.jar

JDBC的操作步骤

?1 导包
?2 注册驱动?? ------>Class.forName("com.mysql.jdbc.Driver");
?3 获取数据库连接对象--------->(三个参数:协议,(jdbc:mysql://localhost:3306/库名)用户名,密码)
?4 写sql语句------------>(DDL 创建表/ insert into/ update /delete ?from)
?5 连接对象获取执行对象 ?------->(Statement stmt=conn.createStatement();)
?6 执行sql语句,---------->? resultSet=stmt.excuteQuery(sql);
?7 释放资源------>(conn.close(); ? stmt.close(); )

代码提现:

package com.qf.jdbc_01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
 *
 * jdbc原生操作步骤:7大步骤
 *  1)导入驱动mysql的jar包
 *  2)注册驱动
 *  3)创建数据库的连接对象Connection
 *  4)准备好sql
 *  5)通过连接对象获取执行对象Statment
 *  6)执行sql语句   (插入操作)
 *  7)释放资源 (系统资源需要被释放的)
 */
public class JDBCDemo {
    public static void main(String[] args) throws Exception {

        //1)导入驱动mysql的jar包
        //2)注册驱动
        Class.forName("com.mysql.jdbc.Driver") ;

       // DriverManager.registerDriver(new com.mysql.jdbc.Driver());

        //3)创建数据库的连接对象Connection
        //jdk提供的DriverManager:驱动管理类(管理jdbc的驱动的)
        //public static Connection getConnection(String url,String user,String password)throws SQLException
        //参数url: 统一资源定义符号  组成  协议:端口号:库名   --->jdbc:mysql://localhost:3306
        //参数user: 登录msyql的用户名 root用户
        //参数password:登录mysql的密码
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/ee_2208_02",
                "root",
                "123456"
        );


        //4)准备好sql
        String sql = "insert into account(name,balance) values('赵又廷2',2000)  " ;

        //5)通过连接对象获取执行对象Statment
        //Statement createStatement()throws SQLException创建一个Statement对象,用于将SQL语句发送到数据库
        Statement stmt = conn.createStatement();

        //6)执行sql语句   (插入操作)
        //Statement执行器里面---->
        //int executeUpdate(String sql)throws SQLException 通用的执行通用添加,删除,修改
        int count = stmt.executeUpdate(sql);
        System.out.println("影响了"+count+"行") ;

        //7)释放资源 (系统资源需要被释放的)
        stmt.close();
        conn.close();
    }
}
package com.qf.jdbc_02;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
 * JDBC来操作DDL语句:创建表
 * 使用JDBC来创建一个学生表,编号id,name姓名,age年龄,gender性别,address住址
 *
 */
public class JdbcDemo2 {
    public static void main(String[] args)  throws Exception{
        //7大步骤
        //1)导包
        //2)注册驱动
        Class.forName("com.mysql.jdbc.Driver") ;

        //3)获取数据库连接对象
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/ee_2208_02",
                "root",
                "123456");

        //4)准备sql
        String sql = "create table student(" +
                " id int primary key auto_increment," +
                " name varchar(10)," +
                " age int," +
                " gender varchar(3)," +
                " address varchar(20)" +
                ");" ;
        //5)通过连接对象获取执行器
        Statement stmt = conn.createStatement();

        //6)执行sql语句  ----通用的更新操作:添加删除/修改, 或者ddl语句 "建表"  ---int executeUpdate(String sql)
        int count = stmt.executeUpdate(sql);
        System.out.println(count);

        //7)释放资源
        stmt.close();
        conn.close();
    }
}
package com.qf.jdbc_02;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * Jdbc操作DML语句
 *      插入,insert
 *      修改,update
 *      删除,delete
 *
 *      加入异常处理----try...catch..finally...捕获异常
 */
public class JDBCDemo3 {
    public static void main(String[] args) {

        Connection conn = null ;
        Statement stmt = null ;
        try {
            //1)导包
            //2)注册驱动
            Class.forName("com.mysql.jdbc.Driver") ;
            //3)获取数据库连接对象
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/ee_2208_02",
                    "root",
                    "123456"
            );
            //4)sql语句
            //插入insert
           /* String sql = "insert into student(name,age,gender,address) values('李帅',25,'男','西安市')," +
                    " ('高圆圆',28,'女','渭南市')," +
                    " ('赵又廷',30,'男','宝鸡市')," +
                    " ('王瑄',23,'男','南窑国际')" ;*/

            //修改操作update
            //String sql = "update student set name = '马蓉',age = 25,address='渭南市富平县' where id = 2" ;

            //删除
            String sql = "delete from student where id = 2 ;" ;

            //5)通过连接对象获取执行器
            stmt = conn.createStatement();

            //6)执行
            int count = stmt.executeUpdate(sql);
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if(stmt!=null){
                try {
                    stmt.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
           if(conn!=null){
               try {
                   conn.close() ;
               } catch (SQLException throwables) {
                   throwables.printStackTrace();
               }
           }

        }
    }
}

定义工具类

针对原生JDBC进行封装 将注册驱动以及获取连接对象,释放资源代码进行优化

package com.qf.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * 针对原生JDBC进行封装 将注册驱动以及获取连接对象,释放资源代码进行优化
 */
public class JdbcUtils {

    //提供几个属性
    private static String url = null ;
    private static String user = null ;
    private static String password = null ;
    private static String driverClass= null ;
    //构造方法私有化
    private JdbcUtils(){}

    //提供静态代码块
    //JdbcUtils 类一加载,static{}就加载了,
    static{

        try {
            //1)读取src下面的配置文件jdbc.properties
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //2)将配置文件的内容加载到属性集合列表Properties
            //创建一个空的属性集合列表
            Properties prop = new Properties() ;
            prop.load(inputStream);
            //System.out.println(prop);
            //3)通过配置文件的key获取value
            //4)就给上面的成员变量赋值
            driverClass = prop.getProperty("driverClass");
            url = prop.getProperty("url") ;
            user = prop.getProperty("user") ;
            password = prop.getProperty("password") ;

            //注册驱动
            Class.forName(driverClass) ;

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



    //对外提供静态方法
    //定义一个方法:获取连接对象
    public static Connection getConnection(){

        try {
            //需要用到驱动管理类,获取连接对象
            Connection conn = DriverManager.getConnection(url, user, password);
            return conn ;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }

    /**
     * 释放资源 针对DQL语句,select语句
     * @param rs  释放结果集对象
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(ResultSet rs,Statement stmt,Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 释放资源,针对DML语句:update,delete,insert操作的
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(Statement stmt,Connection conn){
       close(null,stmt,conn);//复用上面的close,第一个参数为null
    }


    public static void main(String[] args) {

        Connection connection = JdbcUtils.getConnection();
        System.out.println(connection);
    }


}

测试,运用工具类

import java.sql.Statement;

/**
 * 定义工具类,测试工具类
 */
public class JDBCUtilsTest {
    public static void main(String[] args) {

        Connection conn = null;
        Statement stmt = null ;
        try {
            //直接获取数据库连接对象
             conn = JdbcUtils.getConnection();

            //sql
            String sql = "insert into student(name,age,gender,address) values('文章',35,'男','咸阳市')" ;
            //获取执行对象
             stmt = conn.createStatement();
            //执行
            int count = stmt.executeUpdate(sql);
            System.out.println(count);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.close(stmt,conn);
        }


    }
}

?使用JDBC来操作DQL语句(数据库查询语句)

package com.qf.jdbc_operator_dql_02;

import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 使用JDBC来操作DQL语句(数据库查询语句)
 * 查询ee_2208_02库中的学生表的所有信息,展示数据
 */
public class JdbcOperatorDQL {
    public static void main(String[] args) {
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;

        try {
            //注册驱动
            //获取连接
            conn = JdbcUtils.getConnection();

            //sql
            String sql = "select * from student" ;
            //通过连接获取执行对象
            stmt = conn.createStatement();
            //执行查询---ResuletSet executeQuery(String sql)
            rs = stmt.executeQuery(sql);
            //第一次查
            //如果有数据---,才移动一行  boolean next() :有数据,移动
            System.out.println("学生信息如下:");
            System.out.println("学生编号\t学生姓名\t学生年龄\t学生性别\t住址");
       
            //循环
            while(rs.next()){
                //方式2:通过列的名称获取  xxx getXXX(String columnLabel)
                int id = rs.getInt("id") ;
                String name = rs.getString("name") ;
                int age = rs.getInt("age") ;
                String gender = rs.getString("gender") ;
                String address = rs.getString("address") ;
                System.out.println(id+"\t\t"+name+"\t\t"+age+"\t\t"+gender+"\t\t"+address);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            //释放资源
            JdbcUtils.close(rs,stmt,conn);

        }
    }
}

JDBC的测试,自定义一个学生类,属性和表中的字段一一对应

package com.qf.jdbc_test_03;

/**
 * 创建学生类
 */
public class Student {
    //属性和student表的字段一一对应  ,属性私有化
    private int id ;
    private String name ;
    private int age ;
    private String gender ;
    private String address ;

    //无参构造方法
    public Student() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

JDBC的应用?

package com.qf.jdbc_test_03;

import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * JDBC的应用
 * 需求:查询student表的所有数据,将每一条记录封装到Student对象中,将这些学生对象添加到
 * List<Student>,将List集合遍历,获取每一个学生对象的信息!
 *
 * 分析:
 *  1)学生类 Student---->id,name,age,gender,address属性(属性都是小写)
 *  2)在jdbcTest定义一个方法---->返回List<Student>
 *      2.1)完成jdbc操作,查询student表
 *      查询一条,封装一个Student对象
 *      2.2)创建一个空的List<Student>,将封装学生对象添加到list集合对象汇总
 *   3)main方法去调用自定义的方法
 */
public class JdbcTest {
    public static void main(String[] args) throws Exception {

        List<Student> students = getStudents();
        if(students!=null){
            for(Student s:students){
                System.out.println(s);
            }
        }
    }

    /**
     * 获取学生信息
     * @return  学生列表
     */
    public static List<Student> getStudents() throws Exception {

        //jdbc操作
        //注册驱动,获取数据库连接
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "select * from student";
        //通过数据库的连接对象获取执行对象
        Statement stmt = conn.createStatement();
        //执行sql
        ResultSet rs = stmt.executeQuery(sql);
        //创建一个空的集合
        List<Student> list = new ArrayList<>();
        //声明一个学生类型的变量
        Student s = null;
        //遍历结果集
        while (rs.next()) {  //不断在判断:有数据---一动一行---封装一个学生对象
            //封装学生对象
            s = new Student();
            //通用方式1方式2获取 ,列名称或者列的索引值
            int id = rs.getInt("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            String gender = rs.getString("gender");
            String address = rs.getString("address");

            s.setId(id);
            s.setName(name);
            s.setAge(age);
            s.setGender(gender);
            s.setAddress(address);

            //将学生对象s添加list集合中
            list.add(s);
        }
        //释放资源
        JdbcUtils.close(rs,stmt,conn);


        return list;
    }
}

实例:

使用Statement执行对象完成模拟用户登录操作,比如有一个user表(id字段,name,password字段),
有两个用户信息?? ?,查询user表的指定用户,如果找到用户,则提示"登录成功",否则"登录失败!"

package com.qf.jdbc_test_03;

import com.qf.utils.JdbcUtils;

import java.sql.*;
import java.util.Scanner;


public class JdbcTest2 {

    public static void main(String[] args) throws SQLException {
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in) ;
        //提示并录入数据
        System.out.println("请您输入用户名:") ;
        String username = sc.nextLine() ;

        System.out.println("请您输入密码:") ;
        String password = sc.nextLine() ;

        //调用isLogin方法
//        boolean flag = isLogin(username, password);
        boolean flag = isLogin2(username, password);
        if(flag){
            //true
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败!");
        }
    }

    //预编译对象:PreparedStatement
    //两个通用操作:更新 int executeUpdate()   /ResultSet executeQuery()
    public static boolean isLogin2(String username,String password) throws SQLException {
        //注册驱动,获取数据库连接
        Connection conn = JdbcUtils.getConnection();
        //sql
        //预编译sql语句:里面的参数值都是英文的 ?--一个?代表一个值  就是占位符
        String sql = "select * from user  where  username = ? and password = ?" ;
        System.out.println(sql) ;
        //获取执行对象---->预编译对象PreparedStatement
        //PreparedStatement prepareStatement(String sql):将上面的参数化sql发送给数据库
        //将sql语句存储到了预编译对象中
        PreparedStatement stmt = conn.prepareStatement(sql);

        //给占位符赋值
        //通用setXXX(占位符号索引值,实际值) ; // 占位符号索引值是从1开始,第一个?就是1,第二个?就是 2
        //举例:setString(1,username)
        stmt.setString(1,username);
        stmt.setString(2,password);

        //执行查询
        ///ResultSet executeQuery()
        ResultSet rs = stmt.executeQuery();

        boolean flag = rs.next();

        //释放资源
        JdbcUtils.close(rs,stmt,conn);

        return flag ; //查到了返回true


            }

    }

Statement弊端

select * from user where username = 'sdfs' and password = ''OR' ?1= 1'
存储在字符串拼接sql语句 会造成SQL注入,不安全!
执行效率低,每一次写好一个sql,才能发送给数据库,写一个,发送一个!频繁和数据库的交互(次数比较频繁)

?PreparedStatement的特点

不会造成sql注入,不存在sql拼接
执行效率相对Statement,将sql编译一次发送数据库,sql语句存储PreparedStatement预编译对象
里面给赋不同的值即可! ??
?

statement和preparedstatement区别??

共同点:都能将sql发送给数据库,,都称为执行对象,,后者继承前者


区别:

?1.是否能够造成sql注入
Statement,
------由于操作sql语句是静态的,存在字符串拼接,存在安全漏洞
preparedStatement(预编译对象)可以防止sql注入
-----发送的sql数据是一种参数化的sql,不存在拼接,
? ? ? ? 举例:
? ? ? ? ? ? ? ? insert into 表名 values(?,?,?,?,?); ?//? ?占位符号

2.sql执行效率
? ? ? ? ? ?Statement执行sql语句,效率比较低,执行静态sql
? ? ? ? ? ?举例,
? ? ? ? ? ?insert into 表名 ?values (1,''张三,30,'男'','西安市')
? ? ? ? ? ?写sql语句,写一句执行一句,执行效率低
? ? ? ? ? ?PreparedStatement执行效率高,执行参数化的sql

单元测试?

单元测试
导入jar包 junit-4.13.1 ?依赖包hamcrest-core.jar
编写方法---没有返回值,没有参数
使用@Test标记这个方法是单元测试方法--能够单独驱动的(包含启动器runner,直接运行的)
@Before:标记的方法是在@Test标记的单元测试方法先执行---->一般初始化的代码---读取配置文件等操作,对象创建
@After:标记的方法是在@Test标记的单元测试方法之后执行----> 一般释放资源代码
测试功能
org.junit.Assert类--->断言 ?---针对具体数据结果值直接用它
开发中,还是直接测试自己的功能,是否能够从数据库中将数据获取到

代码提现:

package com.qf.junit_04;

/**
 * 定义一个计算器类
 */
public class Calculator {

    //加
    public int add(int a,int b){
        return  a + b ;
    }
    //减
    public int sub(int a, int b){
        return  a -b ;
    }
    //乘
    public int mul(int a,int b){
        return  a * b ;
    }
    //除
    public int div(int a,int b){
        return  a/b ;
    }
}
package com.qf.junit_04;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * 针对计算器类的测试类
 *
 *
 * 单元测试
 * 1)导入jar包 junit-4.13.1  依赖包hamcrest-core.jar
 * 2)编写方法---没有返回值,没有参数
 * 3)使用@Test标记这个方法是单元测试方法--能够单独驱动的(包含启动器runner,直接运行的)
 *
 * @Before:标记的方法是在@Test标记的单元测试方法先执行---->一般初始化的代码---读取配置文件等操作,对象创建
 * @After:标记的方法是在@Test标记的单元测试方法之后执行----> 一般释放资源代码
 * 4)测试功能
 *
 *      org.junit.Assert类--->断言  ---针对具体数据结果值直接用它
 *
 *      开发中,还是直接测试自己的功能,是否能够从数据库中将数据获取到
 *
 */


public class CalculatorTest {
    Calculator c = null ;
    @Before
    public void init(){
        System.out.println("init方法执行了...");
        //创建计算器类
        c = new Calculator() ;
    }

    @After //@After:标记的方法是在@Test标记的单元测试方法之
    // 后执行
    public void close(){
        System.out.println("close方法执行了....");
    }
    /**
     * 测试计算器类的求和功能
     */
    @Test
    public void testAdd(){
        System.out.println("testAdd方法执行了");
        //1)编写Java代码
        //创建计算器类
        //Calculator c = new Calculator() ;
        int reuslt = c.add(10, 20); //求和

        //断言----result结果值和预期结果值是否相等,如果相等,断言成功;否则,断言失败
        //public static void assertEquals(Object expected, Object actual) :参数1:预期值,参数2:实际值
        Assert.assertEquals(30,reuslt);
    }
}

案例,对于员工表进行操作

定义员工实体类

/**
 * 员工类
 */
public class Employee {
    //和员工表的字段一致
    private int id ;//编号
    private String name ;//姓名
    private int age ;//年龄
    private String gender ; //性别
    private String address ; //地址
    private Date birthday ;//出生日期

    public Employee() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address='" + address + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

工具类用到的属性文件?

driverClass=com.mysql.jdbc.Driver? ? ??
url=jdbc:mysql://localhost:3306/库名
user=root????????????????? //用户名
password=******?????????//密码

?简易工具类Utils

/**
 * 针对原生JDBC进行封装 将注册驱动以及获取连接对象,释放资源代码进行优化
 */
public class JdbcUtils {

    //提供几个属性
    private static String url = null ;
    private static String user = null ;
    private static String password = null ;
    private static String driverClass= null ;
    //构造方法私有化
    private JdbcUtils(){}

    //提供静态代码块
    //JdbcUtils 类一加载,static{}就加载了,
    static{

        try {
            //1)读取src下面的配置文件jdbc.properties
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //2)将配置文件的内容加载到属性集合列表Properties
            //创建一个空的属性集合列表
            Properties prop = new Properties() ;
            prop.load(inputStream);
            //System.out.println(prop);
            //3)通过配置文件的key获取value
            //4)就给上面的成员变量赋值
            driverClass = prop.getProperty("driverClass");
            url = prop.getProperty("url") ;
            user = prop.getProperty("user") ;
            password = prop.getProperty("password") ;

            //注册驱动
            Class.forName(driverClass) ;

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



    //对外提供静态方法
    //定义一个方法:获取连接对象
    public static Connection getConnection(){

        try {
            //需要用到驱动管理类,获取连接对象
            Connection conn = DriverManager.getConnection(url, user, password);
            return conn ;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }

    /**
     * 释放资源 针对DQL语句,select语句
     * @param rs  释放结果集对象
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(ResultSet rs,Statement stmt,Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 释放资源,针对DML语句:update,delete,insert操作的
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(Statement stmt,Connection conn){
       close(null,stmt,conn);//复用上面的close,第一个参数为null
    }


    public static void main(String[] args) {

        Connection connection = JdbcUtils.getConnection();
        System.out.println(connection);
    }


}

员工数据访问接口

package com.qf.dao;

import com.qf.pojo.Employee;

import java.sql.SQLException;
import java.util.List;

/**
 * 针对员工的数据访问接口
 */
public interface EmployeDao {

    /**
     * 查询员工表的所有数据,将员工表的数据封装List集合中
     * @return 返回员工列表
     */
    List<Employee> findAll() throws SQLException;

    /**
     * 通过员工编号查询员工,将员工这条信息封装员工类中
     * @param id 已知员工编号
     * @return  返回员工实体
     */
    Employee findEmployeeById(int id) throws SQLException;

    /**
     * 添加员工对象
     * @param employee  员工对象
     */
    void  addEmplyee(Employee employee) throws SQLException;

    /**
     * 修改员工数据
     * @param employee 要修改员工实体
     */
    void updateEmployee(Employee employee) throws SQLException;

    /**
     * 通过id删除员工
     * @param id
     */
    void deleteEmployee(int id) throws SQLException;
}

员工数据访问接口实现

package com.qf.dao.impl;

import com.qf.dao.EmployeDao;
import com.qf.pojo.Employee;
import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 针对员工的数据访问接口实现
 */
public class EmployeeDaoImpl  implements EmployeDao {
    /**
     * 查询员工表的所有数据,将员工表的数据封装List集合中
     * @return 返回员工列表
     */
    @Override
    public List<Employee> findAll() throws SQLException {
        //创建List集合
        List<Employee> list = new ArrayList<>() ;

        //注册驱动.获取数据库连接对象
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "select  * from employee" ;
        //创建执行对象
        Statement stmt = conn.createStatement();
        Employee emp = null ;
        //执行查询
        ResultSet rs = stmt.executeQuery(sql);
        while(rs.next()){
            //封装员工实体
            emp = new Employee();

            emp.setId(rs.getInt("id"));
            emp.setName(rs.getString("name"));
            emp.setAge(rs.getInt("age"));
            emp.setGender(rs.getString("gender"));
            emp.setAddress(rs.getString("address"));
            emp.setBirthday(rs.getDate("birthday"));

            //将emp对象添加list集合中
            list.add(emp) ;
        }
        //释放资源
        JdbcUtils.close(rs,stmt,conn);


        return list;
    }


    /**
     * 通过员工编号查询员工,将员工这条信息封装员工类中
     * @param id 已知员工编号
     * @return  返回员工实体
     */
    @Override
    public Employee findEmployeeById(int id) throws SQLException {
        //注册驱动,获取数据库连接对象
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "select * from employee where id = "+id+"" ;
        //获取执行对象
        Statement stmt = conn.createStatement();
        //执行查询
        ResultSet rs = stmt.executeQuery(sql);
        Employee employee = null ;
        while(rs.next()){
            //封装员工实体
            employee = new Employee() ;
            employee.setId(rs.getInt("id"));
            employee.setName(rs.getString("name"));
            employee.setAge(rs.getInt("age"));
            employee.setGender(rs.getString("gender"));
            employee.setAddress(rs.getString("address"));
            employee.setBirthday(rs.getDate("birthday"));
        }
        //释放资源
        JdbcUtils.close(rs,stmt,conn);
        return employee;
    }

    /**
     * 添加员工对象
     * @param employee  员工对象
     */
    @Override
    public void addEmplyee(Employee employee) throws SQLException {
        //注册驱动,获取数据库连接对象
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "insert into employee(name,age,gender,address,birthday) " +
                "values('" + employee.getName() + "','"  +employee.getAge()+ "','" + employee.getGender() + "'," +
                "'" + employee.getAddress() + "','" + employee.getBirthday() + "')";
        //测试sql
        System.out.println(sql);
        //获取执行对象
        Statement stmt = conn.createStatement();
        //执行更新
        int count = stmt.executeUpdate(sql);
        System.out.println(count);
        //释放资源
        JdbcUtils.close(stmt,conn);

    }

    /**
     *
     * @param employee 要修改员工实体
     */
    @Override
    public void updateEmployee(Employee employee) throws SQLException {
        //注册驱动,获取连接对象
        Connection connection = JdbcUtils.getConnection();
        //sql
        String sql = "update employee set name ='"+employee.getName()+"' ," +
                "age ='"+employee.getAge()+"',gender='"+employee.getGender()+"',address='"+employee.getAddress()+"' where id ='"+employee.getId()+"' ";
        System.out.println(sql) ;
        //获取执行对象
        Statement stmt = connection.createStatement();
        //执行更新
        int count = stmt.executeUpdate(sql);
        System.out.println(count);

        //释放资源
        JdbcUtils.close(stmt,connection);
    }

    /**
     * 删除员工
     * @param id
     */
    @Override
    public void deleteEmployee(int id) throws SQLException {

        //注册驱动,获取连接对象
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "delete from employee where id = '"+id+"' " ;
        System.out.println(sql);
        //获取执行对象
        Statement stmt = conn.createStatement() ;

        //执行
        int count = stmt.executeUpdate(sql);
        System.out.println(count);

        //释放资源
        JdbcUtils.close(stmt,conn);
    }
}

针对员工类的测试

package com.qf.test;

import com.qf.dao.EmployeDao;
import com.qf.dao.impl.EmployeeDaoImpl;
import com.qf.pojo.Employee;
import org.junit.Before;
import org.junit.Test;

import java.sql.SQLException;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * 针对员工类的测试
 */
public class EmployeeTest {
    //声明接口类型
    private EmployeDao employeeDao ;
    @Before
    public void init(){
        //创建接口对象----接口多态
        employeeDao = new EmployeeDaoImpl() ;
    }

    /**
     * 测试查询所有数据,将数据封装List集合汇总
     */
    @Test
    public void testFindAll() throws SQLException {
        //调用功能
        List<Employee> all = employeeDao.findAll();
        if(all!=null){
            for(Employee emp :all){
                System.out.println(emp);
            }
        }
    }


    /**
     * 测试通过id获取员工信息
     */
    @Test
    public void testFindEmpById() throws SQLException {
        Employee emp = employeeDao.findEmployeeById(3);
        if(emp==null){
            System.out.println("没有这个员工");
        }else{
            System.out.println(emp);
        }

    }

    /**
     * 测试添加员工的功能
     */
    @Test
    public void testAddEmployee() throws Exception {
        //创建一个员工
        Employee emp = new Employee() ;
        emp.setName("赵又廷") ;
        emp.setAge(30);
        emp.setGender("男");
        emp.setAddress("西安市");
        //将String--java.util.Date
        String dateStr = "1984-02-10" ;//字符串日期文本
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
        Date date = sdf.parse(dateStr);
        //java.sql.Date有参构造方法
        //public java.sql.Date(long time)
        java.sql.Date myDate = new java.sql.Date(date.getTime()) ;
        System.out.println(myDate);
        emp.setBirthday(myDate);

        employeeDao.addEmplyee(emp);
    }

    /**
     * 测试修改员工
     */
    @Test
    public void testUpdateEmp() throws SQLException {
        Employee emp = new Employee() ;
        emp.setId(7) ;
        emp.setName("张佳宁") ;
        emp.setAge(32) ;
        emp.setGender("女");
        emp.setAddress("西安市鄠邑区") ;
        employeeDao.updateEmployee(emp);
    }


    /**
     * 测试删除员工
     */
    @Test
    public void testDeleteEmp() throws SQLException {

        employeeDao.deleteEmployee(3);
    }
}

JDBC控制事务

void setAutoCommit(boolean flag)? true? 表示自动提交,false 表示禁用自动提交(手动提交)

void rollback() ; 事务回滚

void commit() ;? 提交事务

package com.qf.jdbc_control_tansaction_01;

import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * Jdbc :Java连接数据库的方式控制事务
 * java.sql.Connection接口
 *
 *void setAutoCommit(boolean autoCommit) throws SQLException
 *      是否开启手动提交,参数true,就是自动提交,false,禁用自动提交,手动提交----->相当于mysql的指令 start transaction;
 *void rollback() throws SQLException撤销在当前事务中所做的所有更改----->事务回滚方法---->相当于msyql指令 rollback;
 * void commit()throws SQLException使上次提交/回滚之后所做的所有更改都将永久性  (提交事务)---->mysql的指令 commit;
 *
 *  Jdbc控制事务:当某个业务执行过程中需要同时指定多个sql(添加/删除/修改)需要将这个多个sql看成一个整体,他们要么
 *  同时执行成功,要么同时执行失败!
 *
 *  需求:
 *          account表:针对多个账户更新操作,"转账的操作"
 *
 *          高圆圆给赵又廷转账500
 */
public class JdbcDemo {
    public static void main(String[] args) {


        //现在使用JDBC控制事务
        Connection conn = null ;
        PreparedStatement ps = null ;
        PreparedStatement ps2 = null ;
        try {
            //获取数据库连接对象
            conn = JdbcUtils.getConnection();
            //开启事务
            //void setAutoCommit(boolean autoCommit) throws SQLException
            conn.setAutoCommit(false) ;//禁用自动提交
            //sql语句
            String sql1 = "update account set balance = balance -? where id= ? " ;
            String sql2 = "update account set balance = balance +? where id = ?" ;

            //获取预编译对象
            ps = conn.prepareStatement(sql1);
            //赋值
            ps.setInt(1,500);
            ps.setInt(2,3);

            //将sql2进行发送数据库,获取预编译对象
            ps2 = conn.prepareStatement(sql2);
            //赋值
            ps2.setInt(1,500) ;
            ps2.setInt(2,4);

            //通过预编译对象执行sql
            int count = ps.executeUpdate();

            //操作过程中,给一段代码(有问题的代码)
            //int i = 10 /0 ;//除数不能0  try中的某行代码一出问题,就执行catch语句,处理异常


            int count2 = ps2.executeUpdate();

            System.out.println(count+"---"+count2);

          //更新完上面的所有操作,正常提交数据
            conn.commit();
            System.out.println("转账成功");

        } catch (ArithmeticException throwables) {

            try {
                //回滚事务
                //void rollback() throws SQLException撤销在当前事务中所做的所有更改---
                conn.rollback();
                //回滚完之后,手动提交
                conn.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            throwables.printStackTrace(); //交个jvm处理  将异常信息打印控制台
            //System.out.println("出问题了...除数为0");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
//            System.out.println("SQL语句出问题了");
        } finally {
            //释放资源
            JdbcUtils.close(ps,conn);
            JdbcUtils.close(ps2,conn);

        }
    }
}

Druid连接池

?连接池(Druid)的好处是什么?

?加入连接池后,JDBCUtils工具类里面的步骤?

?1).提供ThreadLocal,代表当前线程
?2).静态代码块--->
? ? ? ? ? ? ? ? a)读取连接池的配置文件--->初始化了配置参数
? ? ? ? ? ? ? ? b)创建连接池--->DataSource---->druid.jar---提供com.alibaba.druid.pool.DruidDataSource
3).定义了一个方法,获取连接池--->DataSource
4).提供一个方法,获取连接对象,--加入了ThreadLocal--->判断当前线程中有连接对象,如果有,直接返回,没有的话,从连接池中获取连接对象,绑定到线程上

Druid封装工具类(德鲁伊)

package com.qf.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
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;

/**
 * 加入连接池Druid工具类的封装
 *
 * 模拟真实场景---->高并发情况下,每一个线程的连接对象应该使用自己的连接对象---->
 * 来自于连接池! jdk提供了这个类ThreadLocal<Connection>
 */
public class JdbcUtils_WithDruid {
    //成员变量的位置
    private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ;//类一加载,创建线程
    private static DataSource ds ; //数据源---->里面空的
    //无参构造方法私有化
    private JdbcUtils_WithDruid(){}
    //静态代码块
    static{
        try {
            //1)读取src下面的 德鲁伊的配置文件
            //创建集合列表
            Properties prop = new Properties() ;
            //读取druid.properties
            InputStream inputStream = JdbcUtils_WithDruid.class.getClassLoader().
                    getResourceAsStream("druid.properties");

            //将资源文件输入流中的内容加载到属性列表中
            prop.load(inputStream);
            System.out.println(prop);


            //2)将配置文件进行加载---DruidDataSource自动封装这些7个参数
            //通过DruidDataSourceFactory 创建数据源
            ds = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //定义方法----获取数据源的方法
    public static DataSource getDataSource(){
        return  ds ;
    }

    //定义一个获取连接对象
    public static Connection getConnection(){
        Connection conn = null ;
        try {
            //现在模拟多线程场景
            //1)从当前线程获取连接对象   ThreadLocal<Connection>----> Connection get()
           conn  = t1.get();
            //2)判断当前线程中的连接对象如果为null,
            if(conn==null){
                //说明没有连接对象
                //从连接池中获取连接对象
                Connection connection = ds.getConnection();
                //将连接池获取连接对象,绑定在当前线程中
                //ThreadLocal<Connection>----> set(Connection conn)
                t1.set(connection);
                return connection ;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  conn ;

    }

    //close()------------------>后面不用写了

    /**
     * 释放资源 针对DQL语句,select语句
     * @param rs  释放结果集对象
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();//释放--->归还给连接池
                //从当前线程中解绑
                //ThreadLocl--->remove()
                t1.remove();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 释放资源,针对DML语句:update,delete,insert操作的
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);//复用上面的close,第一个参数为null
    }


    public static void main(String[] args) {
        DataSource dataSource = JdbcUtils_WithDruid.getDataSource();
        System.out.println(dataSource);

        Connection connection = JdbcUtils_WithDruid.getConnection();
        System.out.println(connection);
    }
}

Druid属性文件配置

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
username=root
password=********
initialSize=5? ? ? ? ? ? --->初始化数量
maxActive=10? ? ? ? ---->最大连接数量
maxWait=3000? ? ? ? ----->最大等待时间

package com.qf.druid_02;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * 德鲁伊Druid连接池的使用步骤:
 * 1)导入druid的jar包
 *
 * com.alibaba.druid.pool.DruidDataSource---->最终实现了javax.sql.DataSource
 * 2)准备好连接池的配置文件
 *      配置好数据库的连接信息
 *      以及一些连接池连接池参数
 *      最大连接数量
 *      空闲数量
 *      超时时间...
 *
 * 3)创建连接池对象---->创建数据源DataSource接口不能实例化
 * com.alibaba.druid.pool.DruidDataSource它具体类,可以创建
 *
 * 4)com.alibaba.druid.pool.DruidDataSourceFactory 连接池数据源工厂类---->静态方法
 * 创建数据源
 *   protected DataSource createDataSourceInternal(Properties properties) throws Exception {
 *         DruidDataSource dataSource = new DruidDataSource();//创建数据源对象
 *         config(dataSource, properties); //将Properties 属性集合列表中的内容封装到数据源中
 *         return dataSource;
 *     }
 *
 *
 *     连接池仅仅只是提供数据库连接对象的,最起码需要有数据库驱动jar包----操作数据库
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {

        //创建属性集合列表
        Properties prop = new Properties() ;
        System.out.println(prop);
        //读取配置连接池文件
        InputStream inputStream = DruidDemo.class.getClassLoader().
                getResourceAsStream("druid.properties");

        //将资源文件输入流对象加载到属性列表中
        prop.load(inputStream);
        System.out.println(prop);

        //创建DruidDataSource对象
        //protected DataSource createDataSourceInternal(Properties properties) throws Exception
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        System.out.println(dataSource) ;
        //就可以连接池中获取连接对象
        //DataSource---->getConnection()--->Connections
      /*  Connection connection = dataSource.getConnection();
        Connection connection2 = dataSource.getConnection();
        System.out.println(connection);
        System.out.println(connection2);*/
        for(int x = 1 ; x <=11 ; x++){
            Connection connection = dataSource.getConnection();
            if(x==3){
                connection.close(); //不是释放,此时将第三个连接对象归还给连接池,有一个没有激活,第11个连接池对就可以获取到了
            }
            System.out.println(connection);
        }

    }
}

案例2

学生实体类

package com.qf.druid_02;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * 德鲁伊Druid连接池的使用步骤:
 * 1)导入druid的jar包
 *
 * com.alibaba.druid.pool.DruidDataSource---->最终实现了javax.sql.DataSource
 * 2)准备好连接池的配置文件
 *      配置好数据库的连接信息
 *      以及一些连接池连接池参数
 *      最大连接数量
 *      空闲数量
 *      超时时间...
 *
 * 3)创建连接池对象---->创建数据源DataSource接口不能实例化
 * com.alibaba.druid.pool.DruidDataSource它具体类,可以创建
 *
 * 4)com.alibaba.druid.pool.DruidDataSourceFactory 连接池数据源工厂类---->静态方法
 * 创建数据源
 *   protected DataSource createDataSourceInternal(Properties properties) throws Exception {
 *         DruidDataSource dataSource = new DruidDataSource();//创建数据源对象
 *         config(dataSource, properties); //将Properties 属性集合列表中的内容封装到数据源中
 *         return dataSource;
 *     }
 *
 *
 *     连接池仅仅只是提供数据库连接对象的,最起码需要有数据库驱动jar包----操作数据库
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {

        //创建属性集合列表
        Properties prop = new Properties() ;
        System.out.println(prop);
        //读取配置连接池文件
        InputStream inputStream = DruidDemo.class.getClassLoader().
                getResourceAsStream("druid.properties");

        //将资源文件输入流对象加载到属性列表中
        prop.load(inputStream);
        System.out.println(prop);

        //创建DruidDataSource对象
        //protected DataSource createDataSourceInternal(Properties properties) throws Exception
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        System.out.println(dataSource) ;
        //就可以连接池中获取连接对象
        //DataSource---->getConnection()--->Connections
      /*  Connection connection = dataSource.getConnection();
        Connection connection2 = dataSource.getConnection();
        System.out.println(connection);
        System.out.println(connection2);*/
        for(int x = 1 ; x <=11 ; x++){
            Connection connection = dataSource.getConnection();
            if(x==3){
                connection.close(); //不是释放,此时将第三个连接对象归还给连接池,有一个没有激活,第11个连接池对就可以获取到了
            }
            System.out.println(connection);
        }

    }
}

Druid封装工具类

package com.qf.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * 加入连接池Druid工具类的封装
 * 模拟真实场景---->高并发情况下,每一个线程的连接对象应该使用自己的连接对象---->
 * 来自于连接池! jdk提供了这个类ThreadLocal<Connection>
 */
public class JdbcUtils_WithDruid {

    //成员变量的位置
    private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ;//类一加载,创建线程
    private static DataSource ds ; //数据源---->里面空的
    //无参构造方法私有化
    private JdbcUtils_WithDruid(){}
    //静态代码块
    static{
        try {
            //1)读取src下面的 德鲁伊的配置文件
            //创建集合列表
            Properties prop = new Properties() ;
            //读取druid.properties
            InputStream inputStream = JdbcUtils_WithDruid.class.getClassLoader().
                    getResourceAsStream("druid.properties");

            //将资源文件输入流中的内容加载到属性列表中
            prop.load(inputStream);
            System.out.println(prop);

            //2)将配置文件进行加载---DruidDataSource自动封装这些7个参数
            //通过DruidDataSourceFactory 创建数据源
            ds = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //定义方法----获取数据源的方法
    public static DataSource getDataSource(){
        return  ds ;
    }

    //定义一个获取连接对象
    public static Connection getConnection(){
        Connection conn = null ;
        try {
            //现在模拟多线程场景
            //1)从当前线程获取连接对象   ThreadLocal<Connection>----> Connection get()
           conn  = t1.get();
            //2)判断当前线程中的连接对象如果为null,
            if(conn==null){
                //说明没有连接对象
                //从连接池中获取连接对象
                Connection connection = ds.getConnection();
                //将连接池获取连接对象,绑定在当前线程中
                //ThreadLocal<Connection>----> set(Connection conn)
                t1.set(connection);
                return connection ;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  conn ;

    }

    //close()------------------>后面不用写了

    /**
     * 释放资源 针对DQL语句,select语句
     * @param rs  释放结果集对象
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(ResultSet rs, Statement stmt, Connection conn){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();//释放--->归还给连接池
                //从当前线程中解绑
                //ThreadLocl--->remove()
                t1.remove();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 释放资源,针对DML语句:update,delete,insert操作的
     * @param stmt 释放执行对象
     * @param conn 释放连接对象
     */
    public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);//复用上面的close,第一个参数为null
    }


    public static void main(String[] args) {
        DataSource dataSource = JdbcUtils_WithDruid.getDataSource();
        System.out.println(dataSource);

        Connection connection = JdbcUtils_WithDruid.getConnection();
        System.out.println(connection);
    }
}

学生数据访问接口

package com.qf.dao;

import com.qf.pojo.Student;

import java.sql.SQLException;
import java.util.List;

/**
 * 针对学生的数据访问接口
 *
 * DAO----> Data Access Object:数据访问对象----->jdbc的操作
 * service---->业务服务层----->  业务逻辑判断--if...else...一些具体的业务上的代码
 */
public interface StudentDao {

    /**
     * 查询所有学生
     * @return 返回的学生列表,里面记录每一个学生实体
     */
    List<Student>  findAll() throws SQLException;


    /**
     * 模糊查询
     * @param name  查询的姓名
     * @return  返回学生列表
     */
    List<Student> findStudentByName(String name) throws SQLException;

    /**
     * 通过学生编号查询学生实体
     * @param id  学生编号
     * @return 返回学生实体
     */
    Student findStudentById(int id) throws SQLException;


    /**
     * 添加学生
     * @param student 学生实体
     * @return 返回值,影响的行数
     */
    int registerStudent(Student student) throws SQLException;
}

学生数据访问接口实现类

package com.qf.dao.impl;

import com.qf.dao.StudentDao;
import com.qf.pojo.Student;
import com.qf.utils.JdbcUtils;
import com.qf.utils.JdbcUtils_WithDruid;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 针对学生的数据访问接口实现
 */
public class StudentDaoImpl  implements StudentDao {
    /**
     * 查询所有学生
     * @return 返回的学生列表,里面记录每一个学生实体
     */
    @Override
    public List<Student> findAll() throws SQLException {
        //JDBC操作
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "select * from student" ;
        //获取预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);//发送sql到数据库
        //直接查询
        ResultSet rs = ps.executeQuery();
        //创建一个集合
        List<Student> list = new ArrayList<>() ;
        //声明学生变量
        Student s =null ;
        //遍历结果集
        while(rs.next()){
            //创建学生实体
            s = new Student() ;
            //封装学生数据
            s.setId(rs.getInt("id"));
            s.setName(rs.getString("name"));
            s.setAge(rs.getInt("age"));
            s.setGender(rs.getString("gender"));
            s.setAddress(rs.getString("address"));

            //将学生对象添加集合中
            list.add(s) ;
        }
        //释放资源
        JdbcUtils.close(rs,ps,conn);
        return list;
    }

    /**
     * 模糊查询
     * @param name  查询的姓名
     * @return  返回学生列表
     */
    @Override
    public List<Student> findStudentByName(String name) throws SQLException {
        //JDBC操作
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "select * from student where name like ?" ;//参数化的sql
        //获取预编译对象
        PreparedStatement ps = conn.prepareStatement(sql);//发送sql到数据库,将编译sql存储到预编译对象中
        //参数赋值
        ps.setString(1,name);//测试的时候 name就是 '%王%'

        //直接查询
        ResultSet rs = ps.executeQuery();
        //创建一个集合
        List<Student> list = new ArrayList<>() ;
        //声明学生变量
        Student s = null ;
        while(rs.next()){
            s = new Student() ;
            //封装学生数据
            //封装学生数据
            s.setId(rs.getInt("id"));
            s.setName(rs.getString("name"));
            s.setAge(rs.getInt("age"));
            s.setGender(rs.getString("gender"));
            s.setAddress(rs.getString("address"));

            //将学生对象添加集合中
            list.add(s) ;
         }
        //释放资源
        JdbcUtils.close(rs,ps,conn);

        return list;
    }


    /**
     * 通过学生编号查询学生实体
     * @param id  学生编号
     * @return 返回学生实体
     */
    @Override
    public Student findStudentById(int id) throws SQLException {
        //获取连接
        Connection conn = JdbcUtils.getConnection();
        //参数化的sql
        String sql = "select * from student where id = ?" ;
        //获取预编译对象并同时将参数化的sql发送给数据库
        PreparedStatement ps = conn.prepareStatement(sql);
        //参数赋值
        ps.setInt(1,id);
        Student s = null ;
        //执行查询
        ResultSet rs = ps.executeQuery();
        while(rs.next()){
            //创建学生对象
            s = new Student() ;
            //封装数据
            s.setId(rs.getInt("id"));
            s.setName(rs.getString("name"));
            s.setAge(rs.getInt("age"));
            s.setGender(rs.getString("gender"));
            s.setAddress(rs.getString("address"));
        }
        //释放资源
        JdbcUtils.close(rs,ps,conn);
        return s;
    }

    /**
     * 添加学生
     * @param student 学生实体
     * @return 返回值,影响的行数
     */
    @Override
    public int registerStudent(Student student) throws SQLException {
        //获取连接
      //  Connection conn = JdbcUtils.getConnection();

        //直接使用最终的工具类
        Connection conn = JdbcUtils_WithDruid.getConnection();

        //参数化的sql
        String sql = "insert into student(name,age,gender,address) values(?,?,?,?)" ;

        //获取预编译对象并同时将参数化的sql发送给数据库
        PreparedStatement ps = conn.prepareStatement(sql);
        //参数赋值
        ps.setString(1,student.getName());
        ps.setInt(2,student.getAge());
        ps.setString(3,student.getGender());
        ps.setString(4,student.getAddress());

        //执行更新
        int count = ps.executeUpdate();

        //释放资源
        JdbcUtils.close(ps,conn);
        return count;
    }
}

针对学生数据接口进行测试?

package com.qf.test;

import com.qf.dao.StudentDao;
import com.qf.dao.impl.StudentDaoImpl;
import com.qf.pojo.Student;
import org.junit.Before;
import org.junit.Test;

import java.sql.SQLException;
import java.util.List;

/**
 * 针对学生的接口进行单元测试
 */
public class StudentTest {
    private StudentDao sd ;
    @Before
    public void init(){
        sd = new StudentDaoImpl() ;
    }
    //测试查询所有
    @Test
    public void testFindAll() throws SQLException {
        List<Student> students = sd.findAll();
        if(students!=null){
            for(Student s:students){
                System.out.println(s);
            }
        }
    }


    //测试模糊查询
    @Test
    public void testFindStudentByName() throws SQLException {
        List<Student> students = sd.findStudentByName("%王%") ;
        if(students!=null){
            for(Student s:students){
                System.out.println(s);
            }
        }
    }

    //测试通过学生编号查询指定的学生
    @Test
    public void testFindStudentById() throws SQLException {

        Student student = sd.findStudentById(7);
        if(student!=null){
            System.out.println(student);
        }
    }

    //测试添加学生信息
    @Test
    public void testAddStudent() throws SQLException {

        //创建学生对象
        Student student = new Student() ;
        student.setName("李帅") ;
        student.setAge(25);
        student.setGender("男");
        student.setAddress("灞桥") ;
       sd.registerStudent(student) ;
    }
}

Dbutils

Apache? 提供的工具类库? commons-Dbutils? ,针对原始JDBC操作七大步骤的简易封装, 简化代码书写量,提高开发效率

导入common-dbutils.jar包

Apache-dbutils官网

关于DBuitls三个常用的实现类,以及使用

BeanListHandler<T>: 将数据库查询的多条数据记录---->封装list<T>集合中

BeanHandler<T>:? ? ? ?将数据查询的某条信息----->封装某个实体类中

ScalarHandler<T>:? 将数据库查询的记录--->封装到Object类中--->返回单行单列的数据(聚合函数)---->查询总记录数

案例3

配置属性文件

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
username=root
password=*********
initialSize=5
maxActive=10
maxWait=3000

dbutils封装druid(德鲁伊)工具类?

package com.qf.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;


public class DruidJdbcUtils {
    //多个用户同时访问数据库

    //模拟线程
    private static ThreadLocal<Connection> tl = new ThreadLocal<>() ;
    private static DataSource ds ;
     //无参构造私有化
    private DruidJdbcUtils(){}

    //静态代码块
    static{
        try {
            //1)读取配置文件
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //2)创建属性集合列表Properties ---将资源文件所在的输入流的内容加载到属性列表中
            Properties prop = new Properties() ;
            prop.load(inputStream);
            //3)通过DruidDataSourceFactory:数据源工厂创建DataSource 连接池(数据源)
            ds = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据源
    public static DataSource getDataSource(){
        return  ds ;
    }

    //获取连接对象
    public static Connection getConnection(){

        try {
            //1)从当前线程中获取连接对象
            Connection conn = tl.get();
            if(conn == null){
                //从DataSource 连接池获取连接对象
                conn = ds.getConnection() ;
                //在将conn连接对象绑定当前线程中
                tl.set(conn);
            }
            return conn ;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;

    }

    //关闭资源----不需要了--- Commons-Dutils.jar包--->QueryRunner---执行对象--->会自动释放资源

    public static void main(String[] args) {
        System.out.println(DruidJdbcUtils.getDataSource());
        Connection connection = DruidJdbcUtils.getConnection();
        System.out.println(connection);
    }

}

学生实体类

package com.qf.pojo;

/**
 * 学生类
 */
public class Student {
    private int id ;
    private String name ;
    private int age ;
    private String gender;
    private String address ;


    public Student() {
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

学生数据访问接口

package com.qf.dao;

import com.qf.pojo.Student;

import java.sql.SQLException;
import java.util.List;

/**
 * 针对学生的数据访问接口
 */
public interface StudentDao {

    /**
     * 查询所有学生
     * @return 返回学生列表
     */
    List<Student> findAll() throws SQLException;

    /**
     * 通过学生编号查询学生信息
     * @param id  学生编号
     * @return 返回学生实体
     */
    Student findStudentById(int id) throws SQLException;

    /**
     * 添加学生
     * @param student 学生实体
     * @return 返回影响的行数
     */
    int addStudent(Student student) throws SQLException;

    /**
     * 查询总记录数
     * @return 返回的总条数信息
     */
    int selectTotalCount() throws SQLException;


    /**
     * 修改学生信息
     * @param student 学生实体
     * @return 返回影响的行数
     */
    int updateStudent(Student student) throws SQLException;


}

学生数据访问接口实现类

package com.qf.dao.impl;

import com.qf.dao.StudentDao;
import com.qf.pojo.Student;
import com.qf.utils.DruidJdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;
import java.util.List;

/**
 * 针对学生的数据访问接口
 *
 *
 * //common-Dbutils的使用步骤
 * 1)导入dbutils.jar包
 * 2)创建执行对象
 *      public QueryRunner(DataSource ds)----->自动提交方式 (前期都用这个)
 *      public QueryRunner() ----->空参构造---手动提交(牵扯事务的是用)
 * 3)准备sql语句  update/delete/insert  /select...
 * 4)执行
 *      QueryRunner针对update/delete/insert----通用方法
 *           int update(String sql,Object[]...params):参数1:sql语句   参数2:就是可变参数,给占位符赋值 (属于自动提交更新)
 *           int update(Connection conn,String sql,Object[]...params) 更新方法
 *
 *
 *       //通用的查询方法
 *       public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
 *       //参数1:sql语句
 *       //参数2:结果集的处理---接口--->需要子实现类
 *                      BeanListHandler<T> :将数据库查询的多条记录--->封装List<T>集合中
 *                      BeanHandler<T>:将数据库中查询的某条记录---->封装某个实体类中
 *                      ScalarHandler<T>:将数据库查询的记录--->封装Object类中---返回的数据单行单列的数据(聚合函数)---->查询总记录数
 *       //参数3:可变参数,在select语句如果有条件查询,传入条件值;如果没有参数,不需要传!
 *
 *
 *
 *
 */
public class StudentDaoImpl  implements StudentDao {

    /**
     * 查询所有学生
     * @return 返回学生列表
     */
    @Override
    public List<Student> findAll() throws SQLException {
        // public QueryRunner(DataSource ds)
        //1)创建执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;

        //2)准备sql语句
        String sql = "select * from student" ;
        //3)执行查询
        // BeanListHandler<T> :将数据库查询的多条记录--->封装List<T>集合中
        //public BeanListHandler(Class<T> type)
        List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class));

        return list;
    }

    /**
     * 通过学生编号查询学生信息
     * @param id  学生编号
     * @return 返回学生实体
     */
    @Override
    public Student findStudentById(int id) throws SQLException {
        //创建执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "select * from student where id = ?" ;
        //查询---执行
        // BeanHandler<T>:将数据库中查询的某条记录---->封装某个实体类中
        //public BeanHandler(Class<T> type) :参数就是当前存储类型的字节码文件
        Student student = qr.query(sql, new BeanHandler<Student>(Student.class), id);
        return student;
    }

    /**
     * 添加学生
     * @param student 学生实体
     * @return 返回影响的行数
     */
   
    @Override
    public int addStudent(Student student) throws SQLException {
        //创建执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "insert into student(name,age,gender,address) values(?,?,?,?)" ;
        //更新操作
        //  int update(String sql,Object[]...params):参数1:sql语句   参数2:就是可变参数,给占位符赋值 (属于自动提交更新)
        int count = qr.update(sql,
                student.getName(),
                student.getAge(),
                student.getGender(),
                student.getAddress());
        return count;

    }

    /**
     * 查询总记录数
     * @return 返回的总条数信息
     */
    @Override
    public int selectTotalCount() throws SQLException {
        //创建执行对象
        QueryRunner qr  = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "select count(id) from student" ;
        //执行查询
//        ScalarHandler<T>:将数据库查询的记录--->封装Object类中---返回的数据单行单列的数据(聚合函数)
//        ---->查询总记录数
        // public ScalarHandler() 空参构造
        Object obj = qr.query(sql, new ScalarHandler<>());

        //Object--->String---->Integer---->int
       // String str = String.valueOf(obj);
       // int totalCount = Integer.parseInt(str);

        int totalCount = Integer.parseInt(String.valueOf(obj));

        return totalCount;
    }


    /**
     * 修改学生信息
     * @param student 学生实体
     * @return 返回影响的行数
     */
    @Override
    public int updateStudent(Student student) throws SQLException {
        //执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "update student set name = ?,age=?,gender=?,address = ? where id = ?" ;
        //执行更新
        int count = qr.update(sql,
                student.getName(),
                student.getAge(),
                student.getGender(),
                student.getAddress(),
                student.getId());
        return count;
    }


}

学生数据测试类

package com.qf.test;

import com.qf.dao.StudentDao;
import com.qf.dao.impl.StudentDaoImpl;
import com.qf.pojo.Student;
import org.junit.Before;
import org.junit.Test;

import java.sql.SQLException;
import java.util.List;

/**
 * 单元测试
 */
public class Dbutils_Test {
    private StudentDao sd ;
    @Before
    public void init(){
        sd = new StudentDaoImpl() ;
    }

    //测试查询所有
    @Test
    public void testFindAll() throws SQLException {
        List<Student> students = sd.findAll();

        if(students!=null){
            for(Student s:students){
                System.out.println(s);
            }
        }
    }

    //测试指定的学生信息
    @Test
    public void testFindStudentById() throws SQLException {
        Student student = sd.findStudentById(1);

        System.out.println(student);
    }

    //测试添加学生
    @Test
    public void testAddStudent() throws SQLException {
        //创建学生
        Student s = new Student() ;
        s.setName("刘亦菲") ;
        s.setAge(30);
        s.setGender("女");
        s.setAddress("西安市");
        int count = sd.addStudent(s);
        System.out.println(count);

    }

    //测试查询总记录数
    @Test
    public void testSelectTotalCount() throws SQLException {
        int count = sd.selectTotalCount();
        System.out.println(count);
    }

    //测试修改学生
    @Test
    public void testUpdate() throws SQLException {
        Student s = new Student() ;
        s.setName("梁朝伟") ;
        s.setAge(50);
        s.setGender("男") ;
        s.setAddress("香港");
        s.setId(11);
        int count = sd.updateStudent(s) ;
        System.out.println(count);
    }

}

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:04:35  更:2022-09-15 02:06:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年5日历 -2025/5/2 8:22:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码