目录

上集回顾

事务

2.1 为什么使用事务

2.2 事务的概念

事务的ACID特性

(原子性,持久性,隔离性,一致性)

并发事务:并发 、 并行

问题一 脏读

问题二: 不可重复读

2.3 事物的三个操作

MySQL事务的四种隔离级别

编辑编辑幻读

事物隔离级别图

JDBC : Java操作数据库的规范

JDBC工作原理编辑

*.jar

IDEA项目引入jar包

用IDEA操作数据库


上集回顾

1. 聚簇索引和非聚簇索引的区别

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库

2. Mysql 为何采用B+树作为索引的实现结构,为何不用RBTree(红黑树), 哈希表

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_02

3. B-树和B+树的各自特点以及B+树的优势–结合画图讲解

解析:B-数 和B+树的优点去看数据库07笔记

4. 什么时候需要考虑使用索引? :数据量比较大,且经常查多改少的场景
注释:索引:也有时间和空间的开销——索引和数据表的关系就相当于书的目录和内容的关系
 

注释:MySQL的索引和事务内容,必须要知道,背也要背下来,必考

事务

2.1 为什么使用事务

drop table if exists accout;
create table accout(
 id int primary key auto_increment,
 name varchar(20) comment '账户名称',
 money decimal(11,2) comment '金额'
);
insert into accout(name, money) values
('阿里巴巴', 5000),
('四十大盗', 1000);

比如说,四十大盗把从阿里巴巴的账户上偷盗了2000元,相应的sql语句

-- 阿里巴巴账户减少2000
update accout set money=money-2000 where name = '阿里巴巴';
-- 四十大盗账户增加2000
update accout set money=money+2000 where name = '四十大盗';

那就是从阿里巴巴的账户上转出 2000 ,增加到 四十大盗的账户上。

可现在发生了意外:假如在执行以上第一句SQL时,出现网络错误,或是数据库挂掉了,阿里巴巴的账户会减少2000,但是 四十大盗的账户上就没有了增加的金额。

如果发生了这样的情况就灾难性的错误~~

解决方案:使用事务来控制,保证以上两句SQL要么全部执行成功,要么全部执行失败。

2.2 事务的概念

所谓的事务:把若干个SQL操作打包为一个整体,实际执行的时候,这个整体要么全部执行,要么都不执行

若执行的过程中出现了突发情况,某些操作执行不下去了,MySQL可以保证突发情况恢复之后,数据没有遭到破坏

通过事务的"回滚"--- roll back 操作进行数据的还原~~

(MySQL中的binlog日志文件实现,记录了所有表数据的修改动作)

binlog日志文件:比如是那年那月什么时间谁给谁转账,转了多少等等...都有记录。到时候如果发生错误可以根据bonlog文件恢复文件信息。

事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。 在不同的环境中,都可以有事务。对应在数据库中,就是数据库事务。

事务的ACID特性

(原子性,持久性,隔离性,一致性)

原子性:事务中最核心的操作
        

一个事务中的所有操作,要么全部执行成功,要么全部执行失败。

(执行失败之后,数据的恢复就通过rollback回滚)

持久性:一个事务执行完成之后,这个事务对数据库的所有修改都有永久的(持久化,保存到磁盘上),不会丢失
 

一致性:一个事务执行前后的数据都是一种合法性的状态,事务永远都是从一个一致性状态到另一个一致性状态。

在执行事务前后,数据库的数据都是合理的~~
举例:

假设执行更新操作之前,海盗的账户有 10w 而 阿里巴巴的账户有 90w , 如果阿里账户给我转了20w,那就变成了 海盗 30w,阿里 70w。如果海盗还是 10w,阿里却变了 70w,这明显是不合理状态。 因为不管我们之间怎么转账, 金额加一起总额一定会是 100w才对。

一致性就是不管是转账前还是转账后,转了多少,两个人加起来的金额总数就不能发生变化的
 

隔离性:多个并发事务访问数据库时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,不同事务之间相互隔离。

普通SQL:一个SQL中执行的操作,MySQL自身可以保证数据并发时的正确性(通过读写锁),若是事务,并发执行就会存在相应的问题。
 

注释:一条sql语句,MySQL可以保证数据并发时的正确性,而事物却不行。

并发事务:并发 、 并行

并发:多个任务不一定是在同时执行的,也不一定就是在不同的CPU上执行

          以前老旧电脑上的单核处理器上的任务调度都属于并发执行。

核心思修:强调一个处理器同时处理多个任务,并不是正在同时运行。

举例:在一个单核的CUP下

我分别在qq和微信都给别人发消息,并且别人都回复了。

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_03

 在cup执行完你发生的qq消息等待别人回复你的期间,cpu并不会死等卡在那里,而是先暂停了qq的进程转而去执行任务二了,同样,在等待微信回复时cpu又跳会到qq上。

CPU的执行顺序是 1,2,3,4 。但因为cpu的执行速度超级快,会让你感觉是在同一时刻执行发生的。但其实是在不同时间段执行不同的任务。

并行:多个任务一定是在不同的CPU上同时执行
 

核心思路:强调多个处理器或者是多核的处理器同时处理多个不同的任务,同时运行多段代码

问题一 脏读

事务A在修改数据,事务B读取到了事务A修改后的数据,事务A进行了"回滚",前面的修改不做数了~~

事务B读到的数据就是"脏"数据~~这种情况称为脏读。

相当于读取到了被撤回的数据

问题二: 不可重复读

同一个事务在多次相同查询后得到的数据不同

在不同的查询时,其他事务的修改对于本事务来说是可见的。

相当于我第一次读到 conut 值的 50,过了一段时间,在这期间内别人在这个表中通过事物把conut值变成了 65,那么下次我再次读取conut值,值就应该是 65,最新的。因为别的事物修改对本事物来说是可见的。

2.3 事物的三个操作

(1)开启事务:start transaction;

当输入开启事物的语句时,后面的多个sql语句算一个整体

(2)执行多条SQL语句

(3)回滚或提交:rollback/commit;

回滚操作,rollback回滚了上次对数据库做的修改

提交事务,就是把开启事务之后的所有SQL语句统一在数据库上进行持久化。

说明:rollback即是全部失败,commit即是全部成功。

注释:只要事物没有进行提交,那都是临时的。提交事物之后才算把这个对象真正写进了磁盘里面。才能对其他事物可见。

MySQL事务的四种隔离级别

1.读未提交∶处在该隔离级别的事务可以看到其他还没提交事务对数据库的修改~~RU

脏读,不可重复读,环读

⒉读已提交:处在该隔离级别的事务可以看到其他已经提交事务对数据库的修改~RC

   Oracle数据库默认的隔离级别

3.可重复读:lnnoDB引擎默认的隔离级别
一个事务一旦开启,在该隔离级别下,该事务提交之前,多次查询看到的结果是相同的~~无论其他事务如何修改数据库,在当前这个事务下都是不可见的~~

4.串行化:事务最高隔离级别,所有事务都串行访问数据库,不会发生冲突,不会产生任何事务的问题,就没有并发执行了~~

串行化就相当于排队执行,没有一起执行待来的冲突。先你后他。

举例:

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_04

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_05

幻读

有一种情况幻读:每次查询得到的值都是相同的,其他事务的修改对于本事务不可见,明明事务中查询不到重复的id信息,但是就是插入不进行,称为幻读。

注释:可重复读的事务中,第一次查询得到的视图会被后面一直使用

 幻读举例说明:假设你现在开启了两个终端

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_06

 一个是终端A,一个是终端B

 现在我们先在终端A中进入某个数据库中,此时开启事物。

 现在我在一个为空的表a中插入两组数据

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_07

如果在当前终端A中去查询表a,肯定是能查询这插入的两条信息的。

但如果你此时在终端A没有提交事物的前提下去终端B查询表a,结果就为空,但如果你想插入数据编号为1或者2时,就会显示插入失败,因为虽然这两个数据对终端B不可见,但就是不能插入,因为已经存在了,这就是幻读。

重点来了

如果现在我们采用的是串行化隔离级别的话,就根本不会出现幻读这样的情况了。只有当一个事物结束后才能去进行另一个事物。

 

 注释:讲清楚事务的四种隔离级别以及相应的问题

             脏读,不可重复读,幻读

事物隔离级别图

上面四种隔离是递进关系

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_08

 串行化隔离能全部解决这三个问题带来的影响

事务的隔离级别越高,安全性越强,并发性就越低
 

JDBC : Java操作数据库的规范

比如我们现在想通过java语言去操控mysql数据库,那么它们之间就需要一个桥梁:数据驱动包

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_09

 注释:这些驱动包一般都是数据库的厂家写的。

java.sql:无论现在通过Java操作哪个具体的数据库,数据库厂商实现的驱动包都需要满足JDBC的标准(实现接口)
 

JDBC工作原理

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_10

 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_11

相当于我们插入一个新的设备的时候都会在安装驱动,这个驱动就目的就是为了让我们这个设备能在这电脑上正常的运转。而这个驱动一般都是厂商实现写好的,要满足USB接口的标准才行。

我们这里的JDBC相当于接口标准

*.jar

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_12

注释:上面这两个就是压缩文件, jar包中都存储了编译好的class文件

 

IDEA项目引入jar包

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java_13

 从这里就可以看到我们现在依赖的只有这个1.8的包

先右击当前项目

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_14

 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_15

点击 +  

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_16

然后找到jar包保存的目录

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java_17

 

点击ok

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_18

 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_19

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java_20

 

 

用IDEA操作数据库

1. 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java_21

 头文件:import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

不管是哪个数据库都需要覆写实现 DataSource 这个类

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_22

  2. 

// 2.配置数据源的属性,用户名,密码,连接的ip和端口号
 dataSource.setURL("jdbc:mysql://127.0.0.1:3306/test_6_6?characterEncoding=utf8&useSSL=false");

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_23

 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_24

注释:如果你是在自己电脑上操作连接,其他都不用改,只需要写人你连接的数据库名称即可 

3.

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_25

 

 上面两个命令相当于SQL里: -u root -p 加上你要输出的密码 1

4. 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_26

 加上请求异常处理

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_27

 5.

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_28

语句就是平常写的添加sql语句一样,用字符串形式。 具体的值先用?,后面可以用具体值替换 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_29

 6.

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_30

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_数据库_31

 

 在sql中我们只想 select ...这条语句的时候就需要一个对象,上面的PreparedStatement

就是对象

prepareStatement 里面的sql语句就是我们等会要执行的语句 

7.

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_32

8.

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_33

运行查看结果 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_34

这是原来的表内容 

运行程序

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_sql_35

 

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java 接收数据库blob 字段乱码_36

 数据库中的增删改到差不多

查询方法

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.swing.text.html.HTMLDocument;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * jdbc的查询操作
 */
public class JDBCTest1 {
    public static void main(String[] args) throws SQLException {
        // 1.获取数据源
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setURL("jdbc:mysql://127.0.0.1:3306/test_6_6?characterEncoding=utf8&useSSL=false");
        dataSource.setUser("root");
        dataSource.setPassword("1");
        // 2.获取连接对象,发起请求获取MySQL连接
        Connection connection = dataSource.getConnection();
        // 3.获取Statement对象,就是具体执行SQL的对象
        String sql = "select * from user where id = ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1,"2");
        // 4.执行SQL取得返回值,返回值存在ResultSet对象中
        ResultSet resultSet = statement.executeQuery();
        // 5.遍历结果集
        String pass = null;
        while (resultSet.next()) {
            // 获取查询结果集中列名为id的属性值,数据库的列是什么类型,咱就用Java中对应的类型来接收
            int id = resultSet.getInt("id");
            // 查询结果集中属性名为username的属性值
            String name = resultSet.getString("name");
            System.out.println("id = " + id + ",name = " + name);

        }

        // 6.关闭资源
        resultSet.close();
        connection.close();
    }
}

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_java_37

 小知识

java 接收数据库blob 字段乱码 数据库的decimal类型java怎么接收_隔离级别_38