MYSQL数据库与JDBC
Junit
- Junit使用步骤:
- 定义一个测试类
- 定义一个测试方法,这个方法必须可以独立运行。
- 在该测试方法前加@Test
- 导入Junit依赖环境
- @Before修饰的方法会在测试方法之前被自动执行,@After修饰的方法会在测试方法执行忠厚自动被执行。
反射
获取字节码Class对象的三种方式:
- Class.forName(“全类名”):将字节码文件加载进内存,并返回Class对象。全类名:包名.类名。
- 类名.class:通过类名的属性class获取Class对象。
- 类的实例化对象.getClass():getClass()方法可以用于获取Class对象,Object类中就定义了该方法。
获取properties配置文件中键值对信息的一种方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17Properties pro = new Properties();
//创建Properties配置文件类对象。
ClassLoader classLoader = ReflectTest.class.getClassLoader();
//获取class目录下的配置文件的方式:
//classLoader是本字节码文件ReflectTest.class的类加载器,它可以找到本项目目录中的类文件和配置文件。
InputStream is = classLoader.getResourceAsStream("pro.properties");
//类加载器的getResourceAsStream()方法可以获取配置文件中对应字节流.
pro.load(is);
//将该配置文件字节流转换为一个集合。
//该集合的内部结构即为HashTable,就是不同的key与value一一对应。
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//获取配置文件集合中key对应的value,这了的key一定要输入正确。
注解
- 注解本质上就是一个接口,该接口默认继承Annotation接口。
MySQL
sql分类
- DDL(Data Definition Language)数据定义语句:用来对数据库、表、列等数据库对象进行增删改操作。
- DML(Data Manipulation Language)数据操作语句:用来对数据库中表中的数据进行增删改操作。
- DQL(Data Query Language)数据查询语句:用来查询数据库中表中的数据。
- DCL(Data Control Language)数据控制语句:用来定义数据库访问权限和安全级别等。
DDL操作
(tips:以下sql语句实例中的括号表示可有可无)
创建数据库:
create database (if not exists) 数据库名称 (character set 字符集名);
查询所有数据库名称:
show databases;
修改数据库的字符集:
alter database 数据库名称 character set 字符集名称;
删除数据库:
drop database (if exists) 数据库名称;
查询当前正在使用的数据库名称:
select database();
指定使用某个数据库:
use 数据库名称;
查询某个数据库中所有表的名称:
show tables;
查询表结构(列名和数据类型):
desc 表名;
创建表:
create table 表名(列名1 数据类型1,…,列名n 数据类型n);
e.g. money double(5,2):数据类型为总位数5位,小数点后两位;name varchar(20):数据类型最大能包含20个字符。
删除表:
drop table (if exists) 表名;
修改表名:
alter table 表名 rename to 新的表名;
修改表的字符集:
alter table 表名 character set 字符集名称;(gbk或者utf8)
给表添加一列:
alter table 表名 add 列名 数据类型;
修改表中列的名称和类型:
alter table 表名 change 列名 新列名 新数据类型;(同时修改名称和类型)
alter table 表名 modify 列名 新数据类型;(只修改类型)
删除表中的列:
alter table 表名 drop 列名;
DML操作
往表中添加数据:
insert into 表名(列名1,…,列名n) values(值1,…,值n);
- 如果表名后不定义列名,则默认给所有列添加值
- 添加多行可以直接用 values(值1,…,值n),(值1,…,值n),…,(值1,…,值n) 的形式
删除表中数据:
delete from 表名 where 条件;
- 这个条件主要用于确定是哪一行,比如id = 1
- 可以不加where 条件,则删除表中所有记录
修改表中数据:
update 表名 set 列名1=值1,列名2=值2,… where 条件;
- 可以不加where 条件,则所有指定列中的值都改变
DQL操作
查询表中数据:
select 列名列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的字段 order by 排序 limit 分页限定;
列名可以是一个运算表达式,比如列名1+列名2,得到的就是两列数据相加的结果
如果要查询所有列的数据值,则可以用*来替代列名列表
distinct可以加在select后面用于去除重复的结果集
ifnull(列名,表达式)可以加在列名列表中,表示如果该列中某个数据为null时,则用表达式表示该数据
as可以加在列名和表名后面用来给列名和表名起别名,其中as可以省略
where子句后面跟的条件可以是:
- <、>、<=、>=、=、!=
- BETWEEN…AND
- IN (集合)
- LIKE :_表示单个任意字符,%表示任意个任意字符,e.g. LIKE”马%”表示所有姓马的,LIKE”%马%”表示只要包含马字就行
- IS NULL
- and 或 &&
- or 或 ||
- not 或 !
order by 排序列名1 排序方式1,排序列名2 排序方式2…
排序方式有ASC表示升序,DESC表示降序;排序列名1的数据相等时,才会再将相等的行按排序列名2排序
聚合函数:将一列数据作为一个整体,进行纵向的计算,聚合函数通常放在查询语句的列名中,作为一个查询结果列:
count 、max、min、sum、avg(计算平均值),e.g. select count(ifnull(math,0)) from student:计算学生中有math的行的个数,其中包括math数据为null的行;select avg(math) from student:计算学生数学成绩平均值。
group by 关键字可以将查询结果按照某个字段或多个字段进行分组,字段中值相等的为一组
group by与聚合函数共同使用时,先进行group by分组,再按组内计算聚合函数结果
having 条件表达式:与group by搭配使用,主要用来限制分组查询结果的显示,符合条件表达式的行才会被显示
limit 每页的第一行在整个表中的行索引,每页显示的行数:用于分页查询,数据库中的表是没有页这个概念的,但是查询结果表格可以有页这个概念
每页的第一行在整个表中的行索引 = (当前的页码 - 1) * 每页显示的行数
约束
非空约束:not null,某一列的值不能为null
e.g. create table stu(id int not null);
唯一约束:unique,某一列的值不能重复
e.g. create table stu(id int unque);
主键约束:primary key,非空并且唯一,一张表只能有一个主键,主键是表的唯一标识
e.g. create table stu(id int primary key);
自动增长:auto_increment,在添加某一列数值类型的值时,只需要添加null,表会自动将该位置赋值为上一行同列中的数值+1。也可以自己随意添加一个值,然后下一行的自动增长就在此基础上+1。
外键约束:foreign key,让表与表产生关系,从而保证数据的正确性
创建表时,添加外键:
create table 表名 {…外键列名 外键数据类型 constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称)};
- 此处的外键名称不对应实际数据,主要用于后面删除外键
- 有foreign key的表叫从表,被从表中外键references的表叫主表
- 在从表中添加行时,外键列添加的值一定要是主表列中存在的值,否则无法添加成功;同理删除或者修改主表列中的值时,应先将对应外键列中的值设置为空或者其他值,否则会报错
删除外键:
alter table 表名 drop foreign key 外键名称;
创建表之后,再添加外键:
alter table 表名 add constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称);
外键约束_级联操作:外键约束中的主表列中的数据做出删除或者修改操作时,对应的从表中的外键列中数据也自动做出改变(作用其实就是为了简化上文中加粗下划线文字部分所提到的情况)
添加级联操作:
alter table 表名 add constraint 外键名称 foreign key (外键列名称) references 主表名称(主表列名称) on update cascade on delete cascade;
- 要在已经建立好外键约束的表上添加级联操作,只能先删除外键,再一并添加外键和级联操作
- on update cascade和on delete cascade分别为级联更新和级联删除,它们可以一起添加;级联删除主要是指当我们删除主表中某一行,从表中对应外键列所在行也会被自动删除。
多表关系
- 一对一关系实现:在任意一方添加唯一外键指向另一方的主键
- 一对多关系实现:将多的一方作为从表,建立外键,指向一的一方的主键
- 多对多关系实现:需要借助第三张中间表,中间表至少包含两个列,这两个列都作为第三张表的外键,分别指向前两张表的主键
多表查询
一次查询多张数据库表:
select 列名1,…,列名n from 表名1,…,表名n where 查询条件;
当无查询条件,查询结果为笛卡尔积,其行数为所有表的行数的乘积,其中大部分结果都是无用的错误结果。可以通过设置合适的查询条件来消除无用的错误结果,主要得到三种较好的查询方式:内连接查询、外连接查询、子查询。
内连接查询:从结果表中删除没有通过外键连接相匹配的所有行
隐式语法:
select 列名1,…,列名n from 表名1,…,表名n where 查询条件;
e.g. select t1.’id’,t1.’name’,t2.’age’ from employee t1,department t2 where t1.’id’=t2.’id’;
- 上例中t1和t2分别为两表的别名
- 列名要加上表名前缀和引号
- 上例中的查询条件为两表中的id相等
显式语法:
select 列名1,…,列名n from 表名1 (inner) join 表名2 on 查询条件;
- 隐式和显式写法查询出来的结果一样,只是写法的不同
- inner可加可不加
外连接查询:分为左外连接和右外连接。以一张表为基表,该基表的内容会全部显示,然后加上左、右连接表中满足查询条件的内容。如果基表中的数据在另一张表中没有记录,则结果集同一行中连接表部分的数据显示为null。
左外连接:
select 列名列表 from 表1 left (outer) join 表2 on 查询条件;
查询的是表1的所有数据以及两表的交集部分
右外连接:
select 列名列表 from 表1 right (outer) join 表2 on 查询条件;
查询的是表2的所有数据以及两表的交际部分
子查询:子查询就是查询中嵌套查询,子查询结果可以是单行单列、多行单列、多行多列的
e.g. select * from emp where emp.salary < (select avg(salary) from emp);
DCL操作
添加用户:
create user ‘用户名‘@’主机名’ identified by ‘密码’;
- 这里的主机名指的是电脑的ip地址,如果直接写成%,则代表任何电脑都可以用该用户名访问该服务器。
删除用户:
drop user ‘用户名‘@’主机名’;
修改用户密码:
update user set password = password(‘新密码’) where user = ‘用户名’;
查询用户:
use mysql;
select * from user;
查询某个用户的权限:
show grants for ‘用户名‘@’主机名’;
授予某个用户权限:
grant 权限列表 on 数据库名.表名 to ‘用户名‘@’主机名’;
- 可以通过查询root用户的权限,看看具体有哪些权限可以授予
撤销权限:
remove 权限列表 on 数据库名.表名 from ‘用户名‘@’主机名’;
JDBC
JDBC基本使用步骤
导入驱动jar包:创建一个文件夹命名为libs,将jar包放到该文件夹中,右键该文件夹–>add as library。这样才是真正把jar包加入到项目中了,使项目程序能使用jar包中的api。
注册驱动。(其实就是通过反射获取libs中的Driver类的Class类对象,将其放入jvm内存中)
获取数据库连接对象。
定义sql语句。(最后不用加分号。)
获取sql对象Statement。
执行sql。
释放资源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21Class.forName("com.mysql.jdbc.Driver");
//注册驱动。(其实就是通过反射获取libs中的Driver类的Class类对象,将其放入jvm内存中)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");
//获取数据库连接对象。
String sql = "update stu set name = '金子涵' where id = 3";
//定义sql语句。(最后不用加分号。)
Statement stmt = conn.createStatement();
//获取sql对象Statement。
int count = stmt.executeUpdate(sql);
//执行sql。
System.out.println(count);
//处理结果。
stmt.close();
conn.close();
//释放资源。
- 在for、while循环语句中,在每次循环内部创建的局部变量的寿命就只有该次循环,不会存活到下一次循环,所以在下一次循环中可以创建一个新的同名局部变量。
加载配置文件
使用类加载器动态加载配置文件
1
2
3Properties pro = new Properties();
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);- 可以是放在项目中任意目录下
使用字符文件读取类+绝对路径加载配置文件**
1
2Properties pro = new Properties();
pro.load(new FileReader("E:\\files\\IntelliJ IDEA\\037.1JDBCTemplate\\dataSource\\src\\druid.properties"));
- 字符串中\\表示\,或者把\\换成/也可以。
- 此处第二个文件夹名为IntelliJ IDEA,可以带空格。
JDBC连接池&JDBCTemplate
获取Druid数据库连接池对象的基本步骤
导入jar包
定义properties配置文件
加载配置文件
获取连接池对象
获取连接对象
1
2
3
4
5
6
7
8
9
10Properties pro = new Properties();
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//加载配置文件
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//获取连接池对象
Connection conn = ds.getConnection();
//获取连接对象
使用Template的基本步骤
导入jar包
创建JdbcTemplate对象
调用JdbcTemplate对象的方法来完成CRUD操作
1
JdbcTemplate template = new JdbcTemplate(ds);
- JdbcTemplate类的构造函数的输入参数类型为数据库连接池
- 与不使用Template对比可以发现,代码简单了很多,连接的获取、结果集的操作、资源的释放、连接的归还等操作都已经被JdbcTemplate类封装好了,不用我们再去写。
JdbcTemplate的方法
update():用于执行DML语句,对表中数据进行增、删、改操作。
1
2
3
4String sql = "update bank set money = 5000 where id = ?";
int count = template.update(sql,2);
//template.update()方法的输入为sql语句和sql语句中的?实参列表。
//返回值为sql增删改语句对数据库中表的影响行数。queryForMap():用于对表中数据进行查询操作,将查询结果封装为map集合,将列名作为key,将数据值作为value。使用这个方法进行查询的sql语句的查询结果行数只能是1。
1
2
3
4
5
6String sql = "select * from student where id = ?";
Map<String,Object> map = template.queryForMap(sql,1);
//1.Map是一个接口,这里用于声明一个Map引用变量,在声明时一定要确定泛型,
//该Map中表名作为key,各种不同数据类型作为value,所以key声明为String,value声明为Object。
//2.这个Map引用变量指向的肯定是Map的一个实现类对象,具体是怎样的实现类我们不知道,
//也不需要知道,JdbcTemplate已经帮我们把该实现类的基本方法接口编写封装好了。queryForList():用于对表中数据进行查询操作,将查询结果封装为List集合。使用这个方法进行查询的sql语句的查询结果行数应大于1,实际上就是把查询结果的每一行封装成一个Map集合。
1
2
3
4String sql = "select * from student";
List<Map<String,Object>> list = template.queryForList(sql);
//这里的list的节点就是JdbcTemplate封装好的Map实现类对象,很多方法接口都可以套用。
//这里的List也是官方接口,list引用变量具体指向的实现类对象结构也是由JdbcTemplate定义封装好的。queryForObject():用于查询,并将查询结果封装为定义好的对象。
1
2
3String sql = "select count(id) from student";
Integer total = template.queryForObject(sql,Integer.class);
//template.queryForObject()方法的输入除了sql语句,还有一个要返回的结果类型的Class对象。query():用于查询,并将结果封装为JavaBean对象。
1
2
3
4
5
6
7
8String sql = "select * from student";
List<Student> list = template.query(sql, new BeanPropertyRowMapper<Student>(Student.class));
//这里的query方法同样是直接得到一个List实现类对象,只不过其中节点是JavaBean对象。
//使用BeanPropertyRowMapper实现类,可以完成数据到JavaBean的自动封装。
//(注意这里的被查询表student中如果有值为null的数据,则Student类中的数据类型
//必须是引用数据类型的封装类,不能是基本数据类型,比如不能是int,要写成Integer,
//因为int不能等于null,而Integer对象可以等于null。)- 一般我们使用BeanPropertyRowMapper类来作为query()方法的输入参数,这个类可以将查询结果的每一行数据自动封装成JavaBean实例对象。