枚举、注解、反射👊
1.枚举
注意事项:
2.注解
目前来说,注解最重点的部分在于学会如何使用注解。
关于自定义注解这一部分,只有在你开发框架时才会大量使用自定义注解。
注解主要用于:
- 编译格式检查
- 反射中解析
- 生成帮助文档
- 跟踪代码依赖
- 等
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的方式
- 类名.class
- 对象.getclass()
- 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。查看具体的失败原因。
总结一些通用的可能的解决办法:
- 将my.ini改为ansi编码格式(因为有可能是因为utf-8编码出错)。
- 修改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’);
其他一些注意的地方:
不在范围则是not in
查询等于null:is null而不是=null。
不等于null:is not null
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.聚合函数
聚合函数是用来做纵向运算的。
- COUNT(列名):统计指定列不为NULL的记录行数;
- MAX(列名):计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
- MIN(列名):计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
- SUM(列名):计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
- 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的区别:
- having是在分组后对数据进行过滤,where是在分组前对数据进行过滤
- having后面可以使用分组函数(统计函数) where后面不可以使用分组函数。
WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分 组;而HAVING是对分组后数据的约束。
5.limit
用来限定查询结果的起始行和行数。
limit 0,10
从第1条数据开始,共10条数据。
也可以写作
limit 10,
代表查询10条数据,默认是从0开始
Mysql高级
1.完整性
-
实体完整性
-
primary key(主键):不能为空,唯一,不能重复
-
创建完表后设置主键的方式:
ALTER TABLE student ADD PRIMARY KEY (id);
-
unique key(唯一约束):可以为空,唯一吗,不能重复
-
auto_increment(自增长):一般给主键设置自动增长,自增长只能应用于int类型。
-
-
域完整性
- 数据类型
- not null(非空约束)
- default(默认值约束)
- check约束(mysql不支持):例如:check(sex=‘男’ or sex=‘女’)
-
引用完整性
-
外键约束:foreign key
-
创建完表后的添加外键的方式:
ALTER TABLEscore1 ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES stu(id);
-
2.多表的关系
-
一对多/多对多
一对多建表原则:在多的一方创建一个字段,字段作为外键指向一的一方的主键
-
多对多
通常情况下,表之间不使用外键,虽然外键可以保证数据的正确性,但是外键会降低性能,而且通常作为外键的列通常是程序员赋值的(不是由用户输入的),一般不会出现错误。
多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一 方的主键.例如学生表和课程表,联合这两张表需要第三张表如下:
-
一对一
如丈夫-妻子。
建表原则:
比如可以:在丈夫表中添加妻子的主键id,并设置为unique。
还可以:将丈夫的主键id设置为外键关联妻子的主键id,
3.多表查询
多表查询分类:
- 合并结果集:union、union all:前者去重、后者不去重。被合并的两个结果:列数、列类型必须相同
- 连接查询
- 内连接:inner join
- 外连接
- 左外连接:left join
- 右外连接:right join
- 全外连接(mysql不支持):full join
- 自然连接:nature join
- 子查询
其中连接查询和子查询是重点。
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.扩展
- 多行操作(多行新增/修改/删除)
- 日期运算函数
- 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();
}
}
- 预状态通道会先编译sql语句,再去执行,效率比状态通道高。
- 预状态通道可以使用占位符?,位置从1开始
- 预状态通道可以防止sql注入
其他:
- jdbc中默认是自动提交事务的,如果要关闭自动提交,可以通过connection的setAutoCommit(false)来关闭自动提交事务。
- 要想使多个(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天。
下一阶段:前端技术。