java学习笔记————本质篇4

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取出,进行销毁.*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值