where条件后面跟表达式(关系运算符/逻辑运算符 ||(or) &&(and) between...and... )
1) 查询年龄大于20岁的所有的学生的id,姓名,年龄,性别,地址
SELECT
id '编号',
NAME '姓名',
age '年龄',
sex '性别',
address '地址'
FROM
student
WHERE
age >20 ; -- 比较运算符
2) 查询学生年龄不等于20岁的学生的信息 Java中的语法!=
SELECT
*
FROM
student
WHERE
age !=20 ;
3) 优化上面sql---使用mysql符号 <> 不等于 :等价于 !=
SELECT
id,
NAME,
age,
sex,
address
FROM
student
WHERE
age <> 20 ;
4) 查询年龄在20-30岁之间的学生信息
-- (Java中逻辑符号呢?&& 可以,数据库and ,使用between 值1 and 值2)
SELECT
id,
NAME,
age,
sex,
address,
math,
english
FROM
student
WHERE
age>=20 && age<=30 ; -- Java中的逻辑符号-- age>=20 AND age<=30 ; mysql有自己的连接符号 :and 表示并列
-- age BETWEEN 20 AND 30 ; 使用between 值1 and 值2
5) 要查询英语成绩为null的学生信息
-- 数据库中:某个字段名称 is null /某个字段名称 is not null
SELECT
id,
NAME,
age ,
address,
english
FROM
student
WHERE
english IS NULL ;
-- -- 要查询英语成绩不为null的学生信息
SELECT
id,
NAME,
age,
address,
english
FROM
student
WHERE
english IS NOT NULL ;
(6) -- 要查询年龄是18或者20,或者30的学生信息
-- || 或者 or ;
-- 关键字in(集合数据)某个字段在是某个集合中的一个的时候:字段名称 in(值1,值2,值3...) .
SELECT
*
FROM
student
WHERE
age =18 OR age = 20 OR age = 30 ;
SELECT
*
FROM
student
WHERE
age IN(18,20,30) ;
模糊查询 关键字 like
格式: select 字段列表 from 表名 where 字段名称 like '包含%符号或者_下划线符号'
show variables like '%character%' ; 查询当前mysql数据库中变量包含"character"的字符集
模糊查询的应用场景: 搜索框---关键字搜索
%:包含的任意字符 姓名包含姓马的人 '%马%'
_:代表的是单个字符 姓名中第二个字符是化的学生新 '%_化%'
1) 查询学生姓名中包含马的学生
SELECT
*
FROM
student
WHERE
NAME LIKE '%马%' ;
2) 姓名中第二个字符是化的学生新'%_化%'
SELECT
*
FROM
student
WHERE
NAME LIKE '%_化%' ;
3) 姓名包含三个字符的人的信息
SELECT
*
FROM
student
WHERE
NAME LIKE '___' ;
聚合函数-- 一般查询都是单行单列的数据
-- count(字段名称) 查询总记录数
字段名称:一般情况使用的非业务字段-- max(字段名称) 求某个列中的最大值
-- min(字段名称) ...最小值
-- sum(字段名称) 针对某个字段列表进行求和
-- avg(字段):针对某个字段列求平均分
SELECT
COUNT(IFNULL(english,0)) '总记录数' -- ifnull(字段名称,预期值)
FROM
student ;
-- count(表中的id字段:非业务字段,开发中都会设置为主键并且自增长)
SELECT
COUNT(id) '总人数'
FROM
student ;
-- 查询数学成绩的最高分
SELECT
MAX(math)
FROM
student ;
-- -- 查询英语成绩的最低分
SELECT
MIN(IFNULL(english,0)) '最低分'
FROM
student ;
-- 求数学成绩的平均分
SELECT
AVG(math) '数学平均分'
FROM
student ;
格式: select 字段列表 from 表名 order by 字段名称 排序方式;
排序方式:
1) 升序: asc 当字段名称后面没有带排序方式(默认使用升序)
2) 降序: desc
-- 将学生成绩按照升序排序
SELECT
*
FROM
student
ORDER BY
math ; -- 不带排序方式:默认 asc
-- 将英语成绩按照降序排序
SELECT
*
FROM
student
ORDER BY
english DESC ;
分组查询 - group by
分组查询的时候,可以查询分组的字段
1) 按照性别分组,查询他们的数学的平均分以及总人数
SELECT
sex '性别',-- 可以查询分组字段
COUNT(id) '总人数',
AVG(math) '数学平均分'
FROM
student
GROUP BY
sex ; -- 性别分组
2) -- 按照性别分组,查询他们的数学的平均分以及总人数
数学成绩不大于70分的人不参与分组
SELECT
sex '性别',-- 可以查询分组的字段
COUNT(id) '总人数',
AVG(math) '数学平均分'
FROM
student
WHERE
math > 70 -- 在前
GROUP BY
sex ; -- 在后
重点: 在分组:如果sql语句中存在where语句以及group by语句,先进行条件,然后再分组,group by 的后面不能where 语句,where 必须在group by之前;group by的后面不能使用聚合函数!
按照性别分组,查询他们的数学的平均分以及总人数
1):数学成绩不大于70分的人不参与分组
2):筛选出总人数大于2的一组
SELECT
sex '性别',
AVG(math) '数学平均分',
COUNT(id) '总人数'
FROM
student
WHERE
math > 70 -- 条件
GROUP BY
sex -- 分组
-- 筛选出总人数大于2的一组
HAVING
COUNT(id) > 2 ;
-- 优化
SELECT
sex 性别,
AVG(math) 数学平均分,
COUNT(id) 总人数
FROM
student
WHERE
math > 70 -- 条件
GROUP BY
sex -- 分组
-- 筛选出总人数大于2的一组
HAVING
总人数 > 2 ;
重点:having和group by 的区别
having后面可以使用聚合函数,而group by 的后面不能使用聚合函数查;
如果存在where 语句,group by,having,先where条件,然后分组group by ,然后筛选having;
分页查询(重点) limit (mysql和oracle有方言差异这个这个语法上)
格式: select 字段列表 from 表名 limit 起始行数(起始索引),每页显示的条数;
起始行数(起始索引):从0开始计算 = (当前页码-1)*每页显示的条数
-- 查询当前学生表中第一页数据,每页显示2条数据;
SELECT
*
FROM
student
LIMIT 0,2 ;-- 查询第二页的数据
-- 起始行数= (2-1)*2
SELECT
*
FROM
student
LIMIT 2,2 ;
约束:约束用户操作表时候的行为,防止无意义的数据在表中存在!
-- 默认约束 default 设置一个默认值,当字段为空时自动使用默认值
-- 非空约束 not null 字段值不能为空
-- 唯一约束 unique 字段值不能重复
-- 主键约束 primary key 非空且唯一
-- 自增长约束 auto_incrment 默认从字段行开始,从0开始自增1,一直往前移动
-- 外键约束 foreign key
-- 外键约束基础,可以进行级联操作(级联修改和级联删除)CASCADE
CONSTRAINT dept_emp_fk -- 声明 跟的外键名称(第一位根据情况命名)
FOREIGN KEY (dept_id) -- 作用在外键上
REFERENCES dept(id); -- 关联与主表的主键id
级联操作:CASCADE
用户在操作主表的时候,跟主表相关的从表的数据也随之更改;
如果不使用操作:针对修改或者删除,都应该先执行从表,然后主表;
级联删除和级联修改: on delete cascade /on update cascade
数据库的备份:需要将数据库进行存储(计算机磁盘上或者是硬盘)
-- 方式1:命令行的方式
-- 方式2:图形界面化的方式:简单/直观/易于上手
进入dos控制台:mysqldump -uroot -p密码 数据库 > 磁盘地址...
还原过程
-- 方式1:命令行方式
mysql8---进入mysql自动控制台或者dos登录mysql
先将数据库删除掉,重新创建一个新的库,使用这个use 库名
souce 将备份的地址 (自动将原先备份的库中的表数据全部执行)-- 方式2:图形界面化
在sqlYog或者navicat里面都可以用,直接将库选中, 删除,删除之后,
在创建的新库右键---选择 import---> Execute Sql Scripts:执行sql脚本
选择备份的地址,直接执行sql文件!
三大范式:呈递次规范(每一个范式依赖上一个范式)
1NF:(最基本范式)
第一范式
数据库表中的每一列是不可在拆分的原子数据项(是一个独立的列)
2NF:
第二范式
满足第一范式基础上,
每一张表的非主键字段(列)必须完全依赖与主键字段,不能产生部分依赖!
3NF
第三范式
满足第二范式基础上(非主键字段必须完全依赖主键字段)
非主键字段不能产生传递依赖
主键--->非主键字段---->非主键字段
解决方案:拆分出来外键约束:可以消除传递依赖/而且降低字段冗余
分类:
-内连接查询
隐式内连接
显示内连接
-外连接查询
左外连接
右外连接
-子查询
情况1:单行单例
情况2:多行多列
复杂查询...
1) 内连接查询
<1>隐式内连接 where语句作为条件
格式:
select
字段列表 1)查询哪些字段
from
表名1,表名2 2)查询哪些表
where
连接条件; 3)连接条件
<2>显示内连接
select
字段类别
from
表名1
inner join 表名2
on
连接条件;
多表查询,连接条件不是很多的情况下;尽量采用隐式内连接使用where(sql优化的一种)
2) 外连接查询
<1> 左外连接(推荐)
将表名1中所有的数据全部查询以及他们的交集的数(满足连接条件数据)据查询出来!
格式:
select
字段列表
from 表名1
left outer(outer可以省略) join 表名2
on
连接条件;
<2> 右外连接
将右表中所有的数据全部查询以及他们的交集的数(满足连接条件数据)据查询出来!
格式:
select
字段列表
from 表名1
right outer join 表名2
on
连接条件;
3) 子查询 (select语句嵌套select语句实现)
<1>子查询情况1:单行单例的结果
-- 利用where条件后面可以携带比较运算符<=,>=,<,>,赋值运算符 =:
例: 查询小于平均工资员工的人
SELECT
*
FROM
emp
WHERE
salary < (SELECT AVG(salary) FROM emp ) ;
<2>子查询情况2: 多行多列的情况
--查询数据的时候 利用or或者in语句 :
例: 查询在2号或者在3号部门的员工信息
SELECT
emp.`NAME` '员工姓名',
emp.`gender` '性别',
emp.`salary` '工资',
emp.`join_date` '入职日期',
emp.`dept_id` '部门编号'
FROM
emp
WHERE
dept_id = 2 OR dept_id = 3 ; -- or 使用in(集合数据) in(2,3)
<3>子查询之复杂查询:
-- 按照需求中给定的已知条件先查询,查出的结果,当做一张虚表继续和当前表进行联合查询
例: 查询入职日期大于'2019-03-14'号的员工信息以及所在的部门信息
SELECT
id,
NAME,
gender,
salary,
join_date,
dept_id
FROM
emp
WHERE
join_date > '2019-03-14' ; -- 入职日期大于'2019-03-14'
-- 将上面查询的结果继续和另一张部门表进行查询SELECT
t.*,
d.`name` '部门名称'
FROM
(SELECT
id,
NAME,
gender,
salary,
join_date,
dept_id
FROM
emp
WHERE
join_date > '2019-03-14') t
LEFT OUTER JOIN
dept d
ON
t.dept_id = d.`id` ;
创建视图
-- create view 视图名 as select 语句
CREATE VIEW
myview -- 一张虚表:名称 myview --虚拟表中隐藏的数据看不到的
AS
SELECT id,NAME,gender,age FROM stu_test
WHERE id < 4 ;SHOW FULL TABLES ; -- 查询的表的时候,查询表的类型
虚表类型为 VIEW
第一种情况:添加视图的检查语言:当前虚拟表中添加不满足条件的数据,直接报错
-- 修改视图
-- alter view 视图名字(虚拟表名称) as select 语句 条件查询 with check option ;第二种情况:视图中不能使用系统或者用户变量的
-- mysql中用户变量 @变量名
-- 全局变量@@变量名
-- mysql8.0 查询隔离级别
-- mysql8.0 查询隔离基本的语法:selecct @@tx_isolation ;
-- mysql8.0之后将@@tx_isolation 弃用第三种情况:临时表中不能创建视图
在执行某个业务功能中,当这个业务功能它同时执行多个sql语句,将这个多个sql语句的执行过程看成
一个整体,要么同时执行成功,要么同时执行失败!
ACID:传统型事务
1) 原子性:事务是一个不可再拆分,是一个整体!
2) 一致性:事务在操作业务数据的前后,总量保持不变的,转账前后:总量一致
3) 隔离性:事务和事务之间---也就是一个业务和一个业务之间独立的,不能相互影响
4) 持久性:对数据的修改,一旦提交commit,对数据的操作是永久性的,即使 关机/或者服务器宕机,下次开机还是存在!
-- 开启事务 START TRANSACTION ;
-- 默认回滚到起始点/回滚事务 ROLLBACK ;
-- 永久存储 COMMIT ;
1) 查询的隔离级别 (mysql 8.0)
SELECT @@transaction_isolation ;-- mysql的默认的事务级别:repeatable read:可重复读]
2) 设置隔离级别
-- set global transaction isolation level 级别的名称;
隔离级别:
read uncommitted;读未提交 安全性最差,执行效率高 脏读会出现(最危险最严重的)
read committed ;读已提交 安全性相对第一种安全,防止脏读,但是出现不可重复读
repeatable read;可重复读 mysql默认级别,能够防止脏读,不可重复读
serializable ;串行话 安全性最高的 只要没有一个事务提交,另一个事务不能够操作的!
(脏读):一个事务读取到另一个没有提交事务的数据,非常严重的!
1) 什么是反射?
Jvm在加载类的时候,引导类加载器---->校验的Java代码的语法,如果语法存在问题编译报错,没有问
题执行代码!
2) 宗旨:
要获取类的或者接口的字节码文件对象,
获取构造器对象Constructor,创建类对象
获取成员变量所在的对象Field,给成员变量赋值
获取成员方法所在的对象Method,调用成员方法并去使用它"
3) Java代码经历三个阶段
SORUCE :源码阶段
CLASS : 编译---类的加载阶段
RUNTIME: 运行阶段
1) Object类的getClass()方法:
Person p = new Person();
Class c = p.getClass(); ---对象名.getClass()
2) 任意Java类型的class属性:
Class c2 = Person.class; --- 类名/接口名.class
任意数据类型都具备一个class静态属性
3) Class类中的静态方法
Class.forName("类或者接口的全限定名称") :
Class c3 = Class.forName("com.Person"); ---全限定名称: 包名.类名
这种扩展更强
没有反射之前: 类名 对象名 = new 类名() ;
总结步骤:
1) 获得当前类的字节码文件对象(建议用第三种方法)
Class c = Class.forNmae("com.deam.Person");
2) 获得构造方法对象
获得单个公共的构造方法: Constructor con = c.getConstructor;
获得单个私有的构造方法: Constructor con = c.getDeclaredConstructor();
获取这个类所有的公共的构造方法: public Constructor<?>[] getConstructors(); 获取这个类中所有的构造方法,包括私有,或者受保护的: public Constructor<?>[] getDeclaredConstructors();
3) 通过Constructor创建当前类实例
Object obj = con.newInstance();
System.out.println(obj);
*--*另外一种方式:创建当前类实例
//只要能够获取当前类的字节码文件对象Class ---- 直接newInstance
//public T newInstance()
Class myClazz = Class.forName("com.deam.Person");
Object personObj3 = myClazz.newInstance(); //默认执行的这个了无参构造方法,公共的
System.out.println(personObj3);
Class.newInstance()
Constructor.newInstance()
以下对两种调用方式给以比较说明:
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。
Class.newInstance() 抛出所有由被调用构造函数抛出的异常。
Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;
Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。如果被调用的类的构造函数为默认的构造函数,采用Class.newInstance()比较好,一句代码就OK;
如果是调用被调用的类带参构造函数、私有构造函数,就需要采用Constractor.newInstance(),两种情况视使用情况而定。
1) 获取字节码文件对象
Class c = Class.forName("com.demo.Person");
2) 获取带参构造方法对象 // public Constructor getConstructor(Class... parameterTypes)
Constructor con = c.getConstructor(String.class, int.class, String.class); --参数类型的字节码文件对象
3) 通过带参构造方法对象创建对象 // public T newInstance(Object... initargs)
Object obj = con.newInstance("张三", 30, "北京");
System.out.println(obj);
1) 获取字节码文件对象
Class c = Class.forName("com.demo.Person");
2) 获取私有构造方法对象
Constructor con = c.getDeclaredConstructor(String.class);
3) 当前获取的构造方法Constructor:是一个默认的并不是公共的,所以要使用取消Java语言访问检查
con.setAccessible(true); //参数为true 取消Java语言访问检查
4) 创建当前类的实例
Object obj = con.newInstance("李四");
System.out.println(obj);
没有反射之前:之前的给成员变量赋值
Person p = new Person() ;
p.address = "西安市" ;
System.out.println(p);
1) 获取所有成员
getFields,getDeclaredFields
2) 获取单个成员
getField,getDeclaredField
3) 修改成员的值
set(Object obj,Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
1) 获取字节码文件对象
Class c = Class.forName("com.demo.Person");
2) 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
3.1) 获取指定的默认的address所在的字段类对象Field (公共的)
Field addressField = c.getField("address") ; --参数为指定的属性名称
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
System.out.println(obj);
3.2) 获取指定的默认的name所在的字段类对象Field (私有的)
Field nameField = c.getDeclaredField("name"); --参数为指定的属性名称
// IllegalAccessException
nameField.setAccessible(true); //取消Java语言访问检查
nameField.set(obj, "赵武"); --将参数值绑定在当前类的实例
System.out.println(obj);
public Field[] getFields():获取所有的公共的字段的类对象
public Field[] getDeclaredFields():获取所有的字段(成员变量)的类对象,包括默认,受保护,私有
没有反射之前:
Person p = new Person() ;
p.show();
1) 获取所有方法
getMethods getDeclaredMethods
2) 获取单个方法
getMethod getDeclaredMethod
3) 暴力访问
method.setAccessible(true);
获得无参的成员方法:
1) 获取字节码文件对象
Class c = Class.forName("com.demo.Person");
2) 通过构造器创建当前Person类对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
3) 获取单个方法并使用
Method m1 = c.getMethod("show");
4) 调用obj对象的m1方法
m1.invoke(obj);
获得有参的成员方法:
1) public Method getMethod(String name,Class... parameterTypes)
// 第一个参数表示的方法名,第二个参数表示的是方法的参数类型的class类型
Method m2 = c.getMethod("method", String.class);
2) 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
m2.invoke(obj, "hello");
获得私有成员方法:
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
Class.forName("类的权限的名称") :参数为String--->使用配置文件
xx.txt
xxx.properites:推荐 ----位置 :src下面
1)读取配置文件的内容---->读取src下面的myclass.properties配置文件
//当前类的字节码文对象---类加载器----getResourceAsStream("配置文件")---->InputStream
InputStream inputStream = ReflectTest.class.getClassLoader().getResourceAsStream("myclass.properties") ;
2)创建属性集合类列表对象:Properties
Properties prop = new Properties() ;
3)load(输入流对象) 加载流对象
prop.load(inputStream);
4)通过反射的获取当前类的字节码文件对象
String className = prop.getProperty("className"); ---获得键对应值
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
5)通过反射获取成员方法的类对象Method---->方法名
String methodName = prop.getProperty("methodName"); ---获得键对应值
Method method = clazz.getMethod(methodName);
6)直接调用方法
method.invoke(obj) ;
动态代理---是在程序中过程中,通过反射获取代理对象!
jdk动态代理:基于接口
核心类:Proxy
java.lang.reflect.Proxy:反射代理静态功能:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
参数1:当前基于接口的类加载
参数2:实现接口的列表的Class
参数3:基于代理的处理程序的接口cglib动态代理----->Spring框架中(基于子类完成)
需要有jar包
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
public object invoke(Object obj,Method method, Object[] args)
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法
JDBC(Java Database Connectivity) Java 连接数据库的规范(标准),可以使用 Java 语言连接数据库完成 CRUD (增删查改) 操作。
Java 中定义了访问数据库的接口,可以为多种关系型数据库提供统一的访问方式。由数据库厂商提供驱动实现类(Driver 数据库驱动)。
类型 | 权限定名 | 简介 |
class | java.sql.DriverManager | 管理多个数据库驱动类,提供了获取数据库连接的方法 |
interface | java.sql.Connection | 代表一个数据库连接(当connection不是null时,表示已连接数据库) |
interface | java.sql.Statement | 发送SQL语句到数据库工具 |
interface | java.sql.ResultSet | 保存SQL查询语句的结果数据(结果集) |
class | java.sql.SQLException | 处理数据库应用程序时所发生的异常 |
1)导入数据库包 mysql-connector-java-8.0.23.jar mysql8的jar包
有了包了,里面的核心类就加载进来了
2)注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;---->获取com.mysql.cj.jdbc.Driver的类字节码文件对象
3)获取连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/javaee_2110?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true", /
//当前支持的字符集格式 服务器时区 开启公钥
"root",
"123456");)
获取数据库的连接对象:
public static Connection getConnection(String url, String user, String password)
参数1:统一资源定位符号
url组成
协议 :jdbc的协议 格式 ---> jdbc: (java连接数据库)
数据库: mysql /oracle /指定的数据库 (安装特定数据库的服务器软件)
域名:端口号
本地 localhost:本机/或者直接写127.0.0.1:本地回环地址
远程连接
远程服务器的ip地址或者域名
mysql端口号:3306
资源地址(数据库地址): 数据库名称
参数2:本地mysql的用户名 root
参数3:用户密码
4)准备sql
String sql = "insert into student values(1,'张三',18,'男','北京')"; 静态sql (硬编码)
5)通过连接对象创建执行对象
java.sql.Connection:与特定数据库的连接会话
Statement createStatement(): 创建执行对象,它可以将静态sql语句发送到数据库中
6)执行sql语句
①java.sql.Statement接口
通用的方法
int executeUpdate(String sql):将sql语句发送的数据库中执行 (更新操作)
针对DDL:表的修改、创建、删除、查询。。。
针对DML语句:insert into,update ,delete,
ResultSet executeQuery(String sql):将select语句发送到到数据中进行执行(通用查询操作)
②PreparedStatement执行对象:
Connection接口:
PreparedStatement prepareStatement(String sql):获取预编译对象,同时将参数化的sql发送给数据库
通过预编译的sql语句对象,它的内存中就可以对参数?(占位符)进行赋值
void setXXX(int parameterIndex,XXX x)
//参数1:就是第几个占位符号(占位符的索引值,从1开始)
//参数2:赋的实际参数---根据字段类型
7)释放资源
java.sql.ResultSet接口:
数据库结果集的数据表,通常通过执行查询数据库的语句生成。
boolean next():判断当前结果集的数据表中是否存在下一行数据,有,返回true
XXX getXXX( int columnIndex;):通过列的索引值获取内容
XXX getXXX(String columnLaber):通过列的标签名称获取内容(字段名称)
//使用Statement执行DQL语句:数据库的查询语句 public class JdbcExecuteQueryDemo { public static void main(String[] args) { Connection connection = null ; Statement stmt = null ; ResultSet rs = null ; //注册驱动 try { Class.forName("com.mysql.cj.jdbc.Driver") ; //获取连接对象 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/java?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true", "root", "root" ) ; //sql //查询账户表所有数据 String sql = "select * from account" ; //获取执行对象 stmt = connection.createStatement() ; //执行查询操作 // ResultSet executeQuery(String sql):将 rs = stmt.executeQuery(sql) ; //使用while循环 System.out.println("账户id\t账户名称\t账户金额"); while(rs.next()){ int id = rs.getInt(1) ; String name = rs.getString(2); int money = rs.getInt(3); System.out.println(id+"\t\t"+name+"\t\t"+money) ; } } 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(connection!=null){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
封装工具类:自定义一个工具类: 封装获取连接对象的功能 / 将释放资源也可以封装到功能中
public class JdbcUtils { private static String url = null ; private static String user = null ; private static String password = null ; private static String driverClassName = null ; private JdbcUtils(){} //构造方法私有化,外界类不能创建对象 //模拟jdbc驱动包里面com.mysql.cj.jdbc.Driver---->当前这个类一加载,就注册驱动,提供static{},静态代码块 //提供一个静态代码块:目的就是当前JdbcUtils一加载,静态代码块就优先执行,读取src下面的配置文件 static{ try { //创建一个空的属性集合列表Properties Properties prop = new Properties() ; //读取src下面的jdbc.properties InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"); //将资源流中的内容加载属性列表中 prop.load(inputStream); //获取配置文件中的key---对应的value url = prop.getProperty("url") ; user = prop.getProperty("user") ; password = prop.getProperty("password") ; driverClassName = prop.getProperty("driverClassName") ; //注册驱动 Class.forName(driverClassName) ; } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } //封装获取连接对象的功能 public static Connection getConnection(){//String url,String user,String password 不直接放在形式参数中 Connection connection = null ; try { //使用驱动管理类 connection = DriverManager.getConnection(url,user,password) ;//从配置文件中获取 return connection ; } catch (SQLException e) { e.printStackTrace(); } return null ; } //针对DQL语句操作,释放资源 //ResuletSet,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(); } } } // 将释放资源也可以封装到功能中 //针对的是DDL/DML语句操作时释放资源 public static void close(Statement stmt,Connection conn){ close(null,stmt,conn); } }
前者:预编译对象,执行都是参数化的sql
写的sql的参数都是占位符号?,可以有效防止sql注入(不存在字符串拼接)
sql就执行一次,可以发送不同的参数进行赋值,执行sql效率相对大于Statement后者:普通的执行对象,每次指定的都是静态的sql,存在硬编码,而且存在字符串拼接,
可以造成sql注入,不安全
执行sql效率低,每次executeUpdate/Query(String sql)都要发送sql
后期的Mybatis框架:底层就是对Jdbc的封装----用的就是 PreparedStatement
1) 什么是 SQL 注入?
用户输入的数据中有 SQL 关键字或语法并且参与了 SQL 语句的编译,导致 SQL 语句编译后的条件含义为true,一直得到正确的结果。这种现象称为 SQL 注入。
2) 如何避免 SQL 注入?
由于编写的 SQL 语句是在用户输入数据,整合后再进行编译。所以为了避免 SQL 注入的问题,我们要使SQL 语句在用户输入数据前就已进行编译成完整的 SQL 语句,再进行填充数据。
1)导包
2)自定义类,书写单元测试方法
3)没有返回值类型,没有参数类型,就是写内容
4)方法注解@Test---启动器
单元测试提供其他注解
@Before:它标记的方法在执行@Test方法之前先执行
后期的服务器的初始化操作代码
@After: 它标记的方法是在执行@After方法之后执行
存储的一些释放资源代码
//计算器类 public class Calcuator { //加 public int add(int a,int b){ // return a - b ; return a + b ; } //减 public int sub(int a,int b){ return a- b ; } //乘 public int mul(int a,int b){ return a * b ; } //除 public int div(int a,int b){ return a / b ; } } public class MyTest { @Before //init()方法是test()之前先执行 public void init(){ System.out.println("业务功能初始化了..."); } @After//close()方式test1执行完后执行 public void close(){ System.out.println("相关的资源对象被释放了"); } //单元测试方法 @Test public void test1(){ //功能代码:进行测试 // Assert :断言 方法---预期的结果 //测试计算器类的相关的功能 //创建计算器类对象 Calcuator calcuator = new Calcuator() ; //求和 //最终的结果 int result = calcuator.add(10, 20); //System.out.println(result) ; //断言的功能 //asserEquals(预期的结果,单元测试中的结果): // 要进行匹配,如果值一直,就断言成功,否则断言失败 Assert.assertEquals(30,result); System.out.println("断言成功"); } }
注解:---标记类,方法,参数,成员变量,由一种特殊的含义 (能被解析的)
注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加
载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下
在源代码中嵌入补充信息。
注解的本质就是接口interface---->前面加入了@标记
注解中的属性----->(就是接口中的方法名)
1) @Overrid:标记当前这个方法是否为重写方法: 重写了类/抽象类或者接口
2) @Deprecated:标记某个方法是过时方法
3) @SuppressWarnings:压制警告, 一般企业中, 项目部署上线的时候,代码中不能黄色警告线!
4) @FunctionalInteface:函数式接口 :jdk8后,
接口如果一个抽象方法,那么这个接口就可以是函数式接口----使用lambda表达式
内置注解底层依赖的元注解
@Target(ElementType.METHOD)
标记当前这个注解所作用的范围
属性:
ElementType[] values()--->返回值枚举的数组--->里面一些常量
TYPE,当前注解可以作用在类上
FIELD,当前这个注解可以作用成员属性上
METHOD, ...当前这个注解可以作用在方法上
@Retention(RetentionPolicy.SOURCE) :
当做标记@Override注解的保留的阶段
RetentionPolicy value();
返回值枚举类型
SOURCE :原码编译阶段
CLASS: 类 的加载
RUNTIME:运行阶段
String
枚举类型Enum
注解类型@Annotation
基本类型
以上类型的数组