Java学习笔记-3

本文详细介绍了Java的枚举、注解和反射机制,包括内置注解、元注解和自定义注解的使用。此外,还深入探讨了Java反射的应用,如通过Class获取构造方法创建对象和调用方法。接着,文章转向数据库操作,讲解了SQL的基础知识,如查询、排序、聚合函数、分组和子查询。最后,涉及了数据库事务、并发问题及JDBC的使用,包括事务的ACID特性、连接池的概念以及JDBC工具类的封装。
摘要由CSDN通过智能技术生成

枚举、注解、反射👊

1.枚举

注意事项:

在这里插入图片描述

2.注解

目前来说,注解最重点的部分在于学会如何使用注解。

关于自定义注解这一部分,只有在你开发框架时才会大量使用自定义注解。

注解主要用于:

  1. 编译格式检查
  2. 反射中解析
  3. 生成帮助文档
  4. 跟踪代码依赖
2.1内置注解
  • @Override:重写。用于编译格式检查***

    • 定义在java.lang.Override
  • @Deprecated:废弃。***

    • 定义在java.lang.Deprecated
  • @SafeVarargs (很少使用)

    • Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface: 函数式接口 ***

    • Java 8 开始支持,标识一个匿名函数或函数式接口。即:可以使用lambda表达式来使用的意思。
  • @Repeatable:标识某注解可以在同一个声明上使用多次 (很少使用)

    • Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
  • @SuppressWarnings(“all”) 抑制编译时的警告信息***

    • (例如,定义的变量或者方法没有使用就会发出警告,使用这个注解就可以取消这些警告。参数all代表忽略所有类型的警告)
2.2元注解

给注解加的注解。

元注解包括:
在这里插入图片描述

2.3自定义注解

这里只是简单的一个示例,没有涉及到反射。通常自定义注解是配合反射来使用。

import java.lang.annotation.*;

//括号中默认是value的值
@MyAnnotation("张三")
public class AnnotationTest {
    public static void main(String[] args) {

    }
    public void hh(){ }
}

//下面是一个自定义注解的示例

//注解可以加在哪些地方,type是类,method是方法
@Target({ElementType.TYPE,ElementType.METHOD})
//表示注解可以被继承,即父类中加注解,子类也会继承这个注解
@Inherited
//标记这些注解是否包含在用户文档中 javadoc
@Documented
//注解保存的位置,范围是source、class、runtime。三个位置是包含关系。
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    //给一个默认值,若没有传入值则为默认值
    String value() default "李四";
    int num() default 1;
}
3.反射(java高级特性)

了解框架底层必须深入理解反射机制。

三种类加载器,双亲委派机制。

在Java中,每一个字节码文件,被加载到内存后,都存在一个对应的Class类型的对象

3.1三种获取Class的方式
  1. 类名.class
  2. 对象.getclass()
  3. Class.forName(“包名.类名”);

前两种是根据一个已存在的类或对象,

上述的三种方式, 在调用时, 如果类在内存中不存在, 则会加载到内存 ! 如果类已经在内存中存在, 不 会重复加载, 而是重复利用 ! (一个class文件 在内存中不会存在两个类对象 )

通过class获取构造方法创建对象,以及通过class获取所有方法的示例如下:(获取字段也是类似的操作,示例中没有演示获取字段)

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.AccessException;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //在main方法中分别测试下面三个方法
        getMethodTest();
    }
    /**
     * 获取一个类的Class三种方式
     * */
    static void clasTest() throws ClassNotFoundException {
        Class<Person> c1 = Person.class;
        System.out.println(c1);
        Person p = new Person();
        Class<Person> c2 = (Class<Person>) p.getClass();
        System.out.println(c1==c2);
        Class<Person> c3 = (Class<Person>) Class.forName("com.zhp.reflect.Person");
        System.out.println(c1==c3);
    }
    /**
     * 获取到Class后,根据这个Class创建对象
     * */
    static void createInstanceTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Person> pClass = (Class<Person>) Class.forName("com.zhp.reflect.Person");

        Constructor<Person> c1 = pClass.getConstructor();
        Person p1 = c1.newInstance();
        System.out.println(p1);

        Constructor<Person> c2 = pClass.getConstructor(String.class, int.class);
        Person p2 = c2.newInstance("张三",20);
        System.out.println(p2);

        Constructor<Person> c3 = pClass.getDeclaredConstructor(String.class);
        c3.setAccessible(true);
        Person p3 = c3.newInstance("李一百");
        System.out.println(p3);
    }
    /**
     * 获取到Class后,根据Class获取类的方法,并调用方法
     * */
    static void getMethodTest() throws Exception{
        Class<?> pClass = Class.forName("com.zhp.reflect.Person");
        //获取一个空的构造方法
        Constructor<?> c = pClass.getConstructor();
        //构造一个对象,没有初始值
        Object o = c.newInstance();
        //根据方法名和参数列表获取这个类的方法,getMethod只能获取public的方法
        Method setName = pClass.getMethod("setName", String.class);
        //执行此方法,参数1是执行此方法的对象,参数2是此方法的参数
        setName.invoke(o,"李四");
        
        //getDeclaredMethod可以获取所有权限的方法
        Method setAge = pClass.getDeclaredMethod("setAge", int.class);
        //获取到私有方法后需调用setAccessible(true),忽略权限检查,否则无法执行
        setAge.setAccessible(true);
        setAge.invoke(o,20);
        //输出结果是:Person{name='李四', age=20}
        System.out.println(o);
    }
}
public class Person{
    private String name;
    private int age;

    public Person() {
    }
    private Person(String name){
        this.name = name;
        this.age = 100;
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }
    //这里把setage设置为私有,测试通过class获取私有方法
    private void setAge(int age) {
        this.age = age;
    }
}

Mysql初级

先说一下mysql启动失败的情况:

在mysql目录下的bin目录中,打卡cmd,输入mysqld --console。查看具体的失败原因。

总结一些通用的可能的解决办法:

  1. 将my.ini改为ansi编码格式(因为有可能是因为utf-8编码出错)。
  2. 修改my.ini配置文件,具体如下。
[mysqld]
#设置3306端口号
port=3306
#设置MySQL的安装目录
basedir=Z:\\Program Files\\mysql\\mysql-8.0.19-winx64
#设置MySQL数据库的数据存放目录
datadir=Z:\\Program Files\\mysql\\mysql-8.0.19-winx64\\data
#运行最大连接数
max_connections=200
#运行连接失败的次数。这也是为了防止有人从该主机试图攻击数据库系统
max_connect_errors=10
#服务端使用的字符集默认为utf-8
character-set-server=utf8
[mysql]
#客户端使用的字符集默认为utf8
default-character-set=utf8
[client]
#客户端默认端口号为3306
port=3306
1.little cookie

范围查询,in

例如:SELECT * FROM stu WHERE sid IN (‘S_1001’,‘S_1002’,‘S_1003’);

其他一些注意的地方:

  1. 不在范围则是not in

  2. 查询等于null:is null而不是=null。

  3. 不等于null:is not null

  4. between xx and xx 包含边界值。

distinct去重

例如: select distinct gender from stu;

gender为需要去重的列。

like模糊查询

_代表任意一个字符,%代表任意长度的任意字符

ifnull(列名,值)函数如果是null则当作值来用,例如:

select sal+ifnull(comm,0) from emp2;

//将计算sal+comm的值,如果comm为null则当作0。

where–>group by–>having–>order by

2.排序

order by 列名 asc/desc

asc 升序 desc 降序 默认不写的话是升序

多列排序:例如:

SELECT * FROM emp ORDER BY sal DESC,empno ASC;

首先将按照sal降序排列,如果相等则对相等的部分使用第二个排序规则(根据empno升序排列)进行排列,

3.聚合函数

聚合函数是用来做纵向运算的。

  1. COUNT(列名):统计指定列不为NULL的记录行数;
  2. MAX(列名):计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
  3. MIN(列名):计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
  4. SUM(列名):计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
  5. AVG(列名):计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;
4.group by

查询每个部门的部门编号以及每个部门工资大于1500的人数:(sal为工资,deptno为部门编号)

select deptno,count(*) from emp2 where sal>1500 group by deptno;

having:不能单独出现,只能用在group by后面,对group后进行条件限定,例如:

//查询到每个部门的工资总和

SELECT deptno, SUM(sal) FROM emp GROUP BY deptno;

//对每个部门的工资总和进行条件筛选

SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal) > 9000;

查询工资总和大于9000的部门编号以及工资和:

注:having与where的区别:

  1. having是在分组后对数据进行过滤,where是在分组前对数据进行过滤
  2. having后面可以使用分组函数(统计函数) where后面不可以使用分组函数。

WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分 组;而HAVING是对分组后数据的约束。

5.limit

用来限定查询结果的起始行和行数。

limit 0,10

从第1条数据开始,共10条数据。

也可以写作

limit 10,

代表查询10条数据,默认是从0开始

Mysql高级

1.完整性
  1. 实体完整性

    • primary key(主键):不能为空,唯一,不能重复

    • 创建完表后设置主键的方式:

      ALTER TABLE student ADD PRIMARY KEY (id);

    • unique key(唯一约束):可以为空,唯一吗,不能重复

    • auto_increment(自增长):一般给主键设置自动增长,自增长只能应用于int类型。

  2. 域完整性

    • 数据类型
    • not null(非空约束)
    • default(默认值约束)
    • check约束(mysql不支持):例如:check(sex=‘男’ or sex=‘女’)
  3. 引用完整性

    • 外键约束:foreign key

    • 创建完表后的添加外键的方式:

      ALTER TABLEscore1 ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES stu(id);

2.多表的关系
  1. 一对多/多对多

    一对多建表原则:在多的一方创建一个字段,字段作为外键指向一的一方的主键

  2. 多对多

    通常情况下,表之间不使用外键,虽然外键可以保证数据的正确性,但是外键会降低性能,而且通常作为外键的列通常是程序员赋值的(不是由用户输入的),一般不会出现错误。

    多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一 方的主键.例如学生表和课程表,联合这两张表需要第三张表如下:

在这里插入图片描述

  1. 一对一

    如丈夫-妻子。

    建表原则:

    比如可以:在丈夫表中添加妻子的主键id,并设置为unique。

    还可以:将丈夫的主键id设置为外键关联妻子的主键id,

3.多表查询

多表查询分类:

  1. 合并结果集:union、union all:前者去重、后者不去重。被合并的两个结果:列数、列类型必须相同
  2. 连接查询
    • 内连接:inner join
    • 外连接
      • 左外连接:left join
      • 右外连接:right join
      • 全外连接(mysql不支持):full join
    • 自然连接:nature join
  3. 子查询

其中连接查询和子查询是重点。

3.1连接查询

内连接:连接共有的部分,不是共有的部分不显示。

通常左/右连接一般会作为子查询的语句使用

左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的 显示NULL。

右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。

#一对多的实现
#创建分类表
create table category(
cid varchar(32) PRIMARY KEY , # 分类id
cname varchar(100) #分类名称
);
# 商品表
CREATE TABLE `products` (
`pid` varchar(32) PRIMARY KEY , #商品id
`name` VARCHAR(40) , #商品名称
`price` DOUBLE, # 价格
category_id varchar(32) # 分类id,外键列
);
#多对多的实现
#用户表
create table users(
userid int,
username varchar(20),
upass varchar(20)
)
#订单表
create table `orders`(
`oid` varchar(32) PRIMARY KEY , #订单id
`totalprice` double, #总计
uid int # 用户id
);
# 订单项表
create table orderitem(
oid varchar(50), #订单id
pid varchar(50) #商品id
);
#初始化数据
#给分类表初始化数据
insert into category values('c001','电器');
insert into category values('c002','服饰');
insert into category values('c003','化妆品');
insert into category values('c004','书籍');
#给商品表初始化数据
insert into products(pid,name,price,category_id) values('p001','联
想',5000,'c001');
insert into products(pid,name,price,category_id) values('p002','海
尔',3000,'c001');
insert into products(pid,name,price,category_id) values('p003','雷
神',5000,'c001');
insert into products(pid,name,price,category_id) values('p004','JACK
JONES',800,'c002');
insert into products(pid,name,price,category_id) values('p005','真维
斯',200,'c002');
insert into products(pid,name,price,category_id) values('p006','花花公
子',440,'c002');
insert into products(pid,name,price,category_id) values('p007','劲
霸',2000,'c002');
insert into products(pid,name,price,category_id) values('p008','香奈
儿',800,'c003');
insert into products(pid,name,price,category_id) values('p009','相宜本
草',200,'c003');
insert into products(pid,name,price,category_id) values('p010','梅明
子',200,null);

3.1 综合练习-【多表查询】

​ 1>查询用户的订单,没有订单的用户不显示

​ selcet * from users u

​ right join order o

​ on u.userid=o.uid

​ 2>查询所有用户的订单详情

​ select * from users u

​ inner join orders o

​ on u.userid=o.uid

​ 3>查询所有订单的用户详情

​ selcet * from orders o

​ left join users u

​ on u.userid=o.uid

3.2 综合练习2-【子查询】

​ 1>查看用户为张三的订单详情

​ select * from order where uid=(select uid from users where username=‘张三’);

​ 2>查询出订单的价格大于300的所有用户信息。

​ select * from users where userid in (select DISTINCT uid from orders where totalprice>300);

​ 3>查询订单价格大于300的订单信息及相关用户的信息。

3.2 综合练习3-【分页查询】

​ 1>查询所有订单信息,每页显示5条数据

4.扩展
  1. 多行操作(多行新增/修改/删除)
  2. 日期运算函数
    • now(),获取当前系统时间
    • year(),获取年份,例如year(now());
    • date_add(日期,interval 计算值 计算的字段); 注:计算值大于0表示往后推日期,小于0表示往前推日期 示例: date_add(now(),interval -40 year);//40年前的日期
5.数据库优化(sql优化)

在这里插入图片描述

Mysql进阶

1.事务

begin开始

insert into stu values(1,’zs’);//此时数据仅仅临时性保存,并未永久保存到数据库中,只有在commit后才会永久保存

rollback;//rollback代表回滚,将撤销之前的操作,注意:回滚只能在commit之前进行,一旦commit就无法进行回滚操作。

commit; //commit代表提交,数据将永久性的保存到数据库中

2.事务特性ACID
  • 原子性(一个事务中的操作要么都成功,要么都失败)

  • 一致性(当事务中一个操作失败后,所有的更改过的数据都必须回滚到修改前的状态。例如a转账给b,a的钱少了,但b的钱没有增加,就违背了一致性)

  • 隔离性(多个线程之间互不影响)

  • 持久性(一旦commit数据就永久保存)

3.事务的并发问题
  • 脏读:一个事务读取了另外一个未提交的数据。
  • 不可重复读:一个事务读取一条数据后,另外的事务对此数据进行了修改(update),导致这个事务再次读取这条数据发现两次读取数据内容不一致。
  • 幻读:一个事务读取一个数据集,另外的事务对此数据集进行了插入或删除(insert/delete),导致这个事务再次读取数据集时读取的数据量不一致。
4.事务的隔离级别

在这里插入图片描述

从上至下,级别增高。隔离级别等级越低,安全性越低,效率越高;隔离级别等级越高,安全性越高,效率越低。

通常数据库默认的级别时读已提交或者可重复读。

可以通过命令查看或设置当前会话中的隔离级别。

5.jdbc
5.1结构

在这里插入图片描述

5.2核心组件

在这里插入图片描述

5.3jdbc一个示例
//状态通道,存在sql注入风险
public class JdbcTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        String username = "root";
        String pwd = "123456";
        String url = "jdbc:mysql://localhost:3306/demo?serverTimezone=UTC";
        //获取连接
        Connection c = DriverManager.getConnection(url, username, pwd);
        //获取statement
        Statement s = c.createStatement();
        String sql = "select * from products";
        //查询使用executeQuery,增删改使用executeUpdate
        ResultSet resultSet = s.executeQuery(sql);
        while (resultSet.next()){
            System.out.println("商品名称是:"+resultSet.getString("name")+",价格是:"+resultSet.getString("price"));
        }
        resultSet.close();
        s.close();
        c.close();

    }
}
import java.sql.*;
//预状态 防止sql注入
public class PrepareStatementTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        String username = "root";
        String pwd = "123456";
        String url = "jdbc:mysql://localhost:3306/demo?serverTimezone=UTC";
        Connection c = DriverManager.getConnection(url, username, pwd);
        String sql = "select * from users where username=? and upass=?";
        PreparedStatement pps = c.prepareStatement(sql);
        pps.setString(1,"张三");
        pps.setString(2,"123");

        //查询使用executeQuery,增删改使用executeUpdate
        ResultSet resultSet = pps.executeQuery();
        if (resultSet.next()) {
            System.out.println("登录成功!");
        }else {
            System.out.println("登录失败!");
        }
        resultSet.close();
        pps.close();
        c.close();
    }
}

  1. 预状态通道会先编译sql语句,再去执行,效率比状态通道高。
  2. 预状态通道可以使用占位符?,位置从1开始
  3. 预状态通道可以防止sql注入

其他:

  1. jdbc中默认是自动提交事务的,如果要关闭自动提交,可以通过connection的setAutoCommit(false)来关闭自动提交事务。
  2. 要想使多个(insert/update/delete)sql语句同时生效需要取消事务的自动提交,应该使用手动提交事务,确保多个语句同时执行成功或者同时执行失败。例如:银行转账就是一个需要同时成功或者同时失败的场景。在一个事务中,成功了就提交,否则就就回滚。
  • Talk is cheap,show me code

dao层编写示例:(单纯的从jdbc的使用角度来编写)

package com.zhp.dao.impl;

import com.zhp.bean.Student;
import com.zhp.bean.Teacher;
import com.zhp.dao.TeacherDao;

import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class TeacherDaoImpl implements TeacherDao {
    @Override
    public Teacher getById(int tid) {
        Connection c = null;
        PreparedStatement pps = null;
        ResultSet resultSet = null;
        try {
            //加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            String username = "root";
            String pwd = "123456";
            String url = "jdbc:mysql://localhost:3306/demo2?serverTimezone=UTC";
            c = DriverManager.getConnection(url, username, pwd);
            String sql = "select * from teacher t,student s where t.tid=s.tid and t.tid=?";
            pps = c.prepareStatement(sql);
            pps.setInt(1,tid);
            //查询使用executeQuery,增删改使用executeUpdate
            Teacher t = new Teacher();
            resultSet = pps.executeQuery();
            ArrayList<Student> students = new ArrayList<>();
            //遍历结果集,将结果集中的数据取出并set给相应的对象
            while (resultSet.next()){
                //根据列名手动调用set方法赋值
                //下面一个方法将示例如何使用反射调用set方法赋值,无需手动指定列名
                t.setName(resultSet.getString("name"));
                t.setTid(tid);
                Student s = new Student();
                s.setSname(resultSet.getString("sname"));
                s.setSid(resultSet.getInt("sid"));
                s.setTid(resultSet.getInt("tid"));
                students.add(s);
            }
            t.setStudents(students);
            return t;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                resultSet.close();
                pps.close();
                c.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 反射处理结果集
     * */
    @Override
    public List getAllStudent(Class cla) {
        Connection c = null;
        PreparedStatement pps = null;
        ResultSet resultSet = null;
        try {
            //加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            String username = "root";
            String pwd = "123456";
            String url = "jdbc:mysql://localhost:3306/demo2?serverTimezone=UTC";
            c = DriverManager.getConnection(url, username, pwd);
            String sql = "select * from student";
            Statement s = c.createStatement();
            //获取结果集,至此操作步骤与之前一致
            ResultSet res = s.executeQuery(sql);
            //获取resultset的信息
            ResultSetMetaData metaData = res.getMetaData();
            //获取列的数量
            int columnCount = metaData.getColumnCount();
            String[] column = new String[columnCount];
            //把每一列的名称赋值到数组中
            for (int i = 0; i < columnCount; i++) {
                column[i] = metaData.getColumnName(i+1);
            }
            //return 的结果
            ArrayList list = new ArrayList();

            //根据Class获取所有的方法	
            Method[] declaredMethods = cla.getDeclaredMethods();
            while (res.next()){

                Object stu = cla.getConstructor().newInstance();
                for (String s1 : column) {
                    String methodName = "set"+s1;
                    for (Method declaredMethod : declaredMethods) {
                        if (declaredMethod.getName().equalsIgnoreCase(methodName)){
                            declaredMethod.invoke(stu,res.getObject(s1));
                            break;
                        }
                    }
                }
                list.add(stu);
            }

            return list;
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return null;
    }

}

每次操作数据库都要先创建连接,等一系列操作,非常麻烦,我们可以把这些创建连接等操作封装起来,便于使用。同时,把username、password、url、driverName单独编写在一个db.properties文件中,便于管理这些数据,通过读取这些配置完成连接。

5.4封装jdbc工具类以及连接池的使用

连接池:(使用前先导包)

每次连接数据库操作数据都要创建连接,非常浪费性能,我们可以创建一个池子存储一些创建好的连接,需要使用时直接拿去使用即可,省去了创建连接的过程。

连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数 据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户 也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连 接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数 以及每个连接的最大使用次数、最大空闲时间等等,也可以通过其自身的管理机制来监视数据库连接的 数量、使用情况等。

常见的一些连接池:

  • dbcp:dbcp没有自动回收空闲连接的功能,dbcp需要手动设置配置文件
  • c3p0:c3p0有自动回收空闲连接功能,c3p0不需要手动设置
  • druid:阿里的,用的最多

一些概念:

  • 最小连接数: 是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库 资源被浪费。
  • 初始化连接数: 连接池启动时创建的初始化数据库连接数量。
  • 最大连接数: 是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队 列中。
  • 最大等待时间: 当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负 数使得无限等待(根据不同连接池配置)。

在这里插入图片描述

Talk is cheap,show me code

//工具类读取配置文件方式2,代码中是另一种方式
static{
//参数只写属性文件名即可,不需要写后缀
ResourceBundle bundle = ResourceBundle.getBundle("db");
driver = bundle.getString("driver");
url = bundle.getString("url");
username = bundle.getString("user");
password = bundle.getString("password");
}
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.dbcp.BasicDataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.List;
import java.util.Properties;

public class JdbcUtil {
    private static Connection c;
    private  PreparedStatement pps;
    private  ResultSet res;
    //dbcp连接池
    //private  static BasicDataSource basicDataSource = new BasicDataSource();
    //德鲁伊连接池
    private static DruidDataSource druidDataSource = new DruidDataSource();

    private static String username ;
    private static String password;
    private static String url;
    private static String driverName;

    static {
        try {
           /* 
           //这是不使用连接池的方式
           //创建db.properties的输入流
            InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
            //创建配置类
            Properties properties = new Properties();
            使用配置类读取db.properties文件
            properties.load(in);
            //获取各种配置的值
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            //加载驱动类
            driverName=properties.getProperty("driverName");
            try {
                Class.forName(driverName);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }*/
           
           //这是使用连接池的方式,前几行与不使用连接池都一样
            InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driverName=properties.getProperty("driverName");

/*            //dbcp连接池设置
            basicDataSource.setUrl(url);
            basicDataSource.setUsername(username);
            basicDataSource.setPassword(password);
            basicDataSource.setDriverClassName(driverName);*/

            //德鲁伊连接池设置
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
            druidDataSource.setDriverClassName(driverName);
            //druidDataSource.setInitialSize(20);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取连接
    protected Connection getConnection(){
        try {
            //dbcp连接池
            //c = basicDataSource.getConnection();
            //德鲁伊连接池
            c = druidDataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return c;
    }
    //获取preparedstatement
    protected PreparedStatement getPps(String sql)  {
        try {
            pps = getConnection().prepareStatement(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return pps;
    }
    //设置?的占位符的值
    protected void setObject(List list){
        for (int i = 0; i < list.size(); i++) {
            try {
                pps.setObject(i+1,list.get(i));
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //获取查询结果集
    protected ResultSet getQueryRes(String sql,List list){
        getPps(sql);
        setObject(list);
        try {
            res = pps.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }
    //获取增删改的结果,int
    protected int getUpdateRes(String sql,List list){
        getPps(sql);
        setObject(list);
        try {
            int i = pps.executeUpdate();
            return i;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return -1;
    }
    //关闭
    protected void closeAll(){
            try {
                if (res!=null)
                    res.close();
                if (pps!=null)
                    pps.close();
                if (c!=null)
                    c.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
}


完结

始于2021-8-19,终于2021-9-9。历时22天。

下一阶段:前端技术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值