静态代理,动态代理----都属于代理设计模式,让代理角色帮助真实角色完成一个事情;
从代码角度去讲:将业务代码和系统监控相关代码(权限校验,系统日志的产生)进行分离;
静态代理:
特点:
代理角色和真实角色需要实现同一个接口;回想多线程的实现方式第二种
jdk动态代理: 使用反射的方式,在程序执行过程中产生代理对象---->利用反射调用接口中的方法,前提条件
必须基于接口,才能完成jdk动态代理;
删除外键约束
alter table 表名 drop foreign key 外键名称;
添加外键以及以及级联修改和级联删除
alter table 表名 add constraint 外键名称 foreign key (当前字段名称) references 主表名(主键id字段) on update cascade on delete cascade ;
多表查询分类三种
1)内连接
隐式内连接---看不到join关键字,使用where条件
显示内连接---inner join 关键字
2)外连接
左外连接(推荐)
右外连接
3)子查询:select 语句嵌套select语句,
这种场景实际开发使用很少
查询的效率比较低
常用where条件使用比较运算符
或者使用in集合语句
或者使用一条select语句的结果作为一个"虚表"和其他表查询
内连接之隐式内连接 :select 字段列表 from 表名1,表名2 where 连接条件 ;
内连接:显示内连接 :inner join 关键字 :inner可以省略
select 字段列表 from 表名1 inner join 表名2 on 连接条件;
-- 实际开发中:内连接优先使用where隐式内连接(SQL优化的一种)
左外连接和右外连接 (可以将员工表里没有部门的员工展示出来)
-- 左外连接:将左边表数据以及满足两种表条件的数据全部展示;
-- 语法:select 字段列表 from 表名1 left outer join 表名2 on 连接条件
-- outer可以省略
-- 多表查询第三种:子查询
-- 情况1:使用where 条件使用比较运算符
-- 情况2:使用in集合语句
-- 需求:查询在市场部或者财务部的员工信息
-- 1)先查询出市场部和财务部的id
-- select id from dept where name = '市场部' or name = '财务部' ;
-- 2)查询dept_id是2或者3的员工信息
-- select * from emp where emp.`dept_id` in(2,3) ;
-- 子查询的情况3:使用一个select语句查询的结果集 当前一张"虚表"和其他表进行关联查询
-- 需求:查询入职日期大于"2020-01-14"的员工信息以及部门名称信息
-- 1)按照这个条件先查询员工信息
SELECT * FROM emp WHERe join_date > '2020-01-14'
-- 2)将上面查询的结果集当做一张"虚表" 和部门表查询
-- 一步走
SELECt
t.*,
d.name '部门名称'
FROM
(SELECt
*
FROM
emp
WHERe join_date > '2020-01-14') t
LEFT OUTER JOIN dept d
ON t.dept_id = d.id ;
1NF:数据库表中的每一列不可在拆分的原子数据项,必须独立的列;
2NF:在1NF基础上,数据库表中非主键字段必须完全依赖于主键字段,完全依赖是指不能存在仅依赖主键一部分的列。
3NF:在2NF基础上,任何非主列不得传递依赖于主键。
事务:就是当前整个业务操作同时要执行多个sql或者多张表的sql的时候,使用事务将业务整体管理起来,
要么多个sql同时执行成功,要么同时执行失败.
关系型数据库事务的特点(重点)--- 传统型事务的特点
-- ACID
-- 原子性:使用事务管理的业务操作(执行多个sql),要么同时执行成功,要么同时失败
-- 一致性:在事务管理的业务操作过程中,执行之前和执行之后它的数量总量不变
-- 隔离性:业务和业务之间是独立,业务又需要被事务管理,事务和事务之间是独立的,相互之间不影响,分离开来!
-- 持久性:针对增删改操作,只要提交事务,即使关机了,数据永久保存!
事务的隔离级别四种:分别从小到大,安全性(从低到高),执行效率(从高到低)
read uncommitted;读未提交,会导致最严重的问题 "脏读"(一个事务读到另一个没有提交事务)
read committed; 读已提交,可以有效防止脏读,但是会现在一个问题"不可重复读"(在提交事务之前和事务,数据 不一致!)
repeatable read;可重复读(mysql默认隔离级别) , 可以有效防止脏读以及不可重复读,会出现"幻读"
serializable; 串行话 级别最高,安全性最高,效率低!
-- 修改隔离等级
-- set global transaction isolation level 级别的名称;
缩写JDBC,全称"Java Database Connectivity",Java数据库链接
JDBC的本质:
他是一个普通的java类,数据库厂商提供,可以实现sun公司提供的一套"应用程序接口规范"
java.sql.Driver 驱动接口
java.sql.connection 连接数据库的接口
JDBC七大操作步骤:
1)//mysql5.1以上5.7以下 的jar包"com.mysql.j dbc.Driver"
如: Class.forName("com.mysql.jdbc.Driver");
//mysql8.0的jar包 "com.mysql.cj.jdbc.Driver"
如: Class.forName("com.mysql.cj.jdbc.Driver");
2)获取数据库的连接对象
//java.sql.DriverManager:里面有静态方法获取数据库连接对象
// public static Connection getConnection(String url, //统一资源定位符
// String user, // 当前mysql的用户名 root 用户
// String password)throws SQLException //当前mysql的登录密码
如:Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/myee_2203_02", //库名
"root",
"123456"
);
3)准备好的sql语句
如: String sql = "insert into account(name,balance) values('高圆圆',1000)";
4)获取数据库的执行对象---执行sql语句
//通过连接对象获取 Connection--- Statement createStatement():创建执行对象,准备将sql发送数据库
如: Statement stmt = conn.createStatement();
5)数据库的执行对象 去操作数据库
//Statement--->int executeUpdate(String sql)
如: int count = stmt.executeUpdate(sql);
6)返回结果
如:System.out.println("影响了" + count + "行");
7)释放资源
如:stmt.close();
conn.close();
1)执行sql效率区别
Statement每一次需要将静态化的sql进行发送给数据库, 写好一条sql,发送一次,相对PreparedStatement预编译对象来说,执行sql效率非常低!
PreparedStatement将编译参数化的sql(占位符号?)发送给数据库,数据库会校验它的列索引值以及对应的类型,将sql保存到预编译对象中预编译对象可以赋值不同的参数,执行对应sql,执行效率相对Statement高很多!
2)是否会造成"SQL注入"
Statement对象发送的sql属于静态sql语句,存在"硬编码",而且还有字符串拼接,就会造成sql注入,非常不安全的一种行为!
PreparedStatement对象发送的sql都是参数化的sql,不存在字符串拼接,不会造成sql注入,相对Statement是一种安全行为!
junit单元测试jar包
@Test:标记方法为单元测试方法,里面包含启动器,可以启动运行
@Before:标记它执行的这个方法是在单元测试方法前先执行,一般:初始化的操作
@After:标记它执行的这个方法是在单元测试方法之后执行,一般:释放系统资源放在这个标记的方法中
//原生操作步骤
//1.导包 驱动包:5.1jar/8.0以及它以上的jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//3.获取数据库的连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/库名",
"root",
"登录mysql的密码"
) ;
//4)准备好参数化的sql语句 DML语句
String sql = "insert into 表名 values(?,?,?...)" ;
String sql2 = "update 表名 set 字段名称1 = ?,字段名称2 = ?,字段名称3 = ? where 字段名称 = ?" ;
String sql3 = "delete from 表名 where 字段名称 = ?" ;
//sql语句:参数化的DQL语句
String sql4 = "select * from 表名 " ;
String sql5 = "select * from 表名 where 字段名称 = ?" ;
//...
//5)获取预编译对象,同时将sql发送给数据库
PreparedStatement ps = conn.prepareStatement(sql) ;
//6)通过预编译对象,参数赋值
ps.setXXX(占位符号的索引值,XXX类型的实际参数) ;
//7)要么执行DML语句
int count = ps.executeUpdate() ;
//影响的行数 count
//要么执行的DQL语句
ResultSet rs = ps.executeQuery() ;
while(rs.next()){
//获取结果数据
XXX 变量名 = rs.getXXX("列的名称要么列的索引值") ;
}
//释放资源
//执行dql语句,
//执行dml,只需要释放后面两个对象 ps对象以及conn对象
rs.close();
ps.close();
conn.close() ;
数据库连接池:
可以分配,释放,管理数据库连接对象,当前某个连接对象释放之后,会归还到连接池中,大大提高了JDBC操作数据库性能!
弊端:维护成本高; (维护它druid的版本以及监控它的连接数量)
好处:可以设置参数,将数据库连接池进行调优;
每一个线程都会使用自己的连接对象!
前某个连接对象释放之后,会归还到连接池中,等待下一次利用(大大提高了连接对象的使用率)
完成jdbc操作
使用步骤:
1)需要导入核心的jar包 commons-dbtils.jar
mysql驱动jar包
连接池--druid的jar包
junit单元测试:核心包junit.jar以及依赖包
2)有关commons-dbtils.jar 核心接口以及核心类有哪些
使用的执行对象:操作数据库
org.apache.commons.dbutils.QueryRunner 里面封装就是PreparedStatement
两个通用的方法
query(xxx,ResultSetHandler rsh):针对dql语句来完成查询操作
update(xxx,xx):针对dml域操作:insert into,update,delete from ....
jdbc管理事务
使用Jdbc控制事务--->通过获取连接对象之后,加入事务的方法 通过工具类获取连接对象 开启事务---->利用Connection的功能void setAutoCommit(boolean autoCommit):默认自动提交 参数为false:禁用自动提交,需要手动提交事务 准备sql---参数化sql 获取预编译对象 参数赋值 执行更新操作 提交事务: 如果没有问题,提交事务---数据在能永久更新 Connection对象的方法:void commit() 出现异常,程序执行catch语句 事务回滚 连接对象的方法void rollback():回滚到默认在更新之前的操作



