17.Mysql数据库:数据库就是一个文件系统,但是这个文件访问需要通过标准SQL语句.
1.关系型的数据库:
保存的是实体之间关系.
常见的关系型数据库: MYSQL、SQLServer、Oracle、DB2、SyBase、SQLite
2.MYSQL内部存储结构:
一个软件对应一个数据库,在数据库内部可以存在多张表:一个实体类对应一张表.表中可以有多条记录的.
一般情况下:一个类的实例对应一条记录.
3.SQL:结构化查询语言.(Structured Query Language)
特性:
非过程性语言:一条语句的执行,就会有一个结果.不需要依赖其他语句.
/** SQL的分类:
* DDL :Data Definition Language.数据定义语言. // 无事务
* create 、alter、drop ...
* :Data Manipulation Language.数据处理语言. //事务
* update 、 insert 、 delete...
* DCL :Data Control Language.数据控制语言.
* if 、grant...
* DQL :Data Query Language.数据查询语言.
* select
SQL对数据库 进行操作:(CRUD)// 属于DDL语句
create database 数据库名
drop database 数据库名;
show databases;
alter database 数据库名 character set 字符集 collate 校对规则;
use 数据库名;
select database();
SQL语句对数据库中 表 进行操作:(CRUD) // 属于DDL语句-
create table 表名 (字段名 字段类型(长度) 约束,字段名 字段类型(长度) 约束..)character set 字符集 collate 校对规则;// char:固定长度varchar:可变长度
// long = BIGINT boolean = BIT byte = TINYINT short = SMALLINT
// File = BLOB/TEXT BLOB :存放一个二进制文件. TEXT:存放一个文件文件. 在Oracle数据库中用BLOB和CLOB
show tables; desc 表名;
drop table 表名;// 删除整个表 truncate table 表名: 删除整个表,创建一个新的表 DDL 无事务
// delete 是一条记录一条记录的删除DML 有事务回滚*/
SQL对数据库中表中的记录进行操作:(CRUD)// 属于DML语句(insert,update,delete)
/*有事务*/
insert into 表名 (字段名1,字段名2,字段名3...) values (值1,值2,值3...);
insert into 表名 values (值1,值2,值3...);// 字符串或者日期类型 单引号引起来
update 表名 set 字段名 = 值,字段名=值 [where 条件];
delete from 表名 [where 条件];
truncate table 和delete from 区别 逐条删/整表删
select 表达式 from 表;like:模糊查询. 占位符:_和% is null / is not null and , or ,not in:一组值
order by 列名 asc/desc;group by 列名;
count(*) sum(math) avg(math) max(math) min(math)
where => having group by product having sum(price) > 2000; //where后使用聚合函数 where => having
* select *|列名 from 表名 where 条件 group by 列名 having 分组条件过滤 order by 列名;
// 列:group by有哪些列,select下才能写哪些列 (除此,还可以写count()、sum()...聚合函数)
// 分组:group by后 再加 分组条件 ,用having 也是前后对应 ,后面写啥,前面才能写啥
SQL语句的多表操作:
笛卡尔积查询:select * from A,B;
内连接:inner join.// 交集
隐式内连接:select * from A,B where 条件;
显式内连接: select * from A inner join B on 条件;//inner 可以省略
外连接:outer join
左外连接:// 左边表的全部以及两个表的交集 select * from A left outer join B on 条件; A:A表数据会全部显示 ==> 全量表
右外连接:// 右边表的全部以及两个表的交集select * from A right outer join B on 条件; B:B表数据会全部显示 ==> 全量表
子查询:指的是一条语句的查询结果需要依赖另一条语句的查询结果.// any:任意一个. all:所有.
18.JDBC:Java语言连接数据库!是一种用于执行SQL语句的Java的API.可以为多种关系型数据库提供统一的访问.(Java DataBase Connectivity Java数据库连接). 是一个总的数据库连接概念!! !
JDBC就是SUN提供规范,厂商提供实现!我们就使用其API来操作数据库!
由Java语言编写
功能:主要就是使用Java语言连接到数据库.
使用:只要与数据库交互
驱动:java连接数据库,必须使用数据库的驱动
JDBC规范:SUN提供接口,数据库厂商提供实现!===> 即:提供各自数据库的 API
JDBC的API:
反射: Class.forName("...")
连接对象:Connection <——— DriverManager
1.创建执行SQL语句的对象: prepareStatement(sql) / ...
2.进行事务的管理: commit() / rollback() / setAutoCommit()
执行SQL的对象:Statement
executeQuery() / executeUpdate() / execute()
结果集:ResultSet
//在ResultSet内部维护了一个指向表格数据行的游标Cursor,初始化时候,游标在第一行之前的位置.调用ResultSet中next()方法.可以使游标指向具体的数据行,进而调用方法获得该行的数据
next() / getInt(..) / getString(..) / getObject(..)
滚动结果集: MYSQL数据库结果集可以滚动. 创建时设置参数即可: createStatement(int resultSetType,int resultSetConcurrency); // 默认是不可
释放资源: close() // 晚创建,早释放!!!
JDBCUtils:解析jdbc.properties文件 , 获取连接 , 关资源//原始JDBC,是手动创建连接,销毁连接!—————从连接池获取连接———> C3P0、DBCP(获取连接,归还连接,创建交给连接池管理)
SQL注入的漏洞:PreparedStatement对象预编译sql
配置文件: jdbc.properties文件
1.2数据库连接池:就是一个装有很多连接的一个容器.使用连接的时候,直接可以从连接池中获取.用完以后归还给连接池. // 提升程序的性能.对程序进行优化
DBCP:数据库连接池。 (DataBase connection pool)
是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar
由于建立数据库连接是一个非常耗时耗资源的行为,
所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。
API; BasicDataSource: 用于手动配置DBCP连接池.
BasicDataSourceFactory: 使用配置文件的方式配置连接池. // 半自动解析
配置文件: dbcp.properties文件
C3P0:是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
----- C3P0包内部自动识别"c3p0-config.xml"文件,并自动解析,这也是一种规范(C3P0规范) 在java中我们可以见到很多规范!!! ————>这也是C3P0好用的一个体现
当然,我们也是可以手动赋值的,ComboPooledDataSource类中就提供了所有的setXXX()方法
API: ComboPooledDataSource (连接池类) //重写了 conn.close() 归还连接
// 这个类就是一个连接池容器,为我们封装了很多连接,并提供了getConnection() 我们直接从此对象中获取连接
使用C3P0连接池改造JDBC的工具类:
配置文件: c3p0-config.xml// 自动解析
Tomcat内置JNDI连接池: Java命名和目录接口,将一个对象与一个名称进行绑定,通过名称查找到指定的对象.
Service的事务:事务要加在业务层. 因为在DAO中不是开启事务的最好的地方.
一个业务层中需要调用多个DAO中的方法的时候,那么每个DAO中的Connection都不是同一个对象.
不是同一个对象的话,开启的事务就不会在同一个事务中.
1.3事务:指的是逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败!
MYSQL中事务管理: MYSQL数据库事务是自动提交.执行一条SQL后,事务就会被提交.
1.MYSQL命令: // 用 Mysql数据库 自身的命令 !!! ——————>直接
使用MYSQL中命令进行事务的管理:
* start transaction;--开启事务.
* 执行操作
* commit; --提交事务.
* rollback; --回滚事务.
修改参数:
查看MYSQL中的与commit相关参数,通过修改参数的方式进行事务的管理.
SHOW VARIABLES LIKE '%commit%';
set autocommit = 0; --0:OFF1:ON(默认)
JDBC中事务管理: // 用 java代码 操作数据库的方式!!! ——————>间接
1.API: // 用 Connection 对象操作
setAutoCommit(boolean autoCommit); true:自动 / false:手动 ————>等同于 start transaction(mysql命令) 开启了一个事务
commin() / rollback()
2.事务管理的保存点: 类似于游戏中的存档.
setSavepoint() / rollback(savepoint)
3.事务的特性:(面试)
原子性:(Atomicity)
原子性:强调事务的不可分割.
一致性:(Consistency)
一致性:事务在执行的前后,数据的完整性保持一致.
隔离性:(Isolation)// 安全问题!!! 并发
隔离性:多个事务并发执行的时候,一个事务的执行不应该受到其他的事务的干扰.
持久性:(Durability)
持久性:事务如果结束了.数据就永久的保存到数据库.
4.不考虑事务的隔离性.引发一些安全性问题: // 都是在一个事务内的问题 我们的解决思路就是:限制你在本次事务内的读取,必须新开事务才能获取到更新数据!!!
3类读问题:
脏读 : 一个事务读到了另一个事务未提交的数据. //那就让他 只能读取 已提交 的数据
不可重复读 : 一个事务读到了另一个事务已经提交的update的数据,导致在一个事务中多次的查询结果不一致. //那就让他 可以重复读取 在提交前后读取的数据不变
//不可重复读:可解释为————当B提交update事务后,A 就不能再读取!!! 若A非要再读取,就会导致~~~ so,我们命名为:不可(以)重复读!!!
虚读/幻读 :一个事务读到了另一个事务已经提交的insert的数据,导致在一个事务中多次查询的结果不一致. //那就让他 可以串行化读取----必须等待对方
//提交事务后,才会执行这边的事务
解决读问题: 数据库中提供了 事务的隔离级别!!!
// 此处隔离级别的设定,自然是针对查询者B而言
* read uncommitted:未提交读. 脏读、不可重复读、虚读 都是有可能发生.// A不提交 B也能查到 数据被修改了
//并发访问
1.此时只要A执行了SQL语句,无论是update、还是insert,且无论是否提交了事务,B每次都能查询到被A更新的数据!!!
// 当A 执行sql语句前 B读到1,当A 执行了sql 但未提交前 B读到2 , 当A提交后 B读到2 A 还没有提交 B就获取了数据更新!!!
* read committed:已提交读. 避免脏读.但是 不可重复读、虚读 是有可能发生. (开发用) // A必须提交 B才能读到
// 并发访问
1.避免脏读: // 当A update未提交前 B读到1 , 当A提交后 B读到2只有A提交了事务,B才能获取到新的数据!
1.不可重复读: // 当A update未提交前 B读到1 , 当A提交后 B读到2 导致B在同一个事务中,两次查询的结果不同
2.虚读: //当A insert未提交前 B读到1 , 当A提交后 B读到1,2 导致B在同一个事务中,两次查询的结果不同
* repeatable read:可重复读. 避免脏读、不可重复读.但是 虚读 是有可能发生.// A update就算提交 B也读不到 除非重开事务
// 并发访问
1.避免了脏读、不可重复读:
// 当A update未提交前 B读到1 , 当A提交后 B仍然读到1
1.虚读: //当A insert未提交前 B读到1 , 当A提交后 B读到1,2导致B在同一个事务中,两次查询的结果不同
* serializable:串行化的. 避免脏读、不可重复读、虚读的发生.// A insert不提交 B查询只能一直等待 不可并发访问!!!
// 直接不让 并发访问!!!
// 只能排队 一个一个来
1.避免了脏读、不可重复读、虚读:
// 当A update未提交前 B等待A提交, 当A提交后 B读到更换后的数据
// 当A insert未提交前 B等待A提交, 当A提交后 B读到更新后的数据
serializable:是串行的.一个事务没有结束.另一个事务不会执行的.(不存在事务的并发访问情况.)
// 当A 执行了insert命令,但未提交前, B的select事务 必须一直等待A 提交事务之后, B的访问事务才会执行!!!
serializable的一方 没有并发访问————需等待!!!
增删改——————可并发执行——————无需等待!!!
// 且若B 执行了DML指令 A也是要等待B提交事务之后,才会执行B的sql(事务)!
非 serializable的一方 并发访问的 可直接执行select操作!!!
增删改————不并发 , 需等待!!!
* 安全性:serializable > repeatable read > read committed> read uncommitted
* 效率性:read uncommitted > read committed > repeatable read > serializable
***** MYSQL数据库默认隔离级别:repeatable read .Oracle数据库默认的隔离级别:read committed
* 查看当前数据库的隔离级别:
* select @@tx_isolation;
* 设置事务的隔离级别:
* set session transaction isolation level 隔离级别;
2类写问题: // 都叫:丢失更新
--- A修改了name,未提交前, B又修改了money,未提交. A提交后,B再提交或者回滚的时候,都会将之前事务修改的字段的值覆盖掉 .
解决丢失更新:
* 悲观锁:假设丢失更新是一定存在.使用了数据库中的一种锁机制.(排它锁)
* 乐观锁:假设丢失更新不一定存在.使用是时间戳或者版本号解决方案.
3.元数据:在JDBC的程序中获得数据库,表,表中的字段的信息.
1.为什么要学习元数据?
编写一些通用性较高的代码,编写一些框架.
2.元数据的分类:
数据库元数据:DatabaseMetaData// 通过Connection中的方法获得: conn.getMetaData();
API:(API即功能)
* 获得连接基本信息: getDriverName() / getURL() / getUserName()
* 获得数据库中表的信息: getTables()
参数元数据: ParameterMetaData // 通过PreparedStatement中方法获得: stmt.getParameterMetaData();
API:
* 用来获得SQL语句中的参数的个数,参数类型. getParameterCount() / getParameterTypeName(i) ————>// MYSQL数据库对参数元数据获得类型名称支持的不好!!!
————>// 这可以帮我们很好的理解,java中动态注入参数的方法args[]
结果集元数据:ResultSetMetaData // 通过ResultSet中的方法获得: rs.getMetaData();
API:
* 获得列的个数,列的类型,列的名称:getColumnCount() / getColumnName(i) / getColumnTypeName(i)
4.DBUtils:Apache组织提供的一个对JDBC进行简单封装的开源工具类库,简化JDBC应用程序的开发.//commons-dbutils-1.4.jar
1.核心类:
DbUtils
API: commitAndCloseQuietly(conn) / rollbackAndCloseQuietly(conn)
QueryRunner
构造: new QueryRunner() // 使用没有传入DataSource的构造方法:(带有事务的操作:需要手动操作)
new QueryRunner(DataSource) // 使用传入DataSource的构造方法: (不带有事务的操作:每条SQL————独立事务)
API: update(增删改) / query(查)
2.ResultSetHandler的实现类:
ArrayHandler / ArrayListHandler ————> 将一/多条记录封装到一个装有Object数组的List集合中Object[] / List<Object[]>
BeanHandler / BeanListHandler————> 将一/多条记录封装到一个装有JavaBean的List集合中Account / List<Account>
MapHandler / MapListHandler————> 将一/多条记录封装到一个装有Map集合的List集合中Map<String, Object> / List<Map<String, Object>>
ColumnListHandler:将表的某列的数据封装到一个List集合中.
ScalarHandler:单值封装.
KeyedHandler:将多条记录封装到一个装有Map集合的Map集合.Map集合的key可以指定的.
5.JDBC案例:客户管理系统:Servlet + JSP + JavaBean + JDBC(/DBCP/C3P0)
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
2.表单重复提交问题:不停点击刷新.重复提交数到数据库中.
* 表单重复提交的问题:// 可以使用重定向方式进行解决??? 不行!!!
/** ******************** 根本解决表单重复提交:
* 令牌机制:
* 在保存页面上生成一个令牌:随机的字符串.
* 将令牌保存到session中:
* 将令牌放入到表单的隐藏字段中:
* 当点击提交的时候:
* 表单中令牌和session中令牌在servlet中都可以获得到.
* 比对两个令牌是否一致:
* 如果一致:提交.
* 如果不一致:跳转到一个错误页面.
* 将session中令牌清空.*/
3.分页查询:主要解决页面的数据加载的过多,导致页面访问速度过慢. //开发中 逻辑+物理 结合使用
// Mysql: select * from 表 where 条件 ... limit startNum,endNum; Oracle : 使用SQL语句嵌套. SQL Server : 使用top关键字.
/* 分页:—————— 前五后四
开始记录数: startNum = (pageNo - 1)*pageSize; // pageNo:当前页数 pageSize:每页显示记录数
结束记录数: endNum = pageNo*pageSize + 1;
*/
* 逻辑分页: 一次性将数据库中所有记录全部查询处理.查出来以后存放到一个List集合中.使用List集合中方法subList()对List集合进行截取.
* 优点:减少与数据库交互次数.
* 缺点:数据量非常大.查询时间比较长.
* 物理分页: 不是一次性将所有数据全部查询出来.查询第一页:发送一条查询10条的SQL语句.查询下一页数据:又发送一条查询后10条的SQL.
* 优点:数据量非常小.查询时间比较短.
* 缺点:与数据库交互次数变多.
4.监听器:监听器就是一个实现了特定接口的Java类.这个Java类用来监听另一个Java类的方法调用或者属性改变.当被监听的对象发生上述的事件后.监听器某个方法就会立即执行.
事件源 :被监听的对象.(汽车)
监听器 :监听的对象.(报警器)
绑定监听器: 在事件源绑定监听器.(汽车上安装报警器)
事件 :就是事件源的改变.事件源一旦发生变化.事件就会传递给监听器对象.监听器的相应的方法就会执行.(踢了汽车一脚,报警).
***** 事件封装了事件源的改变. // 作用: 在监听器对象 中获得 事件源对象.
4.1.Servlet的监听器:监听器,过滤器都属于Servlet技术中的高级部分.
Servlet的规范中提供了8个监听器:
一类 :监听三个域对象的创建和销毁的监听器.(ServletContext,HttpSession,ServletRequest)// ServletContextListener ...
二类 :监听三个域对象的属性变更的监听器.(属性添加,属性移除,属性替换)// ServletContextAttributeListener ...
三类 :监听HttpSession对象中的JavaBean的状态的改变.(绑定,解除绑定,钝化,活化)// HttpSessionBindingListenerHttpSessionActivationListener
与传统的监听器的不同:
* 事件源 :ServletContext,HttpSession,ServletRequest.
* 监听器 :Servlet规范中提供的一组监听器的接口.ServletContextListener,HttpSessionListener,ServletRequestListener...
* 将事件源与监听器进行绑定:——————进行配置:web.xml中完成配置即可.
//一类: 一二类 ——————>web.xml中配置
ServletContextListener监听器作用: 加载框架的配置文件 —————> Spring框架
HttpSessionListener的作用: 进行session扫描 —————> 记录网站的在线人数!
...
问题:
* 访问一个Servlet会不会创建session对象.
不会的!
* 访问一个HTML页面会不会创建session对象
不会的!
* 访问一个JSP页面会不会创建session对象. // jsp ————显示数据
// 会的!!! ———————— 四大域对象 内置的!!! _service()方法默认声明九大内置对象
问题: // 只要发送了请求,就会...
* 访问一个Servlet会不会创建request对象.
会!
* 访问一个JSP会不会创建request对象
会!
* 访问一个HTML会不会创建request对象// 向服务端请求了页面 只要发送请求,就会...
会!
//三类: ————————>这类监听器不需要进行配置:* 需要让JavaBean自己感知在session中状态.
Session的钝化实质是对于session的优化手段!!!
* 将长时间不使用的session使其序列化. // 在context.xml中,可手动配置Session的序列化
4.2.在线踢人案例
将List< Map<"QQ",session("QQ",QQ)> >存放到ServletContext范围 Map:每个用户 key:用户名 value:此用户的session 从List中add() / remove()即可
/** 在线踢人案例的BUG分析及解决:
1:用户重复登录问题:
重写User类的hashCode和equals方法
* 只要ID相同认为是同一个对象.
2:用同一个浏览器,先后使用不同的账号进行登录:
第二次登录用户,将第一个登录的用户踢出.
* 第一个用户的session保存的其他的信息还是存在.
解决办法:
* 当用户登录的时候,将之前的session销毁.
3:使用不同浏览器,先后使用同一个账号进行登录:
第二个登录的用户将第一个登录的用户从map集合中踢出了!
* 第一个登录的用户没有在Map集合中,而且session没有销毁.导致这个用户不能被踢.
解决办法:
* 当用户登录的时候,先去判断用户是否已经在列表中.
* 如果在列表中:已经登录过.将登录过的用户的session取出,进行销毁.*/
java学习笔记————本质篇4
最新推荐文章于 2024-05-18 20:33:30 发布