数据存储形式
文件(存储在硬盘)
文件存储的格式
对数据处理可以通过Java代码实现
缺点:读写速度慢,硬盘本身的特点就是读写慢
变量(存储在内存)
读写速度快,临时数据的存储
数据库(数据库管理系统)
数据库管理系统(DBMS database manage system)是一套软件,是一种存储和管理数据表的软件系统
适用于大数据,支持多人并发操作
数据库中的数据是永久存储,数据操作效率高
数据库分类
关系型数据库(存储在硬盘):MySQL、sql server、oracle、db2
数据以二维表的方式存储
实体之间的关联关系
支持SQL(Structured Query Language)结构化查询语言
非关系型数据库(存储在内存):redis、MongoDB、Hbase...
数据按不同的数据类型存储
不支持SQL
ER模型(E-entity 实体,R-relation 关系)
ER模型,就是将数据库中的table之间的关系,以图形的方式展示出来
ER模型,就是创建数据库表的依据
矩形代表实体,菱形代表关系,椭圆代表实体的属性
实体之间的关系:
1对1:一个国家有一个总统
1对多:一个班级有多个学生
多对多:课程和学生
MySQL中常见的数据类型
类型 | 说明 | 解释 |
tinyint | 短整型 | 对应java的 byte,short |
int | 整型 | 对应java的int |
bigint | 长整型 | 对应java的long |
float | 单精度浮点型 | 对应java的float |
double | 双精度浮点型 | 对应java的double |
decimal | 指定总长度,及其小数占的位数 | 比如:decimal(10,3) |
char(长度) | 定长字符串 | 对应java的string,比如char(5),表示必须是5位的字符串,不够就用空占位 |
varchar(长度) | 可变长字符串 | 对应java的string,比如varchar(50),表示最大50位,以字符串的实际长度为准 |
text | 文本 | |
date | 日期 | yyyy-MM-dd |
time | 时间 | HH:mm:ss |
datetime | 日期时间 | yyy-MM-dd HH:mm:ss |
timestamp(14或8) | 毫秒 | 保存时间毫秒数,14表示yyyyMMddHHmmss,8表示yyyyMMdd |
约束
约束名字 | 概念 | 关键字 |
非空约束 | 是否允许字段位null | null表示可以为空,not null表示不能为空 |
主键约束 | 主键(primary key),保证每行数据不重复,并且主键值不能是null。 一般会在建表的时候,给表设计要给id字段 | primary key |
唯一约束 | 保证字段值不重复 | unique |
外键约束 | 在有这个主从关系的表中,给有管理关系的字段,设置为外键约束,这个字段值,只能参考主表中的某个字段的值 | foreign key references |
默认值 | 可以设置某个字段的默认值,如果没有给这个字段设置数据值,就采用默认值 | default |
Mysql的命令行操作
链接mysql服务器
mysql -u root -p
Enter password:密码
使用mysql的命令
show databases; --显示所有的数据库
use a; --选择要使用的数据库的名字
show tables; --显示a数据库中的所有表
desc lwg(表名); --查看指定表的结构
--Field ,字段
--Type ,字段类型
--Null ,是否允许为空
--Key ,是否为主键
--Default,默认值
--Extra ,描述信息
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| username | varchar(200) | YES | | NULL | |
| password | varchar(200) | YES | | NULL | |
| city | varchar(200) | YES | | NULL | |
| data | varchar(200) | YES | | NULL | |
| email | varchar(200) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
insert into lwg (username,password,city) values('root','123546','重庆');--插入数据的sql语句
Query OK, 1 row affected (0.35 sec) --插入数据成功后的提示信息
select * from lwg; --查询数据
+----+----------+----------+------+------+-------+
| id | username | password | city | data | email |
+----+----------+----------+------+------+-------+
| 1 | root | 123546 | 重庆 | NULL | NULL |
+----+----------+----------+------+------+-------+
1 row in set (0.00 sec)
update lwg set city='渝中区' where username='root'; -- 修改数据
Query OK, 1 row affected (0.31 sec)
Rows matched: 1 Changed: 1 Warnings: 0 -- 成功后的提示信息
select * from lwg;
+----+----------+----------+--------+------+-------+
| id | username | password | city | data | email |
+----+----------+----------+--------+------+-------+
| 1 | root | 123546 | 渝中区 | NULL | NULL |
+----+----------+----------+--------+------+-------+
1 row in set (0.00 sec) --表中数据已被修改
delete from lwg; --删除数据
Query OK, 1 row affected (0.01 sec) --删除成功后的提示信息
select * from lwg;
Empty set(0.00 sec) --没有数据后显示为空
drop table lwg; --删除名为lwg的表
Query OK, 0 rows affected (0.05 sec)
select * from lwg;
ERROR 1146 (42S02): Table 'lwg.lwg' doesnt exist -- 报错显示表不存在
drop database lwg; --删除名为lwg的数据库
create database cms; --创建名为cms的数据库
create table test(id int,name varchar(6),pwd varchar(8)); -- 创建一个名字叫test的表
show tables;
+---------------+
| Tables_in_cms |
+---------------+
| test |
+---------------+
1 row in set (0.00 sec)
SQL(Structured Query Language):结构化查询语言
sql的使用
创建数据库: create database 数。据库名;
create database 数据库名 default character set utf8; -- 指定了数据库的编码
删除数据库:drop database 数据库名;
创建表:
create table 表名 (字段 字段类型 约束条件,字段2...);
如果字段名或表名与关键字重复了,就在字段名或表名上添加引号
尽量避免与关键字重名,一般表可以加前缀:cms_stu -- 表示学生表,s_name -- 表示学生表的name字段名
约束条件:not null 表示字段值不能是null
int类型的数据,可以设置为自动增长:auto_increment
主键约束: primary key, 一般用于实现表中的每行数据不重复
特点:非空且不重复
删除表
drop table 表名;
添加数据 —— insert
数据添加们都是整行添加,每一行数据叫一个record(记录)
给所有字段赋值
表名之后,没有指定字段名,说明添加的所有字段的值,values中按表格结构的顺序,填写上每个字段对应的值。
insert into 表名 values(字段值1 ,字段值2···);
insert into school values('1001','重庆大学','1945-10-23','20650','30065');
遇到自增字段,在values中对应的顺序位置用0,null或者default让其自动填充
遇到有默认的字段,不能省略不写,在values中对应的顺序位置用default占位
遇到允许为空的字段,不能省略不写,在values中对应的顺序位置用null占位
给指定的字段赋值
表名之后,指定的字段名,values只需要设置表名之后指定的字段的value值就可以了(一一对应)
insert into 表名(字段1,字段2,字段3) values(字段1值 ,字段2值,字段3值 );
insert into school(sc_code,sc_name,sc_total) values('1001','重庆大学',25833);
没有默认值的非空字段,必须要设置数据值
表名之后的字段顺序必须和values的值的顺序一致
批量添加
用insert into 语句,一次添加多个记录
一次如果需要添加多条数据,使用批量添加,效率更高
insert into 表名 values(值1,值2),(值1,值2).....
insert into school(sc_code,sc_name,sc_total)
values('1010','重庆大学',25833),
('1011','重庆文理学院',2585533),
('1012','重庆人文科技学院',2583663);
修改数据 —— update
一般修改,主要根据主键进行筛选修改
修改单个字段的所有值
update 表名 set 字段名 = 新值
-- update school set sc_ttal = 100 不合理,这表示吧所有记录中的sc_total都修改为100了
修改多个字段的值
update 表名 set 字段名 = 新值, 字段名 = 新值2.。。。。
-- update school set sc_ttal = 100 ,sc_area = 100 不合理,这表示吧所有记录中的sc_total都修改为100了,总面积都修改为100
根据条件修改数据(where)
update 表名 set 字段名 = 新值 where 条件
update 表名 set 字段名 = 新值, 字段名 = 新值2.。。。。 where 条件
指定值
update 表名 set 字段名 = 新值 where 字段名 = 字段值
update school set sc_total=6000 where sc_code = 1002 --修改学校编号是1002的学校人数
指定范围
--1. > , < , >= , <= 表示范围, and ,or 将多个条件进行关联
update school set sc_total=6120 where sc_code < 1004
--2.使用between...and ,设置要给区间之内
update school set sc_total=6120 where sc_code between 1005 and 1620 -- [1005,1620]
--3.使用!=或<>不等于
update school set sc_total=6120 where sc_code <>1665 --不是1665的就修改
指定集合
-- 1.在某个集合中 in
update school set sc_total=6120 where sc_code in(1001,1002,1003); -- 修改sc_code等于1001或1002或1003
update school set sc_total=6120 where sc_code =1001 or sc_code = 1002 or sc_code = 1003;
-- 2.不在某个集合中 not in
update school set sc_total=6120 where sc_code not in(1001,1002,1003); --不修改sc_code等于1001或1002或1003,其他都修改
空值 null
-- 1. is null 表示空
update 表名 set 字段名 = 新值 where 字段 is null
-- 2. is not null 表示非空
update 表名 set 字段名 = 新值 where 字段 is not null
模糊匹配
-- 1. '_'代表一个任意字符
-- 2. '%'代表任意个字符(1个或多个)
--以什么开始
sc_name like "重庆%"
--以什么结尾
sc_name like "%大学"
--包含什么
sc_name like "%交通%"
--只能包含4个字符
sc_name like "__大学"
--倒数第二个是大
sc_name like "%大_"
update school set sc_total = sc_total+1000 where sc_name like '%大_' -- 匹配成功的行,人数增加
删除数据 —— delete(remove,drop)
delete是删除数据本身,表的结构还在
drop是删除表,数据库,结构被删除了,数据自然被删除了
删除所有数据
delete会保留自增列删除前的值,继续添加新数据,从删除前的最大一个数值开始增加
truncate会重置自增列的值,效率高
如果有主从表关系,建议先删除从表的数据,再删除主表的数据
delete from 表名
-- 或
truncate table 表名
根据添加删除
根据主键删除
delete from 表名 where 主键字段 = 值
delete from book_info where book_id = 1006 --删除主键为1006的书
参考update中的where条件的写法
-- 练习: 删除book_id是1004到1008区间的
delete from book_info where book_id between 1004 and 1008;
-- 练习:删除booK_id不是1001,1004,1007的
delete from book_info where book_id not in(1001,1004,1007)
删除表结构
drop table 表名
查询 — select
全表查询
select * from 表名 -- *表示的是所有字段名
select * from school --查询school表的所有数据
select 列名1,列名2... from 表名 --直接把所有列名写出来
select sc_code,sc_name,sc_birth,sc_address,sc_total,sc_area from school --等同于select * from school
查询指定的列
select 列名1,列名2 from 表名 -- 只查找出指定的列
select sc_name,sc_address from school --只显示学校的名字和地址
条件查询(筛选行)——where
模糊查询——like
-- 模糊查询是针对字符类型(char,varchar)
-- % ,任意个字符
-- _ , 一个字符
select * from 表名 where 字段名 like
数据的条件查询
-- > , < , >= , <= , = , != , <>
select * from 表名 where 字段名 [> , < , >= , <= , = , != , <>]数据值
使用关键字,实现条件的组合
-- and , or , in , not in , between...and
select * from 表名 where 条件1 and[or] 条件2
select * from 表名 where 字段名 in[not in](数据1,数据2......) or 条件 and ....
去掉重复的行 —— distinct
select distinct * from 表名 where 条件
给字段取昵称
select 字段1 as "1",字段2 as "2" from 表名 where 条件 --as 用于取别名,1是字段1的别名,2是字段2的别名
select 字段1 "1",字段2 "2" from 表名 where 条件 --as可以省略
select school.sc_code code,school.sc_name name from school
多表查询 —— 两张表
交叉连接、笛卡尔积
集合A:{a,b}
集合B:{1,2,3}
集合A * 集合B = {a1,a2,a3,b1,b2,b3}
将两张表中的数据两两组合,得到的结果就是交叉连接的结果,也成为笛卡尔积
select * from 表1 ,表2
select * from 表1 cross join 表2 -- cross
select * from 表1 inner join 表2 -- inner
-- 两张表数据组成一张表,其中有很多无效数据
内连接
通过主表主键字段和从表外键字段进行等值判断
主表和从表字段名一样,使用“表名.字段名”进行区分,可以给表取别名
如果用where进行内连接,后续还有其他条件的查询,使用and拼接 后续条件
如果用 inner join /on join ,后续有其他条件,使用where进行条件拼接
只显示两张表中有关联的数据
select * from 表1 ,表2 where 表1.字段 = 表2.字段 --判断相等的字段就是有外键约束的字段
select * from 表1 inner join 表2 on 表1.字段 = 表2.字段-- on后买你的相等字段判断,也是有外键约束的字段
-- 查询学生的学生信息和班级信息
select * from t_stu,t_class where t_stu.c_id = t_class.c_id
select * from t_stu,t_class where t_stu.c_id = t_class.c_id and t_stu.money > 5000 -- 使用and拼接查询条件
select * from t_stu inner join t_class on t_stu.c_id = t_class.c_id where t_stu.money > 5000 -- 加上关键字where后,拼接条件
左连接
左表内容全显示,右表只显示有关联的数据
保证左表的数据完整,关联右表中的数据,没有关联的数据用null表示
select * from 左表 left join 右表 on 左表.字段=右表.字段 -- 左连接
-- 查询学生和班级信息
select * from t_class c left join t_stu s on c.c_id=s.c_id -- 左表内容全显示
select * from t_stu s left join t_class c on c.c_id=s.c_id
右连接
右表内容全显示,左表只显示有关联的数据
保证右表的数据完整,关联左表中的数据,没有关联的数据用null表示
select * from 左表 right join 右表 on 左表.字段=右表.字段 -- 右连接
select * from t_class c right join t_stu s on c.c_id=s.c_id -- 右表内容全显示
select * from t_stu s right join t_class c on c.c_id=s.c_id
子查询
子查询是在查询语句中,嵌套了另一个查询语句,也可以嵌套查询
子查询作为where条件
-- 查询出班级名字为"软件技术11班"的所有学员
select * from t_stu where c_id = (select c_id from t_class where c_name='软件技术11班')
-- 查询出没有学生的班级
select * from t_class where c_id not in(select c_id from t_stu) -- 查询出学生的班级c_id,不在这些c_id中的班级就没有学生
子查询是作为一张临时表
如果把子查询的结果作为一张临时表,必须要把子查询的结果,设置一个别名
-- 查询出所有男生 ,工资大于5000
-- 先用一个查询,查询出所有男生,然后在跟这个结果中,查询出工资大于5000的
select * from (select * from t_stu where s_sex = '男') stuman where s_money >5000
子查询作为一个字段
如果子查询的结果作为一个字段,那么要求该子查询每次只能返回一行记录
-- 查询出所有班级名字和学生名字
select (select c_name from t_class c where c.c_id = s.c_id) as c_name , s_name from t_stu ss
修改表结构
drop table,然后重新建
给表增加字段
alter table 表名 add 字段名 字段类型 -- alter 修改
alter table dept add d_phone varchar(20) -- 给dept表增加一个字符串类型的字段d_pohoe
删除表中的字段名
alter table 表名 drop 字段名 字段类型 -- alter 删除字段名
alter table dept drop d_phone -- 删除dept表的d_phone字段名
修改表中的字段名
alter table 表名 modify 原字段名 新的类型 -- 修改字段的类型
alter table dept modify d_note int
修改字段名
alter table 表名 change 原字段名 新字段名 新字段类型
alter table dept change d_note d_note1 varchar(200)
修改表名
alter table 表名 rename to 新表名
alter table emp rename to employee -- 修改表名
增加外键约束
alter table 从表名 add constraint 约束名 foreign key(字段名) references 主表名
alter table t_stu add constraint fk_stu_class foreign key(c_id) references t_class(c_id) -- 在c_id字段添加一个名叫fk_stu_class的外键
删除外键约束
alter table 表名 drop foreign key 约束名字
alter table t_stu drop foreign key fk_stu_class -- 根据约束名字,删除约束
添加约束
-- 添加唯一约束
alter table 表名 add unique (字段名)
-- 添加非空约束
alter table 表名 change 原字段名 新字段名 数据类型 not null
-- 添加主键约束
alter table 表名 add primary key(字段名)
-- 添加默认值
alter table 表名 字段名 set default 默认值
函数
统计函数(聚合函数)
select 统计函数字段名 from 表名
函数名 | 功能 |
count(字段名),count(*) | 统计行数 |
sum(字段名) | 求和 |
avg(字段名) | 平均值 |
max(字段名) | 最大值 |
min(字段名) | 最小值 |
数学相关的函数
select 函数(字段名) ...... from 表名
select sc_name ,round(sc_area) from school
函数名 | 功能 |
round(字段名 或 值) | 四舍五入 |
ceil(字段名) | 向上取整 |
floor(字段名) | 向下取值 |
abs(字段名) | 绝对值 |
pow(字段名) | 幂 |
sqrt(字段名) | 平方根 |
字符串函数
select 函数(字段名) ...... from 表名
select reverse(sc_name) ,round(sc_area) from school --反转学校名
select concat(sc_name,sc_birth) from school --学校名字和建校日期拼接
函数名 | 功能 |
trim(字段名) | 去掉字符串前后多余的空格 |
lenth(字段名) | 计算字符串的长度 |
substr(字段名,start) | 截取字符串 |
lcase(字段名) | 转小写 |
ucase(字段名) | 转大写 |
reverse(字段名) | 反转 |
concat(字段名1,字段名2...) | 拼接 |
时间函数
select 函数(日期相关的字段名) ...... from 表名
select now() -- 得到系统时间
select current_date() -- 得到当前日期
select sc_name ,year(sc_birth) from school
函数名 | 功能 |
now() | 当前日期时间 |
current_date() ,curdate() | 当前日期 |
current_time() ,curtime() | 到期时间 |
year/month/day(日期相关的字段名) | 得到时间分量 |
datediff(时间,时间) | 计算相隔的天数 |
数据库中的其他对象
视图(view)- 虚表
可以使用select语句查询视图中的数据
修改了视图中的数据,会同时修改到原表中的数据,建议不要修改视图的数据
create view 视图名字 as select ...
--- 查出女生的信息,保存在视图当中
create view v_student as select s_id,s_name,s_age,s_sex from student where s_sex='女'
--- 视图名字:v_student
--- 视图内容: select s_id,s_name,s_age,s_sex from student where s_sex='女'
-- 查询出所有的女生
select * from v_student -- 在视图中查找数据
drop view 视图名字 -- 删除视图
索引(index) - 有助于提高查询的效率
create index 索引名字 on 表名(字段名) -- 给表中的字段创建索引
create idnex idx_stu_name on student(s_name) --给student表的s_name创建了索引
drop index 索引名 on 表名
drop index idx_stu_name on student --删除索引
PL/SQL - 存储过程
复杂的逻辑通过java程序来实现
DBA - 数据库管理员
create procedure p_test(in a int , out b int) -- p_test是存储过程的名字 , a - 输入参数, b - 输出函数
begin
select s_age into b from student where s_id = a ; -- 存储过程的功能:根据id,查询出学生的年龄
end
set @a = 2;
call p_test(@a,@b);
select @b;
JDBC - JAVA Database Connection
jdbc:java 连接数据库,进行数据库中数据的操作:insert , update , dalete , select
jdk中提供了一套操作数据库的接口:java.sql.*,每一个数据库厂商,实现这些对应的接口,把这些实现类打包为.jar文件。
比如:使用mysql服务器,下载mysql对应的jar包,使用的oracle服务器,下载对应的oracle的jar包。
jar包:以 .jar 为后缀的文件,称为java的归档文件,保存的是java的字节码文件(.class),在我们的java工程中,导入 .jar 文件,就可以使用这些 .class
核心接口
Connection,用于设置连接数据库的地址,账号,密码
PreparedStatement,用于预处理,始行sql
ResultSet,用于接收查询后的数据
项目中导入数据库驱动程序包 -jar
把msql的驱动程序包,添加到项目中(建一个lib文件夹,然后把jar包复制到这个文件夹中)
在.jar文件上,右键,选择"add as library"
查询
package test;
import entity.School;
import java.sql.*;
public class SchoolTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/bookdb?serverTimeZone=Asia/shanghai";
String user = "root";
String pwd = "123456";
Connection con = DriverManager.getConnection(url, user, pwd);
System.out.println(con);
String sql = "select * from school";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()){
int code = rs.getInt(1);
String name = rs.getString(2);
Date birth = rs.getDate(3);
String address = rs.getString(4);
int total = rs.getInt(5);
double area = rs.getDouble(6);
School school = new School(code, name, birth, address, total, area);
System.out.println(school);
}
rs.close();
ps.close();
con.close();
}
}
增加
package test;
import entity.School;
import java.sql.*;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class SchoolInsert {
public static void main(String[] args) throws ClassNotFoundException, SQLException, ParseException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/bookdb?serverTimeZone=Asia/shanghai";
String user = "root";
String pwd = "123456";
Connection con = DriverManager.getConnection(url, user, pwd);
System.out.println(con);
String sql = "insert into school values (?,?,?,?,?,?)";
PreparedStatement ps = con.prepareStatement(sql);
ps.setInt(1, 3);
ps.setString(2, "重庆兴渝学校");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse("2022-08-04 00:00:00");
long dateTime = date.getTime();
ps.setDate(3, new java.sql.Date(dateTime));
ps.setString(4, "重庆市九龙坡区二郎新区大道99号");
ps.setInt(5, 10000);
ps.setDouble(6, 5220.2);
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
ps.close();
con.close();
}
}
修改
package test;
import java.sql.*;
import java.text.ParseException;
public class SchoolUpdate {
public static void main(String[] args) throws ClassNotFoundException, SQLException, ParseException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/bookdb?serverTimeZone=Asia/shanghai";
String user = "root";
String pwd = "123456";
Connection con = DriverManager.getConnection(url, user, pwd);
System.out.println(con);
String sql = "update school set sc_code = 5,sc_name ='重庆中学' where sc_code=3";
PreparedStatement ps = con.prepareStatement(sql);
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("修改成功");
} else {
System.out.println("修改失败");
}
ps.close();
con.close();
}
}
删除
package test;
import java.sql.*;
import java.text.ParseException;
public class SchoolDelete{
public static void main(String[] args) throws ClassNotFoundException, SQLException, ParseException {
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/bookdb?serverTimeZone=Asia/shanghai";
String user = "root";
String pwd = "123456";
Connection con = DriverManager.getConnection(url, user, pwd);
System.out.println(con);
String sql = "Delete from school where sc_code = 5";
PreparedStatement ps = con.prepareStatement(sql);
int i = ps.executeUpdate();
if (i > 0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
ps.close();
con.close();
}
}
事务
事务是由一组数据sql语句组成的执行单元(几个sql是要一个整体操作),这些sql语句之间一般互相依赖,那么这些sql语句要么全部成功,要么全部失败(原子性)
事务的使用
提交:commit,事务执行成功,需要commit
回滚: rollback,事务执行失败了。需要rollback,回滚到事务执行之前的状态
java中的jdbc默认是自动提交了
con.setAutoCommit(false): 设置了不自动提交,那么sql执行之后,需要主动提交:con.commit();
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.url地址,用户名,密码
String url = "jdbc:mysql://localhost:3306/cms?serverTimeZone=Asia/shanghai";
String user = "root";
String pwd = "123456";
//3.获取连接
Connection con = DriverManager.getConnection(url, user, pwd);
con.setAutoCommit(false);
//4.增加(insert...)
String sql = "insert into book_info values(0,'基督山伯爵','大促马',19.6,'1655-02-15',1001,2)";
PreparedStatement ps = con.prepareStatement(sql);
int i = ps.executeUpdate();// i -- 返回行数
if (i>0){
System.out.println("添加成功");
}else {
System.out.println("添加失败");
}
con.commit(); // 提交
//5.释放资源
ps.close();
con.close();
事务的特性ACID
原子性:atomicity,事务是最小的执行单元
一致性:Consistency,事务执行的前后,必须让所有的数据保持一致状态。(总体数据守恒)
隔离性:Isolation,事务并发时相互隔离,互补影响
持久性:Durability。事务一旦提交,对数据的改变是永久的
事务并发可能出现的问题
在同一时间同时执行了多个事务,称为事务的并发
事务并发可能会出现以下问题:
问题 | 描述 |
脏读 | 事务A读取到了事务B未提交的数据 |
不可重复读 | 事务A中如果读取两次数据,在这期间,事务B对数据进行了修改并提交,导致事务A读取两次的数据情况不一致 |
幻读 | 事务A读取id从1~10之间的数据,假如只有到2,5数据,在读取的期间,事务B添加了id为3的数据。导致事务A多读到了事务B中的数据 |
事务的隔离级别
为了防止事务并发时出现以上的情况。数据库中设计了集中事务与事务之间的隔离级别
隔离级别 | 能否出现脏读 | 能否出现不可重复读 | 能否出现幻读 |
Read Uncommited 未提交读(RU) | 会 | 会 | 会 |
Read Commited 已提交读(RC)默认(Oracle) | 不会 | 会 | 会 |
Repeatable Read 可重复读(RR) | 不会 | 不会 | 会 |
Serializable 可以序列化 | 不会 | 不会 | 不会 |
redis - 非关系型数据库
关系型数据库:mysql 、oracle ,以二维表的形式存储在硬盘上,支持sql语言
非关系型数据库:redis,存储在内存中,不支持sql语言
redis 安装
双击安装包
redis 的命令
通过命令,存,取,改,删数据
字符串操作
set user alice -- 保存一个key是user,value是alice的字符串内容到redis服务器
get user -- 根据key,找到value
strlen user -- 获取长度
getrange user 0 1 -- 取子字符串
hashes操作(hashmap)
hmset hqyj web www.baidu.com tel 023-111 address 总部城A区 -- 存储
了一个hqyj 这个hashmap , 保存了三个键值对
hgetall hqyj -- 查看所有的内容
hkeys hqyj -- hashmap的键
hvals hqyj -- hsahmap 的values
hdel hqyj web -- 删除一个键
ists 操作
lpush java css -- 从队列的左边添加一个
rpush java js -- 从队列的右边添加一个
lpush java servert mysql jsp -- 一次加多个
lrange java 0 1 -- 指点范围查看元素
lindex java 1 -- 查找指定索引位置的元素
lpop java -- 从左边出队一个
rpop java -- 从右边出队一个
set 操作
sadd web html -- 增加一个数据
sadd web css js jquery -- 批量增加
scard web -- 查看数据量
smembers web -- 查看成员
srem web jquery -- 删除一个成员
key 操作
keys * -- 查看所有的键
keys u* -- 模糊匹配, 查看u开始的
del key -- 删除key
exist key -- 判断是否存在
rename key newkey -- 修改名字
type key -- 查看key的类型
java程序操作redis数据库
redis数据库的驱动jar包(redis数据库操作的类)
java程序,连接上redis数据库,然后调用操作数据库的各种方法
package test;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RedisTest {
public static void main(String[] args) {
//testString();
//testSet();
//testList();
testHash();
}
// 4.测试hash
public static void testHash() {
Jedis jedis = new Jedis("localhost");
Map<String, String> map = new HashMap<>();
map.put("语文", "80");
map.put("数学", "90");
map.put("英语", "100");
jedis.hmset("score", map); // 存储
System.out.println("所有的keys:" + jedis.hkeys("score"));
System.out.println("所有的values:" + jedis.hvals("score"));
Map<String, String> score = jedis.hgetAll("score");
Set<Map.Entry<String, String>> entries = score.entrySet();
for (Map.Entry<String, String> one : entries) {
System.out.println(one.getKey() + "---" + one.getValue());
}
}
// 3. 测试list
public static void testList() {
Jedis jedis = new Jedis("localhost");
jedis.lpush("stu", "a1", "a2", "a3");
jedis.rpush("stu", "a4", "a5", "a6");
System.out.println("学生的个数:" + jedis.llen("stu"));
System.out.println("索引为3的学生:" + jedis.lindex("stu", 3));
List<String> stus = jedis.lrange("stu", 0, jedis.llen("stu") - 1);// 获取全部元素,保存到List中
System.out.println(stus);
jedis.lrem("stu", 1, "a1"); // lrem 删除
System.out.println("出去一个:" + jedis.lpop("stu"));
jedis.close();
}
// 2. 测试set
public static void testSet() {
Jedis jedis = new Jedis("localhost");
// 重庆风景区保存redis中
jedis.sadd("cqfjq", "李子坝", "磁器口", "解放碑", "观音桥");
jedis.sadd("cqfjq", "杨家坪");
// 查看成员
Set<String> cqfjq = jedis.smembers("cqfjq");
for (String s : cqfjq) {
System.out.println(s);
}
Long num = jedis.scard("cqfjq");
System.out.println("风景区的数量:" + num);
jedis.close();
}
// 1. 测试字符串
public static void testString() {
Jedis jedis = new Jedis("localhost"); // 端口号默认是6379
System.out.println(jedis);
// set user tom -- 命令 , 存要给字符串
jedis.set("username", "admin");
System.out.println("redis数据库中的所有key:");
System.out.println(jedis.keys("*"));
String username = jedis.get("username");
System.out.println("username:" + username);
System.out.println("判断keys是否存储:" + jedis.exists("web"));
System.out.println("username的长度:" + jedis.strlen("username"));
jedis.close();
}
}