外键约束foreign key
创建表:员工表
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
NAME VARCHAR(20), -- 员工姓名
gender VARCHAR(10), -- 性别
dept_name VARCHAR(10)-- 部门名称
) ;
INSERT INTO emp VALUES(1,'张三','男','开发部'),(2,'李四','女','测试部'),
(3,'高圆圆','女','开发部'),(4,'赵又廷','男','测试部'),(5,'文章','男','运维部') ;
SELECT * FROM emp ;
-- 员工表中部门名称:字段冗余了
DROP TABLE emp ;
创建部门表,来存储部门
-- 一般一个表中:都会id字段(非业务字段:自增的主键约束都会设置在这个上面)
CREATE TABLE dept( -- 部门表
id INT PRIMARY KEY AUTO_INCREMENT, -- 部门编号
dept_name VARCHAR(20) -- 部门名称
);
-- 插入数据
INSERT INTO dept VALUES(1,'开发部'),(2,'测试部'),(3,'运维部') ;
创建表:员工表
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
NAME VARCHAR(20), -- 员工姓名
gender VARCHAR(10), -- 性别
dept_id INT -- 部门编号
) ;
-- 插入员工数据
INSERT INTO emp VALUES(1,'高圆圆','女',1),
(2,'赵又挺','男',1),
(3,'文章','男',2),
(4,'马伊琍','女',3),
(5,'姚笛','女',2),
(6,'马三奇','男',1) ;
-- 插入一条员工数据
INSERT INTO emp VALUES(7,'王宝强','男',4) ;
-- 非法数据了,因为部门表中并没有4号部门
-- 创建员工表的时候:员工表的dept_id应该关于部门表主键id
外键约束(两张表设置一个外键):两种设置方式
1)创建表的时候直接添加外键
CREATE TABLE emp(
id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
NAME VARCHAR(20), -- 员工姓名
gender VARCHAR(10), -- 性别
dept_id INT, -- 部门编号
CONSTRAINT fk_demp_emp -- 声明 外键名称
FOREIGN KEY (dept_id) -- 作用在指定从表的指定字段
REFERENCES -- 关联
dept(id) -- 部门表的主键id
) ;
-- 插入一个不存员工,而且插入一个不存在部门编号
INSERT INTO emp (NAME,gender,dept_id) VALUES('王宝强','男',4) ;
-- 针对员工表(从表:外键所在的表)的插入/修改/删除不能直接操作 从表
-- 部门表:主表
-- 删除外键约束 ALTER TABLE emp DROP FOREIGN KEY 外键名称
ALTER TABLE emp DROP FOREIGN KEY fk_demp_emp ;
-- 删除id为8的员工
DELETE FROM emp WHERE id = 8 ;
2)通过alter table 表名 add … 方式添加外键
通过修改表添加外键
ALTER TABLE
emp
ADD
CONSTRAINT -- 声明
fk_demp_emp -- 外键名称
FOREIGN KEY (dept_id) -- 作用在指定从表的指定字段
REFERENCES -- 关联
dept(id) ; -- 部门表的主键id
SELECT * FROM dept ; -- 查询部门表
SELECT* FROM emp ; -- 查询员工表
-
– 有了外键有关联关系,所以不直接操作主表;修改/删除 (很麻烦)
-
– 1)修改或者从表的数据,让这个数据和主表没有关联
-
– 2)修改/删除 主表的数据
级联操作:CASCADE
级联修改 ON UPDATE CASCADE
- – 当前修改主表的数据,那么从表和主表相关关联的数据一会被随着更改掉
级联删除 ON DELETE CASCADE
- – 当删除主表的数据,那么从表和主表关联的数据一会被随着删除掉
-- 先sql语句将外键约束删除,然后添加外键并且添加级联操作
ALTER TABLE emp DROP FOREIGN KEY fk_demp_emp ;
ALTER TABLE emp ADD
CONSTRAINT fk_dept_emp
FOREIGN KEY (dept_id)
REFERENCES
dept(id)
ON UPDATE CASCADE -- 添加级联修改
ON DELETE CASCADE ; -- 添加级联删除
SELECT * FROM emp ;
SELECT * FROM dept ;
-- 直接修改主表的数据:
-- 将开发部的部门编号更改为4
UPDATE dept SET id = 4 WHERE id = 1 ;
-- 删除主表的数据,从表的随之删除
-- 删除id为4号部门的开发部
DELETE FROM dept WHERE id = 4;
数据库的备份和还原(两种方式)
图形界面话:简单直观
- – 选择数据库—右键----备份---->选择导出的路径(结构以及数据都保存)
- – 将之前存在库,然后选择 执行指定sql脚本----> 选择指定的sql脚本—进行执行即可!
命令行方式
- 备份:mysqldump -uroot -p密码 备份数据库名称 > 保存的本地地址
- 还原:将原来删除,新建库,使用库, source 将保存的本地地址
表与表的关系
一对一
- 是一种特例 (应用场景不多)
– 举例: 人和身份证
– 一个人对应一张身份证
– 一个身份证属于某个人的
一对多,多对多
– 员工表和部门表
– 一部门可以有多个员工,一个员工属于某一个部门的(员工表中有一个外键)
数据库的三大范式
1NF
- 数据库表的每一列都是不可分割的原子数据项
- 不能出现复合项
2NF
- 第二范式就是在第一范式的基础上所有列(所有字段)完全 依赖于主键列(主键字段)。
3NF
- 在第二范式2NF基础上,非主键字段不能传递依赖于主键(外键解决)
多表查询
- 在某个sql语句中查询多张表
```sql
CREATE DATABASE ee_2106;
-- 部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT, -- 部门编号
NAME VARCHAR(20) -- 部门名称
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
-- 员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dept_id INT,
FOREIGN KEY
(dept_id)
REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id)VALUES('孙悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id)VALUES('猪八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id)VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);
-- 查询部门表
SELECT * FROM dept ;
SELECT * FROM emp ;
-- 需求:查询员工表和部门表的所有信息
SELECT
*
FROM
emp , dept ;
- 查询多张表:员工表5条记录,部门表有3条记录 (A*B=15)
- 出现迪尔卡乘积的原因:没有连接条件
- 通过外键解决字段冗余问题 员工表的部门dept_id关联与部门表的主键id
多表查询之 内连接查询
隐式内连接
- 通过where 语句作为连接条件来查询(按照外键关联关系)
操作步骤:
- 1)查询哪张表
- 2)要查询的是指定表中的哪个字段
- 3)表和表之间的关联关系问题
-- 1)员工表和部门表
-- 2)查询员工表的中name,gender,salary以及部门表的部门名称
-- 3)连接条件:dept_id= 部门表的id
SELECT
e.name '员工姓名' ,
e.`gender` '性别',
e.`salary` '工资',
e.`dept_id` ,
d.id ,
d.`name` '部门名称'
FROM
emp e,dept d -- 员工表的别名e ,部门表的别名d
WHERE
e.`dept_id` = d.`id` ;
内连接之显示内连接
- (实际开发中,多去使用where条件查询,查询速度快 ,sql优化的一种方式)
-- select <字段列表>
-- from 表名1
-- (inner) join
-- 表名2
-- on 关联关系(连接条件);
SELECT
t1.*,-- 员工表中的所有字段 (实际开发中,* 不建议使用!)
t2.`name` -- 部门表的部门名称
FROM
emp t1
-- inner 可以省略,不写
JOIN dept t2
ON
t1.`dept_id` = t2.`id` ;
-- 给员工表插入一条数据
INSERT INTO emp(NAME,gender,salary,join_date)
VALUES('高圆圆','女',12000,'2021-8-14');
-- 要查询所有的员工表信息的同时关联查询部门表信息(部门名称即可)
-- 即使员工没有部门信息,也得查询出来...
SELECT
t1.`name` '员工名称',
t1.`gender` '性别',
t1.`salary` '工资',
t1.`join_date` '入职日期',
t2.`name` '部门名称'
FROM
emp t1
INNER JOIN dept t2
ON
t1.`dept_id` = t2.`id` ; -- 交集的条件
- 通过内连接查询存在问题 :只是查出了交集部分的数据,没有部门编号的员工并没有查询出来
- 内连接就不能使用了
多表查询之外连接查询
左外连接 left (outer) join: 通用
将两种表中左表的数据全部进行查询并且以及他们交集部分的数据全部查询
-- 右外连接 right (outer) join
-- 语法格式
-- select
-- 字段列表
-- from
-- 表名1 -- 左表
-- left outer join 表名2
-- on 连接条件 ;
SELECT
t1.`name` '姓名',
t1.`gender` '性别',
t1.`salary` '工资',
t1.`join_date` '入职日期',
t1.`dept_id` ,
t2.`name` '部门名称'
FROM
emp t1 -- 左表(见图中的A表)
LEFT
-- outer
JOIN
dept t2 -- (图中的B表)
ON
t1.`dept_id` = t2.`id` ; -- 交集部分数据
SELECT
*
FROM
dept t1
RIGHT OUTER JOIN emp t2
ON
t2.`dept_id` = t1.`id` ;
子查询
情况1:单行单列的情况:通用使用运算符进行操作
需求:查询最高工资的员工信息
-- 1)查询最高工资是多少 : 聚合函数
/*
select
max(salary)
from
emp ; -- 12000
*/
-- 2) 查询等于最高工资的员工信息
/*
select
emp.`name`,
emp.`salary`,
emp.`gender`,
emp.`join_date`
from
emp
where
salary = 12000 ;
*/
-- 一步走: 将12000的sql语句代入过来即可
SELECT
emp.`id`,
emp.`name`,
emp.`salary`,
emp.`gender`,
emp.`join_date`
FROM
emp
WHERE
salary = (SELECT MAX(salary) FROM emp ) ;
-- 查询工资小于平均工资的员工信息
-- 1)查询平均工资是多少
/*
select
avg (salary)
from emp ;
*/
-- 2)查询员工工资小于 6883.333....的员工信息
8
SELECT
*
FROM
emp
WHERE
salary < (SELECT AVG (salary) FROM emp ) ;
情况3 :多行多列的情况 —使用关键字in(集合数据)
需求:查询 在财务部或者市场部的员工信息
-- 分步骤
-- 1)查部门表中财务部和市场部的id是多少
/*
select
id
from
dept
where
name = '市场部' or name = '财务部' ;-- 2 , 3
*/
-- 2)在员工表中查 id为 财务部 (3) 或者市场部(2)的员工信息
SELECT
t.`name` '姓名',
t.`gender` '性别',
t.`salary` '工资',
t.`join_date` '入职日期',
t.`dept_id` '部门编号'
FROM
emp t
WHERE
t.`dept_id` = 2 OR t.`dept_id` = 3 ;
-- 优化 步骤2)sql语句 or---->in(集合数据)
-- 在xxx数据内 /not in exists /not exists /any(sql)
SELECT
t.`name` '姓名',
t.`gender` '性别',
t.`salary` '工资',
t.`join_date` '入职日期',
t.`dept_id` '部门编号'
FROM
emp t
WHERE
t.`dept_id` IN(
SELECT
id
FROM
dept
WHERE
NAME = '市场部'
OR
NAME = '财务部') ;
情况3:使用select语句查询的结果作为一个虚表,使用这个虚表然后继续和其他表进行查询
查询入职日期大于'2011-3-14号的员工信息以及所在的部门信息
-- 入职日期 join_date > '2011-03-14' 将查询作为虚表 和部门表继续进行查询
SELECT * FROM emp WHERE join_date > '2011-03-14';
-- 可以使用左外连接
SELECT
t2.*, -- 员工的所有信息
t1.`name` '部门名称'
FROM
dept t1 -- 部门表
LEFT OUTER JOIN
(SELECT * FROM emp WHERE join_date > '2011-03-14') t2
ON
t1.`id` = t2.`dept_id` ;
-- 最基本隐式内连接
SELECT
t1.* , -- 员工所有信息
t2.`name` -- 部门名称
FROM
emp t1 ,
dept t2
WHERE
t1.`dept_id` = t2.`id`
AND
t1.`join_date` > '2011-03-14' ;
多表查询
- 查询哪个表/哪个字段/连接条件
- SELECT * FROM dept ;
- SELECT * FROM emp ;
mysql事务
事务
- 在业务操作过程中,一次性可能同时操作多个sql语句,防止操作多个sql语句时候出现问题,将这整个业务操作看成一个整体,进行处理这些多个sql要么一次性全部执行成功,要么同时失败!
例题:转账
创建一张账户表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT, -- 账户编号
NAME VARCHAR(20), -- 账户名称
balance INT -- 账户余额
) ;
INSERT INTO account(NAME ,balance) VALUES('zhangsan',1000),('lisi',1000) ;
SELECT * FROM account ;
-- 没有开启事务,需要管理多个操作(一次执行多个sql语句),可以将多个操作
-- 使用事务管理,开启事务
-- 没有使用事务之前
-- zhangsan- 500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan' ;
出问题了
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi' ;
SELECT * FROM account ;
UPDATE account SET balance = 1000 ;
- 将转账业务操作看成整体,开启事务
START TRANSACTION ;开启手动提交事务(默认自动提交)
– 执行业务 操作
UPDATE account SET balance = balance - 500 WHERE NAME = ‘zhangsan’ ;
– 中间出问题了
UPDATE account SET balance = balance + 500 WHERE NAME = ‘lisi’ ;
事务回滚:回滚到在操作语句之前的状态ROLLBACK
提交 COMMIT
– 后期所有业务操作: 增删改 都需要使用事务进行管理
– 增删改:一次性执行多张表的多个sql语句(同时操作)------>
– SpringAOP 面向切面编程 基于OOP(面向对象)
事务的特点:ACID
原子性:
- 就是事务操作业务的中sql,要么同时执行成功,要么同时失败!
一致性:
-
操作sql语句的前后,总数量保持不变
-- 转账之前:1000 1000 -- 转账之后:500 1500
隔离性:
-- 将业务使用事务管理,业务和业务之间分离的,
-- 事务和事务之间不能相互影响---->事务是独立的
持久性:
- 如果一旦事务被提交了,是永久存储的,即使关机也还存在!
隔离级别
read uncommitted
- 读未提交 安全性最差 不能有效防止脏读
read committed ;
- 读已提交 安全相对第一个高一些,能够有效脏读,不能够防止可重复读的问题
repeatable read
- 可重复读 能够有效防止脏读,可重复读
serializable 串行话
查看全局的隔离级别的命令
查询隔离级别
-
select @@tx_isolation; mysql5.5/5.7都可以
-
SELECT @@transaction_isolation; mysql8.0
设置隔离级别
- set global transaction isolation level 级别字符串;
- SELECT @@transaction_isolation;
隔离级别不同,会出现不同的问题
脏读:一个事务读取另一个没有提交的事务(最严重的问题)
不可重复读: 一般都是update语句影响,两个事务中,一个事务读取的前后的内容不一致!
幻读:一般insert/delete :影响两个事务中,前后数量不一致!
JDBC(Java连接数据库)
使用java连接数据库过程:
- 1)在java项目添加额外的第三方的jar包
idea中 file----> project structure (ctrl+Alt+shift+s:默认快捷键_)
—model---->denpendies---->添加—jar包 —将指定路径拿过来 - 2)注册驱动
- 3)获取数据库的连接对象
- 4)准备静态sql语句
- 5)通过数据库连接对象创建执行对象Statement
- 6)执行更新操作
- 7)释放资源
public class JdbcDemo {
public static void main(String[] args) throws Exception {
//1)导包了
//2)注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ; //mysql8.0 的驱动实现类:com.mysql.cj.jdbc.Driver
//mysql8.0以前的驱动实现类:com.mysql.jdbc.Driver
//3)获取数据库的连接对象
//使用驱动管理类 DriverManager:用于管理一组JDBC驱动程序的基本服务。
//public static Connection getConnection(String url,String user,String password) throws SQLException
//参数1:url: 连接数据库的路径: 协议名称 + ip地址/域名 :3306/数据库名称 针对mysql server 8.0以前这样使用
//参数1:url: 连接数据库的路径: 协议名称 + ip地址/域名 :3306/数据库名称?参数1=值2&参数2=值2 针对mysql server 8.0使用
//?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
//参数2:用户名:root用户
//参数3:mysql连接的密码
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb_01?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//4)准备sql语句
String sql = "insert into account(name,balance) values('赵又廷',1000)" ;
//5)通过数据库连接对象获取执行对象
//public Statement createStatement() ;用于将sql语句发送的数据库的执行器对象
Statement stmt = connection.createStatement();
//6)执行更新操作
//通用方法
//int executeUpdate(String sql) throws SQLException
int count = stmt.executeUpdate(sql);
System.out.println("影响了"+count+"行");
//7)释放资源
stmt.close() ;
connection.close();
}
}
针对DDL语句
public class JdbcDemo {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建Connection对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql语句 DDL语句
String sql = "create table student(" +
"id int primary key auto_increment," +
" name varchar(20)," +
" gender varchar(10)," +
" email varchar(50) )" ;
//通过连接对象获取执行对象
stmt = conn.createStatement();
//发送sql语句到数据库中进行更新
// int exeuteUpdate(String sql) :DDL语句:表的操作/以及DML语句insert into ,update,delete
int count = stmt.executeUpdate(sql);
//0
System.out.println(count);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
if(stmt!=null){ //释放执行对象
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){//释放连接对象
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
针对DML语句
public class JdbcDemo2 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
try {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建Connection对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql语句 DML语句
String sql = "update student set gender = '女' where id = 3 " ;
//通过连接对象获取执行对象
stmt = conn.createStatement();
//发送sql语句到数据库中进行更新
// int exeuteUpdate(String sql) :DDL语句:表的操作/以及DML语句insert into ,update,delete
int count = stmt.executeUpdate(sql);
System.out.println(count);
System.out.println("修改成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
if(stmt!=null){ //释放执行对象
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){//释放连接对象
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
针对DQL语句
public class JdbcDemo3 {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
//注册驱动
try {
Class.forName("com.mysql.cj.jdbc.Driver") ;
//创建数据库连接对象
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true",
"root",
"123456");
//准备sql
String sql = "select * from student" ;
//创建执行对象
stmt = conn.createStatement() ;
//执行sql语句
rs = stmt.executeQuery(sql);
//先判断
//第一次获取
if(rs.next()) {
//如果有下一行数据,那么就获取
//通用方法
//XXX getXXX(int columnIndex):列的索引值获取 内容 index从1 开始,第一列值就是1
//XXX getXXX(String columnIabel):列的名称获取 内容
int id = rs.getInt(1);
String name = rs.getString(2) ;
String gender = rs.getString(3) ;
String email = rs.getString(4) ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
/*
//继续判断:继续移动获取第二行数据
if(rs.next()) {
//如果有下一行数据,那么就获取
//通用方法
//XXX getXXX(int columnIndex):列的索引值获取 内容 index从1 开始,第一列值就是1
//XXX getXXX(String columnIabel):列的名称获取 内容
int id = rs.getInt("id");
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
//继续判断:继续移动获取第三行数据
if(rs.next()) {
//如果有下一行数据,那么就获取
//通用方法
//XXX getXXX(int columnIndex):列的索引值获取 内容 index从1 开始,第一列值就是1
//XXX getXXX(String columnIabel):列的名称获取 内容
int id = rs.getInt("id");
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
//继续判断:继续移动获取第三行数据
if(rs.next()) {
//如果有下一行数据,那么就获取
//通用方法
//XXX getXXX(int columnIndex):列的索引值获取 内容 index从1 开始,第一列值就是1
//XXX getXXX(String columnIabel):列的名称获取 内容
int id = rs.getInt("id");
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}*/
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
封装jdbc
- 频繁的去操作数据库:CRUD:增删查改
- 每一条sql都去创建Connection对象
- 而且还需不断的去释放资源 Statment对象,Connection,ResultSet集合对象
工具类
public class JdbcUtils {
private static String url = null ;
private static String user = null ;
private static String password = null ;
private static String drivceClass = null ;
//构造方法私有化
private JdbcUtils(){}
//静态代码块
//JdbcUtils工具类一加载就执行静态代码块
static{
try {
//创建一个Properties属性列表
Properties prop = new Properties() ;
//读取src下面的jdbc.properties配置文件
//直接获取当前类的字节码文件对象,获取类加载,获取资源文件所在的输入流对象
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//将流中内容加载到属性列表中
prop.load(inputStream);
System.out.println(prop);//测试属性列表中的内容
//通过key获取value
url = prop.getProperty("url") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
drivceClass = prop.getProperty("driverClass") ;
//注册驱动
Class.forName(drivceClass) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//提供功能都是static
//通用的功能:获取数据库连接对象
public static Connection getConnection(){
Connection conn = null ;
try {
//通过驱动类管理类获取
conn = DriverManager.getConnection(url,user,password) ;
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭资源:
//DDL语句或者DML语句----->Statement对象和Connection
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
//关闭资源
//DQL语句---->ResultSet对象,Statement对象和Connection
public static void close(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt !=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
测试类
- 将获取连接对象以及关闭资源封装到工具类中了,测试下
public class JdbcDemo {
public static void main(String[] args) {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
//获取连接对象
conn = JdbcUtils.getConnection();
//准备sql语句
//DML语句
//String sql = "insert into student(name,gender,email) values('文章','男','wenzhang@163.com')" ;
//DQL语句
// String sql = "select * from student" ;
String sql = "select * from emp" ;
//执行对象
stmt = conn.createStatement();
//执行
// int count = stmt.executeUpdate(sql);
// System.out.println("执行成功"+count+"行受影响");
rs = stmt.executeQuery(sql) ;
// System.out.println("编号"+"\t"+"姓名"+"\t"+"性别"+"\t"+"邮箱");
while(rs.next()){
/*int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String gender = rs.getString("gender") ;
String email = rs.getString("email") ;*/
// System.out.println(id+"\t\t"+name+"\t"+gender+"\t\t"+email);
int id = rs.getInt("id") ;
String name = rs.getString("name") ;
String gender =rs.getString("gender") ;
Double salary = rs.getDouble("salary") ;
Date join_date =rs.getDate("join_date") ;
//添加:java.util.Date----->java.sql.Data(添加/修改)..._
System.out.println(id+"\t"+name+"\t"+gender+"\t"+salary+"\t"+join_date);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
// JdbcUtils.close(stmt,conn);
JdbcUtils.close(rs,stmt,conn);
}
}
}
jdbc封装到List集合
学生类
public class Student {
/*
Field Type Comment
id int NOT NULL
name varchar(20) NULL
gende rvarchar(10) NULL
email varchar(50) NULL*/
private int id ; //编号
private String name ;//姓名
private String gender ;//性别
private String email ; //邮箱
public Student() {
}
public Student(int id, String name, String gender, String email) {
this.id = id;
this.name = name;
this.gender = gender;
this.email = email;
}
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 String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", email='" + email + '\'' +
'}';
}
}
** 针对学生的数据库访问接口**
public interface StudentDao {
/**
* 查询所有学生信息
* @return 返回学生列表数据
*/
List<Student> findAll() ;
/**
* /通过学生id学号查询某个学生信息
* @param id 学号id
* @return 返回的某个学生实体
*/
Student findById(int id) ;
/**
* 添加学生信息
* @param student 学生实体类
*/
void add(Student student) ;
/**
* 更新学生信息
* @param student
*/
void updateStudent(Student student) ;
/**
* 通过学号删除学生
* @param id 学生id号
*/
void delete(int id) ;
}
数据库访问实现层
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> findAll() {
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
//操作数据库
try {
//创建List集合对象
List<Student> list = new ArrayList<>() ;
//获取连接对象
conn = JdbcUtils.getConnection();
//准备sql语句
String sql = "select * from student" ;
//获取执行对象
stmt = conn.createStatement();
//执行查询
rs = stmt.executeQuery(sql);
//声明学生类型的变量student
Student student = null ;
while(rs.next()){
//创建学生对象,并封装学生数据
student = new Student() ;
//查询一行,将这条学生信息封装到学生类中
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender") ;
String email = rs.getString("email");
student.setId(id);
student.setName(name);
student.setGender(gender);
student.setEmail(email);
//将学生添加到集合中
//返回集合List
list.add(student) ;
}
return list ;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public Student findById(int id) {
return null;
}
@Override
public void add(Student student) {
}
@Override
public void updateStudent(Student student) {
}
@Override
public void delete(int id) {
}
}
测试类
public class JdbcDemo2 {
public static void main(String[] args) throws Exception {
//接口多态方式
//遍历集合,获取结果
/* StudentDao sd = new StudentDaoImpl() ;
List<Student> list = sd.findAll();
for (Student student : list) {
//System.out.println(student);
System.out.println(student.getId()+"\t"+student.getName()+"\t"+student.getGender()+"\t"+student.getEmail()); //toString()
}*/
//反射创建当前StudentDaoImpl的实例
Class clazz = Class.forName("com.qf.jdbc_statment_03_jdbcutils.StudentDaoImpl");
//创建当前类实例
Object obj = clazz.newInstance(); //或者Constructor类对象
//获取Method类对象
Method method = clazz.getMethod("findAll");
//调用
Object result = method.invoke(obj); //toString()
System.out.println(result);
}
}
预编译对象(PreparedStatement)
- 操作步骤
- 1)注册驱动
- 2)获取数据库连接对象
- 3)准备参数化的sql 这些sql并非是静态sql语句
- 4)通过连接创建预编译对象并将参数化的sql语句保存PreparedStatement对象中
- 5)给参数化的sql的数据进行赋值
- 6)执行更新/查询
- 7)释放资源
public class PerparedStatementDemo {
public static void main(String[] args) {
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
try {
//获取数据库的连接对象
conn = JdbcUtils.getConnection();
//准备sql语句:参数化的sql
//占位符号:?(英文符号)
// String sql = "insert into student(name,gender,email) values(?,?,?)" ;
String sql = "select * from student" ;
//通过连接对象获取预编译对象并将参数化的sql保存到该对象中
//PreparedStatement prepareStatement(String sql)
stmt = conn.prepareStatement(sql); //预编译的过程:对sql语句中占位符号进行描述
//参数赋值
//void setXXX(int parameterIndex,XXX num)
//举例:setString(第几个占位符号(占位符号的索引值:1开始),当前占位符的实际参数"hello" )
/* stmt.setString(1,"王桑") ;
stmt.setString(2,"男") ;
stmt.setString(3,"wangsang@163.com") ;*/
//执行
//ResultSet executeQuery() :执行查询操作:DQL语句
//int executeUpdate() 执行通用的更新操作:DDL/DML语句(insert into /update/delete)
// int count = stmt.executeUpdate();
// System.out.println("影响了"+count+"行");
//查询
rs = stmt.executeQuery();
while(rs.next()){
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
String email = rs.getString("email");
System.out.println(id+"\t"+name+"\t"+gender+"\t"+email);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JdbcUtils.close(stmt,conn);
}
}
}
使用PreparedStatement对象模拟登录操作
- Statement对象和PreparedStatement对比:
- 1)后者防止sql注入,前者存在sql注入(存在sql语句字符串拼接)
- 2)执行效率后者高于前者
- 前者效率低
每次获取Statement对象
executeUpdate(String sql)
executeQuery(String sql) - 后者:
String sql = “select * from user where username=? and password = ?” ;
每次获取PreparedStatement对象的时候就已经sql保存在对象中进行预编译过程赋值
executeUpdate()
executeQuery()
public class Statement_And_PreparedStatementTest {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请输入用户名:");
String username = sc.nextLine() ;
System.out.println("请输入密码:");
String password = sc.nextLine() ;
//调用一个功能
boolean flag = isLogin2(username,password) ;
if(flag){
System.out.println("恭喜您,登录成功");
}else{
System.out.println("登录失败...");
}
}
//PreparedStatement
//定义登录方法
public static boolean isLogin2(String username, String password) {
//获取数据库的连接对象
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
try {
conn = JdbcUtils.getConnection();
//准备sql :参数化sql
//通过用户和密码查询用户
String sql = "select * from user where username=? and password = ?" ;
System.out.println(sql);
//创建执行对象PreparedStatement预编译对象
stmt = conn.prepareStatement(sql) ;
//参数赋值
//在PerparedStatement对象中完成参数赋值过程
stmt.setString(1,username);
stmt.setString(2,password);
//执行查询
rs = stmt.executeQuery();
return rs.next() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,stmt,conn);
}
return false ;
}
//Statement对象
//定义登录方法
public static boolean isLogin(String username, String password) {
//获取数据库的连接对象
Connection conn = null ;
Statement stmt = null ;
ResultSet rs = null ;
try {
conn = JdbcUtils.getConnection();
//准备sql :静态sql
//通过用户和密码查询用户
String sql = "select * from user where username='"+username+"' and password = '"+password+"' " ;
System.out.println(sql);
//创建执行对象Statement对象
stmt = conn.createStatement();
//执行查询
rs = stmt.executeQuery(sql);
return rs.next() ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(rs,stmt,conn);
}
return false ;
}
}
连接池(Druid)
- 1)导包 数据库驱动包/连接池的包
- 2)准备druid.properties
- 3)读取druid.properties配置文件
public class DruidDataSourceDemo {
public static void main(String[] args) throws Exception {
//创建属性集合列表
Properties prop = new Properties() ;
//读druid.properties配置文件
InputStream inputStream = DruidDataSourceDemo.class.getClassLoader().getResourceAsStream("druid.properties");
//将druid.properties配置文件加载到属性列表中
prop.load(inputStream);
//通过Druid连接池提供的工厂类创建数据源对象DataSource 接口
//public static DataSource createDataSource(Properties properties) throws Exception
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
//底层起始就是 子实现类对象DruidDataSoure
//Connection getConnection()
for(int x = 1; x <= 11 ; x ++){
Connection connection = dataSource.getConnection();
if(x == 5){
connection.close(); //并不是真正释放,而是归还到连接池中,等待下一次利用!
}
System.out.println(connection) ; //com.mysql.cj.jdbc.ConnectionImpl@2a17b7b6
}
// connection.close(); //并不是真正释放,而是归还到连接池中,等待下一次利用!
}
}
DruidJdbcUtils
- 工具类---->DataSource----->获取数据库的连接对象 Connection以及后期管理事务
- 获取连接对象----静态方法
- 关闭资源-----静态方法
public class DruidJdbcUtils {
//成员变量位置
private static DataSource ds ;
//为了保证线程安全:每一线程使用自己的Connection (张三/李四)
private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ; //提供线程的局部变量保存连接对象
//构造方法私有化
private DruidJdbcUtils(){}
//静态代码块
static{
try {
//读取数据库连接池的配置文件----->通过DruidDataSourceFactory工厂类创建DataSource
//创建一个属性集合列表
Properties prop = new Properties() ;
//读取druid.properties
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
getResourceAsStream("druid.properties");
//将资源文件所在的输入流加载列表中
prop.load(inputStream);
ds = DruidDataSourceFactory.createDataSource(prop); //底层子实现类:DruidDataSource
System.out.println("数据源获取成功");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//提供静态方法:单独获取数据源
public static DataSource getDataSource(){
return ds ;
}
//获取连接对象Connection静态功能
public static Connection getConnection(){
//从ThreadLocal中获取局部变量的副本:Connection
/**
* public T get() :从线程中获取局部变量的副本!
*/
Connection conn = null ;
try {
conn = t1.get();
if(conn==null){
//如果空,需要从数据库的连接池中获取连接对象
conn = ds.getConnection();
//获取到之后,每一线程执行自己的Connection
//将获取到的连接对象 绑定到当前线程中
t1.set(conn);
}
//如果不为空,说明ThreadLocal线程中已经存在Connection
return conn ; //
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭(释放资源)资源
public static void close(ResultSet rs, Statement stmt,Connection conn) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
//关闭之后,归还到连接池中,需要从当前线程中解绑
t1.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close( Statement stmt,Connection conn) {
close(null,stmt,conn);
}
//事务管理代码 --- 加入
public static void main(String[] args) {
// DataSource ds = DruidJdbcUtils.getDataSource();
//System.out.println(ds);
Connection connection = DruidJdbcUtils.getConnection();
System.out.println(connection);
}
}
JdbcUtils(封装jdbc操作的工具类)
- 频繁的去操作数据库:CRUD:增删查改
- 每一条sql都去创建Connection对象
- 而且还需不断的去释放资源 Statment对象,Connection,ResultSet集合对象
public class JdbcUtils {
private static String url = null ;
private static String user = null ;
private static String password = null ;
private static String drivceClass = null ;
//构造方法私有化
private JdbcUtils(){}
//静态代码块
//JdbcUtils工具类一加载就执行静态代码块
static{
try {
//创建一个Properties属性列表
Properties prop = new Properties() ;
//读取src下面的jdbc.properties配置文件
//直接获取当前类的字节码文件对象,获取类加载,获取资源文件所在的输入流对象
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//将流中内容加载到属性列表中
prop.load(inputStream);
//System.out.println(prop);//测试属性列表中的内容
//通过key获取value
url = prop.getProperty("url") ;
user = prop.getProperty("user") ;
password = prop.getProperty("password") ;
drivceClass = prop.getProperty("driverClass") ;
//注册驱动
Class.forName(drivceClass) ;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//提供功能都是static
//通用的功能:获取数据库连接对象
public static Connection getConnection(){
Connection conn = null ;
try {
//通过驱动类管理类获取
//DriverManager---->DataSource:数据源 获取连接对象
conn = DriverManager.getConnection(url,user,password) ;
return conn ;
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭资源:
//DDL语句或者DML语句----->Statement对象和Connection
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
//关闭资源
//DQL语句---->ResultSet对象,Statement对象和Connection
public static void close(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt !=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
}
}
Druid测试题
管理员实体类Admin
public class Admin {
/* FieldTypeComment
id int NOT NULL
usernam evarchar(20) NULL
gender varchar(5) NULL
age int NULL
address varchar(50) NULL
phone varchar(11) NULL*/
private int id ;
private String username ;
private String gender ;
private int age ;
private String address ;
private String phone ;
public Admin() {
}
public Admin(int id, String username, String gender, int age, String address, String phone) {
this.id = id;
this.username = username;
this.gender = gender;
this.age = age;
this.address = address;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
针对Admin的数据库访问接口层AdminDao
public interface AdminDao {
/**
* 数据库访问的查询所有的管理员列表
* @return 返回列表数据
*/
List<Admin> findAll() ;
/**
* 根据id编号查询指定的管理员
* @param id 编号
* @return 获取实体
*/
Admin selectAdminById(int id);
/**
* 查询总记录数
* @return
*/
int selectTotalCount();
}
针对Admin的数据库访问接口实现层AdminDaoImpl
public class AdminDaoImpl implements AdminDao {
Connection conn = null ;
PreparedStatement stmt = null ;
ResultSet rs = null ;
@Override
public List<Admin> findAll() {
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin" ;
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
rs = stmt.executeQuery() ;
//创建List
List<Admin> list = new ArrayList<>() ;
//声明admin变量 Admin类型的
Admin admin = null ;
while(rs.next()){
admin = new Admin() ;
int id = rs.getInt("id");
String username = rs.getString("username");
String gender = rs.getString("gender");
int age = rs.getInt("age");
String address = rs.getString("address");
String phone = rs.getString("phone");
//封装Admin实体
admin.setId(id);
admin.setUsername(username);
admin.setGender(gender);
admin.setAge(age);
admin.setAddress(address);
admin.setPhone(phone);
//添加到集合中
list.add(admin) ;
}
return list ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return null;
}
//查询单个实体
@Override
public Admin selectAdminById(int id) {
//获取数据库的连接对象
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin where id = ?" ;
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
//参数赋值
stmt.setInt(1,id);
//执行更新
rs = stmt.executeQuery() ;
Admin admin = null ;
while(rs.next()){
admin = new Admin() ;
int adminId = rs.getInt("id");
String username = rs.getString("username");
String gender = rs.getString("gender");
int age = rs.getInt("age");
String address = rs.getString("address");
String phone = rs.getString("phone");
//封装
admin.setId(adminId);
admin.setUsername(username);
admin.setGender(gender);
admin.setAge(age);
admin.setAddress(address);
admin.setPhone(phone);
}
return admin ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return null;
}
@Override
public int selectTotalCount() {
//获取数据库的连接对象
try {
//获取连接对象
conn = DruidJdbcUtils.getConnection();
//准备sql
String sql ="select * from admin" ; //全部数据
//创建预编译对象
stmt = conn.prepareStatement(sql) ;
//执行更新
rs = stmt.executeQuery() ;
//int getRow():ResultSet 获取行数 (第一行1,第二行2)
int countRow = 0 ;
while(rs.next()) {
countRow ++ ;
}
return countRow ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
DruidJdbcUtils.close(rs,stmt,conn);
}
return 0 ;
}
}
针对Admin业务接口层AdminService
public interface AdminService {
/**
* 查询所有的Admin管理员实体
* @return 返回列表数据
*/
List<Admin> getAllAdmin() ;
/**
* 通过id 查询管理员
* @param id 管理员编号
* @return 返回实体对象
*/
Admin getAdmin(int id) ;
/**
* 查询总记录数
* @return
*/
int getCount() ;
}
针对Admin的业务接口实现层AdminServiceImpl
public class AdminServiceImpl implements AdminService {
@Override
public List<Admin> getAllAdmin() {
//创建数据库访问接口对象AdminDao
AdminDao adminDao = new AdminDaoImpl() ;
List<Admin> list = adminDao.findAll();
return list;
}
/**
* 获取指定的管理员
* @param id 管理员编号
* @return
*/
@Override
public Admin getAdmin(int id) {
//调用dao层
AdminDao adminDao = new AdminDaoImpl() ;
Admin admin = adminDao.selectAdminById(id) ;
if(admin!=null){
return admin;
}else{
System.out.println("没有查找到管理员");
}
return null ;
}
@Override
public int getCount() {
//调用dao层
AdminDao adminDao = new AdminDaoImpl() ;
int count = adminDao.selectTotalCount() ;
return count;
}
}
测试类MyTest
public class MyTest {
/* public static void main(String[] args) {
//调用业务层Service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}*/
//测试查询功能所有
@Test
public void testFindAll(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}
//测试查询某个管理员
@Test
public void testfindById(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
Admin admin = adminService.getAdmin(2);
System.out.println(admin);
}
//测试查询总记录数
@Test
public void testSelectTotalCount(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
int totalCount = adminService.getCount();
System.out.println(totalCount);
}
}
通用jdbc工具(dbUtils)
- 1)导包 核心工具包
commons-dbutils-1.7.jar
依赖包 commons-logging:支持相关的
commons-collections:工具类中涉及其他的api - 2)获取数据库的连接对象Connection
- 3)获取执行对象:通过物理数据源DataSource:java.sql.DataSource(sun公司提供一个接口)---->替代了DriverManager
QueryRunner
//基本使用
public class DbUtilsDemo {
public static void main(String[] args) throws SQLException {
//1)创建执行对象QueryRunner (执行对象)
// public QueryRunner(DataSource ds) { //数据源
// super(ds);
// }
//属于自动提交
QueryRunner queryRunner = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//需要给ee_2106的admin表 添加一条数据
//插入数据
String sql = "insert into admin(username,gender,age,address,phone) values(?,?,?,?,?)" ;
//执行通用方法:update()DML语句 ,query()DQL
// updateS(String sql,Object...parames):参数1sql 参数2:可变参数,可以使用多个实际参数
int count = queryRunner.update(sql, "王宝强", "男", 20, "西安市", "13566662222");
System.out.println(count);
//不需要关闭资源
}
}
注解
- 注解:Java中针对 类的编译,加载,运行时提供一种特殊的代码标记
可以被解析-----就是通过反射实现的
普通注解
- @Override:一般方法中使用,标记这个方法是否是重写方法
- @SupressWarning:压制警告 (项目部署上线的时候,项目中不能出现黄色警告线)
- @Deprecated:标记方法已经过时
- @FunctionalInterface:标记某个接口是否为函数式接口
接口中有且仅有一个抽象方法
人类
public class Person {
public void show(){
System.out.println("show person...");
}
}
工人类
//工人类继承人类
//给worker去使用 @MyAnno
//使用某一个注解,那么要给注解中的所有的属性赋值
@MyAnno(name="高圆圆",age=20,direction = MyEnum.LEFT,value = @MyAnno2("hello"),strs = {"aaa","bbb","ccc"})
public class Worker extends Person {
@Override
public void show() {
System.out.println("show worker....");
}
//@Override报错
@Deprecated // 标记这个方法为过时方法
public void method(){}
}
测试类
public class Test {
public static void main(String[] args) {
//创建Worker
Worker worker = new Worker() ;
worker.method();
}
}
元注解
- @Target:当前这个注解能够使用的范围
ElementType[] value(); value属性(“抽象方法名”) 返回值枚举数组类型
ElementType 枚举中的都是常量字段 (等价于 public static final …) - TYPE,能够使用在类上或者接口上
- FIELD:能够使用在成员变量上
- METHOD:能够使用在成员方法上
//自定义的枚举类
public enum MyEnum {
//常量
FRONT,
RIGHT,
BEHIND,
LEFT;
}
- @Retention:标记当前这个某个注解保留的阶段
RetentionPolicy value(); value属性 它的返回值枚举类
RetentionPolicy - SOURCE 原码编译阶段
- CLASS 类的加载,反射阶段
- RUNTIME 类的运行阶段
- 注解(本质接口)中的方法名----- 称为"属性"
属性中可以是什么样的数据类型呢? - 基本数据类型
- String类型
- 枚举类型
- 注解类型
- 以上类型的数组格式
public @interface MyAnno {
//字符串类型
String name() ; //name属性
//基本数据类型
int age() ; // age属性
//枚举类型
MyEnum direction() ;//direction
//注解类型
MyAnno2 value() ;//value属性
//以上类型的数组格式
String[] strs() ;//strs属性
}
自定义注解
- 1)自定义一个注解 @Annotation
- 2)在加上一些元注解,标记当前你自己的定义这个的@Target:作用的位置
- @Retention:保留的阶段(Runtime,source,class)
- 3)如何解析自定义注解
- 反射的方式
public <A extends AnnotationA getAnnotation(Class<A annotationClass)
参数:表示当前注解类型的Class
元注解测试题
学生类
public class Student {
public void love(){
System.out.println("爱学习,爱Java");
}
}
工人类
public class Worker {
public void love(){
System.out.println("爱生活,爱高圆圆,爱Java..");
}
}
元注解类
/元注解
@Target(ElementType.TYPE) //@MySelfAnno就可以作用在类上
@Retention(RetentionPolicy.RUNTIME) //@MySelfAnno保留在运行阶段 (一般自定义注解:设计层面,考虑运行阶段)
public @interface MySelfAnno {
//定义一些属性(方法---返回值类型(五种))
String className() ;
String methodName() ;
}
三种方式的测试类
@MySelfAnno(className ="com.qf.annotation_03.Worker",methodName = "love")
public class Test {
public static void main(String[] args) throws Exception {
//创建一个学生类
Student s = new Student() ;
s.love();
//需求改进了:使用Worker类
Worker worker = new Worker() ;
worker.love();
//需要不断改进,一会创建学生类,一会创建工人类,就会不断修改代码
//开发的设计原则:开闭原则:对修改关闭,对扩展开放
System.out.println("---------------------------------------");
//创建一个属性集合类
Properties properties = new Properties() ;
//读取src下面的classname.properites
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("classname.properties");
//将资源文件输入流对象加载属性列表中
properties.load(inputStream);
//通过key获取value
String className = properties.getProperty("className");//全限定名称
String methodName = properties.getProperty("methodName");//方法名
//反射技术
Class clazz = Class.forName(className);
//创建当前类实例
Object obj = clazz.newInstance();
//获取方法的Method类对象
Method method = clazz.getMethod(methodName);
//调用方法
method.invoke(obj) ;
System.out.println("-----------------------------");
//解析当前类Test上的 @MySelfAnno注解
//1)获取当前类的字节码文件对象
Class testClass = Test.class ;
//2)当前类的Class类对象获取注解的实例
//public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
// 参数:表示当前注解类型的Class
//获取的公共接口Annotation--->向下转型 具体的注解类型
MySelfAnno annotation = (MySelfAnno) testClass.getAnnotation(MySelfAnno.class);
/**
* public interface MySelfAnno{
*
*
* String className() ;
* String methodName() ;
* }
*
* public class XXX implements MySelfAnno{
*
*
* 重写了
* public String className(){
* return "com.qf.annotation_03.Student" ;
* }
* public String methodName(){
*
* return "love" ;
* }
*
* }//子类
*
*
*/
String className1 = annotation.className();
String methodName1 = annotation.methodName();
//继续反射
Class clazz1 = Class.forName(className1);
//创建当前类实例
Object clazzObj = clazz1.newInstance();
//获取当期类的Method
Method method1 = clazz1.getMethod(methodName1);
method1.invoke(clazzObj) ;
}
}
优化Druid测试题
管理员实体类Admin
public class Admin {
/* FieldTypeComment
id int NOT NULL
usernam evarchar(20) NULL
gender varchar(5) NULL
age int NULL
address varchar(50) NULL
phone varchar(11) NULL*/
private int id ;
private String username ;
private String gender ;
private int age ;
private String address ;
private String phone ;
public Admin() {
}
public Admin(int id, String username, String gender, int age, String address, String phone) {
this.id = id;
this.username = username;
this.gender = gender;
this.age = age;
this.address = address;
this.phone = phone;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
", address='" + address + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
针对Admin数据库访问接口
public interface AdminDao {
/**
* 获取所有管理员列表
* @return 列表
*/
List<Admin> findAll();
/**
* 查询编号获取Admin实体
* @param id 编号
* @return 返回实体对象
*/
Admin findAdminById(int id);
/**
* 查询总记录
* @return
*/
long selectTotalCount();
/**
* 修改admin
* @param selectAdmin
* @return
*/
int updateAdmin(Admin selectAdmin);
}
针对Admin的数据库访问接口实现类
public class AdminDaoImpl implements AdminDao {
@Override
public List<Admin> findAll() {
try {
//创建执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//准备sql语句
String sql = "select * from admin" ;
//执行查询
//query(String sql,ResuletSetHandler handler)
//参数1:sql
//参数2:结果集的处理
//子类:BeanListHandler<T> 将查询的多条记录封装到List集合中
//List<当前指定的javeBean实体>
// BeanListHandler<将查询的结果封装实体类型>(当前实体的类Class)
List<Admin> list = qr.query(sql, new BeanListHandler<Admin>(Admin.class));
return list ;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//通过id查询Admin实体
@Override
public Admin findAdminById(int id) {
try {
//创建执行对象
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select * from admin where id = ?" ;
//执行查询
//query(String sql,ResultSetHandler handler,Object...params)
//将查询的某一条记录封装到实体类(JavaBean)中,使用到类BeanHandler<T>
Admin admin = qr.query(sql, new BeanHandler<Admin>(Admin.class), id);
return admin;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
//查询总记录数
@Override
public long selectTotalCount() {
//QueryRunner执行对象
try {
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "select count(id) from admin" ;
//查询一些单行单列的数据(总记录数),使用单类ScalerHandler<>
long count = (Long)qr.query(sql, new ScalarHandler<>());
return count ;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
//修改Admin
@Override
public int updateAdmin(Admin selectAdmin) {
try {
//QueryRunner
QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
//sql
String sql = "update admin set username = ? ,gender =?,age = ?,address = ? ,phone =? where id = ?" ;
//更新操作
int count = qr.update(sql,
selectAdmin.getUsername(),
selectAdmin.getGender(),
selectAdmin.getAge(),
selectAdmin.getAddress(),
selectAdmin.getPhone(),
selectAdmin.getId());
System.out.println(count);
return count ;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
}
针对Admin业务接口
public interface AdminService {
/**
* 获取所有管理员列表
* @return 列表
*/
List<Admin> getAllAdmin() ;
/**
* 查询编号获取Admin实体
* @param id 编号
* @return 返回实体对象
*/
Admin getAdmin(int id) ;
/**
* 查询总记录
* @return
*/
long getTotal() ;
/**
* 根据id修改admin
* @param admin
* @return
*/
int update(Admin admin) ;
}
针对Admin的业务接口实现类
public class AdminServiceImpl implements AdminService {
@Override
public List<Admin> getAllAdmin() {
//调用数据库访问接口
AdminDao adminDao = new AdminDaoImpl() ;
List<Admin> list = adminDao.findAll() ;
if(list!=null){
return list ;
}
return null ;
}
@Override
public Admin getAdmin(int id) {
//调用数据库访问接口
AdminDao adminDao = new AdminDaoImpl() ;
Admin admin = adminDao.findAdminById(id) ;
if(admin!=null){
return admin ;
}
return null;
}
@Override
public long getTotal() {
//调用数据库访问jiekou
AdminDao adminDao = new AdminDaoImpl() ;
long count = adminDao.selectTotalCount() ;
return count;
}
@Override
public int update(Admin admin) {
//1)修改管理员数据,需要通过id查询Admin
AdminDao adminDao = new AdminDaoImpl() ;
//通过编号查询Admin
Admin selectAdmin = adminDao.findAdminById(admin.getId());
if(selectAdmin !=null){
//存在
//进行修改
int count = adminDao.updateAdmin(admin) ;
return count ;
}
return 0;
}
public static void main(String[] args) {
AdminService adminService = new AdminServiceImpl() ;
Admin admin = new Admin() ;
admin.setId(3) ;
admin.setUsername("张三丰");
admin.setGender("男");
admin.setAge(20);
admin.setAddress("南窑国际");
admin.setPhone("13588889999");
int count = adminService.update(admin);
System.out.println(count);
}
}
提供一些业务测试 (单元测试)
public class DbutilsTest {
@Test
public void testFindAll(){
//调用业务层方法
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
for (Admin admin : list) {
System.out.println(admin);
}
}
@Test
public void testFindById(){
AdminService adminService = new AdminServiceImpl() ;
Admin admin = adminService.getAdmin(3);
System.out.println(admin);
}
@Test
public void testSelectTotalCount(){
AdminService adminService = new AdminServiceImpl() ;
long count = adminService.getTotal();
System.out.println(count);
}
@Test
public void testUpdateAdmin(){
AdminService adminService = new AdminServiceImpl() ;
//创建Admin
Admin admin = new Admin() ;
admin.setId(3) ;
admin.setUsername("张三丰2");
admin.setGender("男2");
admin.setAge(22);
admin.setAddress("南窑国际2");
admin.setPhone("13588889888");
int count = adminService.update(admin);
System.out.println(count);
}
}
JDBC操作管理事务
- 事务:
- 一种机制,某个业务中多次调用dao完成多个sql同时执行,要么同时执行成功/要么同时执行失败.否则,就出现数据紊乱! 使用事务管理(JDBC方式操作)
- 用户发送请求,通过连接池获取Connection对象
- Connection:管理事务的功能
- void setAutoCommit(boolean autoCommit) throws SQLException
- 默认情况下,新创建的连接对象处于自动提交模式 参数为true,声明为false,禁用自动提交需要收到提交sql
- void rollback() throws SQLException:当前执行提交之前,如果sql发生异常,将撤销之前的所有操作
- void commit() SQLException:如果执行过程中没有问题或者回滚了,都提交事务,将之前的所有操作永久保存!
测试题(转账)
*需求:mydb_01数据库中的account表
zhangsan账户---- lisi账户 转账500
- 1)获取连接对象
- 2)准备sql语句
两个update的sql
zhagnsan -500
lisi+ 500 - 3)分别执行
- 4)释放资源
public class JdbcTransactionDemo {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement stmt1 = null;
PreparedStatement stmt2 = null;
try {
//通过DruidJdbcUtils获取连接对象
connection = DruidJdbcUtils.getConnection();
//开启事务---将自动提交禁用调用,参数为false,手动提交
connection.setAutoCommit(false);
//准备sql语句
String sql1 = "update account set balance = balance - ? where id = ?" ;
//创建预编译对象对sql1进行预编译
stmt1 = connection.prepareStatement(sql1);
//参数赋值
stmt1.setInt(1,500);
stmt1.setInt(2,1);
//执行更新
stmt1.executeUpdate() ;
//程序出问题了
// int i = 10 /0 ;
String sql2 = "update account set balance = balance + ? where id = ? " ;
//创建预编译对象对sql2进行预编译
stmt2 = connection.prepareStatement(sql2);
//参数赋值
stmt2.setInt(1,500);
stmt2.setInt(2,2);
//执行更新
stmt2.executeUpdate() ;
//如果没有问题,正常提交
connection.commit();
System.out.println("转账成功...");
} catch (SQLException e) {
//处理异常: 直接事务回滚
//有异常,执行catch语句,就回滚
try {
System.out.println("程序出问题了...");
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
//e.printStackTrace();
}
//释放资源
DruidJdbcUtils.close(stmt1,connection);
DruidJdbcUtils.close(stmt2,connection);
}
}
Html
- html: Hyper Text Markup Language:超文本标记语言
- h5的一些标签对视频或者音频操作!
- 通过html标签 写半成品的网页 ----- 类似于房屋的主体结构
- 通过css(层叠样式表):能针对html标签进行修饰 ----类似于房屋的装修
- 通过js(javascript):实现效果(轮播图,js事件编程)----类似房屋中的功能
文本标签
<title>01_html文本标签</title>
标题标签(h1-h6)
<!-- 标题标签 h1-h6:从大到小 闭合标签:有开始有结束-->
<h1>JavaEE</h1>
<h2>JavaEE</h2>
<h3>JavaEE</h3>
<h4>JavaEE</h4>
<h5>JavaEE</h5>
<h6>JavaEE</h6>
滚动标签(marquee)
<!-- 滚动标签marquee
不指定滚动方向,默认从右到左滚动
属性:
behavior:滚动方式
slide:滚动到一边停止
alternate:来回滚动
scroll:(交替滚动 碰到边框不会停止)
direction:滚动的方向:默认值 left(右到左)
scrollamount:滚动的速度: 正整数值(越大,速度快)
bgcolor:背景色
-->
<marquee behavior="scroll"direction
="right" scrollamount="22" bgcolor="pink">hello,html</marquee>
段落标签(闭合标签)(p
<!-- 段落标签p 闭合标签 -->
<p>
高圆圆,原名高园园,1979年10月5日出生于北京市丰台区,祖籍河北唐山,中国内地影视女演员、模特。1996年,被广告公司发掘,随后拍摄大量的商业广告,在广告圈中崭露头角。1997年,主演个人首部大银幕作品《爱情麻辣烫》,从此开始了她的演艺生涯。2003年,凭借古装武侠爱情剧《倚天屠龙记》受到广泛关注。2005年,因在剧情片《青红》中饰演女主人公青红入围戛纳电影节最佳女主角奖。2006年,凭借喜剧
</p>
<p>
1996年,被广告公司发掘,随后拍摄大量的商业广告,在广告圈中崭露头角。1997年,主演个人首部大银幕作品《爱情麻辣烫》,从此开始了她的演艺生涯。2003年,凭借古装武侠爱情剧《倚天屠龙记》受到广泛关注 [2] 。2005年,因在剧情片《青红》中饰演女主人公青红入围戛纳电影节最佳女主角奖 [3] 。2006年,凭借喜剧动作片《宝贝计划》入围百花奖最佳女演员提名 [4] 。2007年,因在爱情电影《男才女貌》中饰演聋哑幼师秦小悠获得第11届电影表演艺术学会奖新人奖 [5] 。2010年,凭借都市爱情电影《单身男女》提名第31届香港电影金像奖最佳女主角、华语电影传媒大奖观众票选最受瞩目女演
</p>
换行标签(非闭合标签)(br)
<!-- 换行标签 非闭合标签 br -->
hello,高圆圆 <br />
hello,马三奇<br />
水平标签(非闭合标签)(hr)
<!-- 水平标签 非闭合标签 hr -->
<hr/>
上下标标签(sup和sub)
<!-- 上下标标签sup和sub 应用场景:在门户系统最后一行 注册商品以及版权所有 -->
数学公式:x^2 <br />
x<sup>2</sup> <br />
化学公式: H<sub>2</sub>O
<br/>
转义字符
<!-- html转义字符
版权所有 : © 代表 © 版权所有
注册商品 : ® 代表 ®
空格 : 一个 代表一个空格
  一个转义字符 代表两个空格
-->
xxx公司版权所有2021-2022<sup>©</sup> <br/>
xx公司注册商品<sup>®</sup><br/>
中  国<br />
加粗标签(strong/b)
<!-- 加粗标签 strong / b
语义强调的加粗使用b标签,一般通用strong
-->
<strong>阿富汗</strong>
<b>奥拉夫</b><br />
倾斜标签(em/i)
<!-- 倾斜标签 em/ i
义强调的加粗使用i标签, 一般通用em
-->
<em>路飞</em>
<i>索隆</i>
居中标签(center)
<!-- 居中标签center 将文本内容进行居中-->
<center>HTML</center>
原样输出标签(pre)
<!-- 原样输出标签 pre -->
<pre>
举头望明月,低头思故乡.
funciton hello(){
alert("hello") ;
}
</pre>
列表标签
<!-- 列表标签
无序列表ul li (列表项)
有序列表ol li
-->
<br/>
以下的明星喜欢谁?
<!-- 无序列表
ul:
type属性 :指定列表项前面的标记disc
-->
<ul type="square">
<li>高圆圆</li>
<li>姆巴佩</li>
<li>赵又廷</li>
</ul>
<hr/>
以下的明星喜欢谁?
<ol type="1">
<li>高圆圆</li>
<li>姆巴佩</li>
<li>赵又廷</li>
</ol>
超链接标签(a)
- 超链接a标签来表示
- 协议:
ftp
http协议
thunder://
超链接标签的属性
href: 后面跟统一资源定位符 url 以后本地地址或者服务器地址
需要加上协议:http://www.baidu.com
- http协议请求规则
C:\Windows\System32\drivers\etc
hosts文件
记录ip地址 域名
127.0.0.1(本地回环地址) localhost - 如果在hosts文件本地找不到www.baidu.com对应的ip地址那么就会调用网卡联网操作
- DNS服务器(网络运营商)
ip地址1 www.baidu.com
ip地址2 www.sina.com.cn
回显百度首页给用户
指定服务器地址
http://locahost:8080/后台地址 - url地址:统一资源定位符
- http:// 域名:端口号/
端口号:80端口可以省略不写
target普通用法:打开方式
- _blank:新建窗口打开
- _self:当前窗口打开
- 如果现在在框架标签中使用target 指定哪个frame中打开
超链接标签的用法
- 1)作为资源跳转进行使用
- 2)作为锚链接来使用
- 同一个页面(使用居多)
a)打锚点(创建一个跳转标记)
b)创建跳转链接
跳转 - 不同页面跳转
a)打锚点(创建一个跳转标记) :在另一个页面的某个位置
b)在当前的某个位置创建跳转链接
跳转
跳转到另一个页面链接
<!-- 跳转到另一个页面链接 -->
<a href="00_html文本标签.html#ul" target="_self">跳转到指定页面的某个位置</a><br/>
跳转标记
<!-- 跳转标记 -->
<a name="top"></a>
<a href="#foot">[跳转底部]</a><br/>
<a href="http://www.baidu.com:80">链接到百度</a><br/>
<a href="http://14.215.177.39:80">链接到百度</a><br/>
<a href="thunder://www.dytt8.net"><<特种部队.中英双字>></a>
<p>
20世纪90年代,硬件领域出现了单片式计算机系统,这种价格低廉的系统一出现就立即引起了自动控制领域人员的注意,因为使用它可以大幅度提升消费类电子产品(如电视机顶盒、面包烤箱、移动电话等)的智能化程度。Sun公司为了抢占市场先机,在1991年成立了一个称为Green的项目小组,帕特里克、詹姆斯·高斯林、麦克·舍林丹和其他几个工程师一起组成的工作小组在加利福尼亚州门洛帕克市沙丘路的一个小工作室里面研究开发新技术,专攻计算机在家电产品上的嵌入式应用。
</p>
<p>
由于C++所具有的优势,该项目组的研究人员首先考虑采用C++来编写程序。但对于硬件资源极其匮乏的单片式系统来说,C++程序过于复杂和庞大。另外由于消费电子产品所采用的嵌入式处理器芯片的种类繁杂,如何让编写的程序跨平台运行也是个难题。为了解决困难,他们首先着眼于语言的开发,假设了一种结构简单、符合嵌入式应用需要的硬件平台体系结构并为其制定了相应的规范,其中就定义了这种硬件平台的二进制机器码指令系统(即后来成为“字节码”的指令系统),以待语言开发成功后,能有半导体芯片生产商开发和生产这种硬件平台。对于新语言的设计,Sun公司研发人员并没有开发一种全新的语言,而是根据嵌入式软件的要求,对C++进行了改造,去除了留在C++的一些不太实用及影响安全的成分,并结合嵌入式系统的实时性要求,开发了一种称为Oak的面向对象语言。
</p>
<p>
由于在开发Oak语言时,尚且不存在运行字节码的硬件平台,所以为了在开发时可以对这种语言进行实验研究,他们就在已有的硬件和软件平台基础上,按照自己所指定的规范,用软件建设了一个运行平台,整个系统除了比C++更加简单之外,没有什么大的区别。1992年的夏天,当Oak语言开发成功后,研究者们向硬件生产商进行演示了Green操作系统、Oak的程序设计语言、类库和其硬件,以说服他们使用Oak语言生产硬件芯片,但是,硬件生产商并未对此产生极大的热情。因为他们认为,在所有人对Oak语言还一无所知的情况下,就生产硬件产品的风险实在太大了,所以Oak语言也就因为缺乏硬件的支持而无法进入市场,从而被搁置了下来。
</p>
<p>
1995年,互联网的蓬勃发展给了Oak机会。业界为了使死板、单调的静态网页能够“灵活”起来,急需一种软件技术来开发一种程序,这种程序可以通过网络传播并且能够跨平台运行。于是,世界各大IT企业为此纷纷投入了大量的人力、物力和财力。这个时候,Sun公司想起了那个被搁置起来很久的Oak,并且重新审视了那个用软件编写的试验平台,由于它是按照嵌入式系统硬件平台体系结构进行编写的,所以非常小,特别适用于网络上的传输系统,而Oak也是一种精简的语言,程序非常小,适合在网络上传输。Sun公司首先推出了可以嵌入网页并且可以随同网页在网络上传输的Applet(Applet是一种将小程序嵌入到网页中进行执行的技术),并将Oak更名为Java(在申请注册商标时,发现Oak已经被人使用了,再想了一系列名字之后,最终,使用了提议者在喝一杯Java咖啡时无意提到的Java词语)。5月23日,Sun公司在Sun world会议上正式发布Java和HotJava浏览器。IBM、Apple、DEC、Adobe、HP、Oracle、Netscape和微软等各大公司都纷纷停止了自己的相关开发项目,竞相购买了Java使用许可证,并为自己的产品开发了相应的Java平台。
</p>
<br/><br/><br/>
<p>
1997年2月,JDK 1.1面世,在随后的3周时间里,达到了22万次的下载量。4月2日,Java One会议召开,参会者逾一万人,创当时全球同类会议规模之纪录。9月,Java Developer Connection社区成员超过10万。
1998年12月8日,第二代Java平台的企业版J2EE发布。1999年6月,Sun公司发布了第二代Java平台(简称为Java2)的3个版本:J2ME(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及有限资源的环境;J2SE(Java 2 Standard Edition,Java 2平台的标准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台的企业版),应用于基于Java的应用服务器。Java 2平台的发布,是Java发展过程中最重要的一个里程碑,标志着Java的应用开始普及。
</p>
创建一个锚点:跳转标记
<!-- 创建一个锚点:跳转标记 -->
<a name="foot"></a>
跳转链接
<!-- 跳转链接 -->
<a href="#top">[跳转顶部]</a>
<center>xxx公司版权所有<sup>©</sup></center>
表格标签(table)
表格标签属性
属性:
- 显示表格样式 必须指定border 边框
- algin:对齐方式
- width/height:宽度和高度(px/百分比(占当前系统分辨率权重百分比))
- bgColor:背景色
- cellspacing:设置边框线和单元格的距离
表格标签的子标签
- capation:表格表格标签
- tr:行标签
- td:单元格标签
- th:表格的表头标签:特殊的单元(自动居中,加粗)
单元格合并:td的属性
- 合并行: rowspan属性
占用的单元格数量 - 合并列:colspan属性
占用单元格数量
<body>
<!-- 写一个三行四列的表格 -->
<table border="1px" width="100%" height="300px" cellspacing="0"
bgcolor="greenyellow">
<!-- 标题 -->
<caption>xxx学校成绩表</caption>
<tr>
<th>编号</th>
<th>姓名</th>
<th>班级</th>
<th>成绩</th>
</tr>
<tr align="center">
<td>1</td>
<td>高圆圆</td>
<td>Java基础班</td>
<td>98</td>
</tr>
<tr align="center">
<td>2</td>
<td>赵又廷</td>
<td>Java基础班</td>
<td rowspan="2">89</td>
</tr>
<tr align="center">
<td>3</td>
<td>张三丰</td>
<td>计算机1班</td>
<!-- <td>76</td> -->
</tr>
<!-- 平均分 -->
<tr align="center">
<!-- 合并列coslpan -->
<td colspan="3">平均分</td>
<!-- <td></td>
<td></td> -->
<td>80</td>
</tr>
</table>
</body>
表格标签的应用----布局
<body>
<!-- 以前的早期布局:table布局 弊端:一旦宽度和高度尺寸变化,整个布局就乱了 -->
<table border="1" width="100%" height="100%">
<tr>
<td>
<!-- 第一部分logo部分 -->
<table>
<tr>
<td>
<!-- 图片logo -->
<img src="img/logo2.png" width="100%" />
</td>
<td>
<img src="img/header.png" />
</td>
<td>
<a href="#">登录</a>
<a href="#">注册</a>
</td>
</tr>
</table>
</td>
</td>
</tr>
<tr style="background-color: black;">
<td>
<a href="#">首页</a>
<a href="#">手机数码</a>
<a href="#">笔记本专区</a>
<a href="#">其他</a>
</td>
</tr>
</table>
</body>
表单标签(form)
表单标签属性
- method:提交方式 默认get请求(用户直接在浏览器访问)
post - action:url 本地提交或者提交后台服务器地址
http://localhost:8080/xxx
表单标签的应用场景
- 注册: (同步)
需要输入用户相关的信息 点击----“注册”------用户的数据提交后台服务器
—查询用户名是否存在,如果存在,不能进行注册了,“请更换用户名”" - 登录(同步)
输入用户名和密码---- 点击登录----服务器里面先通过查询用户名是否存在,
如果存在,就在通过获取到的用户对应的密码和前台提交的密码如果匹配,登录成功,否则登录失败!
get方式和post方式的区别
get方式
- 1)将用户提交的数据 -----提交到后台地址上地址上
url?key1=value1&key2=value2… - 2)因为提交到地址栏上,提交数据大小有限制的
- 3)不适合提交私密数据,相对post不安全
post方式
- 1)不会将用户的数据提交地址上
通过浏览器进行查看:
f12—network网络部分查看 post提交参数
request header 请求头
form-data (实体参数)
key1=value1&key2=value2 - 2)这种方式不提交到地址栏上,提交大小没有限制
- 3)相对get方式,安全一些
- 密码后期都需要处理 加密方式 (md5加密)
123456 ---- "随机字符的值是固定的 - springSecurity:安全卫士(密码进行加密) 更好一些
123456 每次密码随机不一样
<body>
<form action="server.html" method="post">
<!-- 表单项 中必填name属性:需要给后台提交,后台需要知道书写的参数名称 -->
<!-- 文本输入框
placeholder:H5的属性 提示输入的内容,当鼠标光标获取焦点并输入内容,自动清空
-->
用户名:<input type="text" name="username" placeholder="请输入用户名" /><br/>
<!--
input type="password"密码输入框 非明文
-->
密  码:<input type="password" name="password" placeholder="请输入密码"
/><br/>
<!-- 提交按钮 -->
<input type="submit" value="登录" />
</form>
</body>
表单标签常用表单项----输入型
文本输入框,密码输入框,日期组件,邮箱…
必须要指定name属性
input
- type=“text” 文本输入框
- type=“password” 密码输入框
- type="radio"单选按钮
- type="checkbox"复选框
- type="date"日期格式
- type=“eamil” 必须符合邮箱格式@字符
- type=“hidden”:隐藏域(没有效果,可以携带数据)
表单标签常用表单项----下拉菜单
- select标签:普通下拉菜单 选择一个
- option:下列选项
表单标签常用表单项----文本域
textarea
- rows:文本域中指定多少行内容
- cols:一行里面指定多少个字符
表单标签常用表单项----按钮
特殊按钮:提交按钮
input
- type="submit"提交按钮(将表单中的所有表单项中的内容全部提交后台)
跟 input type="submit"等价的一个标签 button
提交 - type=“reset” 重置按钮
普通按钮
- type=“button” value=“点击…”
表单标签常用表单项----举例
<body>
<h3>注册会员</h3>
<form action="server.html" method="get">
<!-- 表单项中必须指定name属性:要给后台标记用户输入的内容 -->
用户名:<input type="text" name="username" placeholder="请输入用户名" /><br />
密  码:<input type="password" name="password" placeholder="请输入密码" /><br />
确认密码:<input type="password" name="repassword" placeholder="请再次输入密码" /><br/>
性别:
<!--
将它同一组信息 name属性值必须一致
-->
<input type="radio" name="gender" value="男" />男
<input type="radio" name="gender" value="女" />女<br />
出生日期
<input type="date" name="birthday" />
<br/>
技术栈:
<!--
将它同一组信息 name属性值必须一致
checked:选中
-->
<input type="checkbox" name="tecknology" value="Spring" />Spring
<input type="checkbox" name="tecknology" value="JDBC" />JDBC
<input type="checkbox" name="tecknology" value="MySQL" />MySQL
<input type="checkbox" name="tecknology" value="MyBatis" />Mybatis<br />
学历:
<!-- multiple 属性:表示多选
multiple="multiple"
-->
<select name="edu" >
<option value="请选择">请选择</option>
<option value="大专">大专</option>
<option value="本科">本科</option>
<option value="研究生">研究生</option>
</select>
<br />
<!-- 文件上传组件 -->
上传照片:
<input type="file" name="img" />
<br />
自我介绍
<textarea rows="5" cols="20">
优秀!
</textarea><br />
<!-- 验证码 -->
<!--
组成:前面是文本输入框
后面可以通过js 的画布来完成也可以通过后台servlet(利用第三方绘制图形)
-->
<!-- <input type="text" placeholder="输入验证码" /> -->
普通按钮
<input type="button" value="点我试试" /><br />
提交按钮
<input type="submit" value="注册" /><input type="reset" value="清空" />
</form>
</body>
格式优雅的表单
form嵌套table
<body>
<form action="server.html" method="get">
<!-- 块标签:占一行 -->
<div>会员注册</div>
<table border="1px" cellspacing="0" width="300px" height="200px">
<tr>
<td>用户名</td>
<td>
<input type="text" name="username" placeholder="请输入用户名" />
</td>
<tr>
<td>密码</td>
<td>
<input type="password" name="password" placeholder="请输入密码" />
</td>
</tr>
<tr>
<td>出生日期</td>
<td>
<input type="date" name="birthday" />
</td>
</tr>
<tr>
<td>性别</td>
<td>
<input type="radio" name="gender" value="男" />男
<input type="radio" name="gender" value="女" />女
</td>
</tr>
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="hobit" value="跑步" />跑步
<input type="checkbox" name="hobit" value="lol" />lol
</td>
</tr>
<tr align="center">
<td colspan="2">
<input type="submit" value="注册" />
</td>
</tr>
</table>
</form>
</body>
框架标签(frameset)
当前这个整个结构4个页面组成
<frameset rows="10%,*,10%">
<!-- 三个部分:分别是frame -->
<frame src="header.html"/><!-- 头部页面 -->
<!-- 从左--到右 -->
<frameset cols="15%,*">
<!-- 两个部分页面通过frame导入 -->
<frame src="menu.html" />
<!-- 给当前中间页面表示的frame给定name -->
<frame src="main.html" name="main" />
</frameset>
<frame src="footer.html" /><!-- 底部页面 -->
</frameset>
顶部(header)
<html>
<head>
<meta charset="utf-8">
<title>logo</title>
</head>
<body>
<img src="../img/index_2.jpg" height="100px" width="95%" />
</body>
</html>
底部(footer)
<html>
<head>
<meta charset="utf-8">
<title>底部页面</title>
</head>
<body>
<center>xxx公司版权所有<sup>©</sup>2021-2025</center>
</body>
</html>
主页(main)
<html>
<head>
<meta charset="utf-8">
<title>主页</title>
</head>
<body>
<p> 欢迎访问该系统</p>
</body>
</html>
图像标签(img src)
img src=“图片资源地址”
- src:加载的图片资源地址 使用的是相对路径
- width和height:宽度和高度属性指定像素,或者指定占当前整个宽高分辨率的百分比
- alt:替代文本,当图片失效是起作用,描述这个图片
- title:给图片设置标题内容,当鼠标悬浮在图片时候,提示文字
<body>
<!--
.. 退出当前目录(访问上级目录)
-->
<img src="../img/1.jpg" width="200px" height="300px" alt="手机图片" /><br />
<img src="../img/mm.jpg" width="200px" height="300px" title="高圆圆" />
</body>