Java面试准备之 事务
发布日期:2021-09-29 01:26:42 浏览次数:6 分类:技术文章

本文共 5835 字,大约阅读时间需要 19 分钟。

这里只是为了记录,由于自身水平实在不怎么样,难免错误百出,有错的地方还望大家多多指出,谢谢。

参考

1. 事务的理论级概念

(1)事务具有ACID的特性:

原子性

一致性
隔离性
持续性

Atomicity:原子性

事务是最小的执行单位,不可分割,必须一次作为一个整体执行完;

Consistency:一致性

事务如果中间被割裂可能会导致数据的不一致性,因此事务最终的目的就是为了保证数据的完整性和一致性,而这个性质是由原子性来保障的;

Isolation:隔离性

并发事务之间不能相互影响(并发事务竞争的数据必然被同步监视),
原因很简单,那就是原子性!并发事务之间不能看到对方的中间状态!由此可见原子性是事务的根本属性,其他特性都是由原子性保证的;

Durability:持续性

也称为持久性,是指事务一旦提交,那么对数据的修改就会永久保存到物理存储器中!未提交之前只是在内存映像中进行修改!

(2) 事务的内容和提交

  • 事务必须是由DML语句组成的:只是显然的,事务就是为了防止修改数据时发生数据的不一致!但中间允许出现select语句,但是select语句并不属于事务的一部分,因为select语句并不修改数据,仅仅就是临时查看一下结果而已;

  • Ⅱ 最多只能出现一条DDL或者DCL语句,并且必须作为最后一句:因为DDL和DCL默认会自动触发提交动作,出现或者就意味着事务已经结束。

  • Ⅲ 显示提交和隐式提交:显式提交就是手动显示执行commit命令,隐式提交就是执行或DCL语句,在JDBC编程中顺利从方法中正常退出也会隐式自动提交!

(3) 回滚

显式回滚:手动显示执行rollback命令;

隐式回滚:抛出了没有处理的异常;在JDBC编程中主动强行从一个方法中退出(强退 、exit等)也会触发隐式回滚;
注 :
DML:
data manipulation language,它们是select、update、insert、delete,就像它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言。

DDL:

DDL比DML要多,主要的命令有CREATE 、ALTER 、DROP等,DDL主要是用在定义或改变表结构,数据类型,表之间的连接和约束等初始化工作上,他们大多在建立表时使用。

DCL:

是数据库控制功能。是用来设置或更改数据库用户或角色权限的语句,包括(grant,deny,revoke等)语句。在默认状态下,只有sysadmin, dbcreator, db_ouner或db_securityadmin等人员才有权利执行DCL。

2. 关闭自动提交功能来开启事务

(1)其实默认状态下MySQL将每一条输入的SQL命令都当做一个单独的事务来处理,比如你输入了一条insert into(DML)命令,它会立即执行并将修改直接更新奥物理存储器上,这是因为MySQL默认将每一条SQL命令都当做一个单独事务来了,并且执行一条命令就自动提交。

(2)MySQL默认将自动提交功能开启了,即每输入一条MySQL语句都会被当做一个单独的事务并立即提交!因此,为了开启事务功能,就必须将自动提交的功能关闭掉!

(3)开关命令:set autocommit=0|1; (这里是SQL命令)

0表示关闭自动提交
1表示开启自动提交
一旦开启了事务功能,就可以顺利执行DML语句了,一旦执行到DCL/DDL或者执行了commit就会提交由之前连续的DML组成的一个事务,而后面的语句将开启一个新的事务。当然也可以用rollback命令来回滚事务;
示例如下:

drop table if exists emp;create table emp(emp_id int PRIMARY key,emp_name VARCHAR(20))set autocommit = 0;-- 设置手动提交事务insert into emp values (1, 'jj');insert into emp values(2, 't');COMMIT; -- 提交事务-- 执行完commit之后,上面的sql语句组成的事务结束insert into emp values(3, 'bb'); -- 开启一个新的事务insert into emp values('c', 'cc');COMMIT;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

结果是只有id为1、2的记录能被插入到数据库,id为3,’c’的记录没能被插入到数据库,因为id为int,所以在插入id为’c’的记录时出错,而id为3,’c’的记录是在一个事务里面的,所有事务不能被成功执行。

注:在执行sql的过程中,如果出错,则不会再执行下面的sql了。示例如下:

drop table if exists emp;create table emp(emp_id int PRIMARY key,emp_name VARCHAR(20))set  autocommit = 1;insert  into emp values('c', 'bbb');  -- 如果sql语句出错了的话,就不会再执行下面的语句了insert into emp values(1, 'aaa');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(4)开启临时事务:

①当你在命令行对数据库进行操作是可能不想set autocommit=0来关掉自动提交,而只是想临时执行一段事务,这种需要是常见的;

②那么可以输入begin或者start transaction命令(以分号结尾)表示开启了一个临时性的事务;
③接下里就一条条执行事务的DML语句就行了;
⑤遇到commit或者DDL或DCL就会提交本次临时事务,然后本次临时事务结束,重新回到自动提交的状态,如果要想再执行事务那就必须再使用begin或start transaction开启一个临时事务!
示例如下:

drop table if exists emp;create table emp(emp_id int PRIMARY key,emp_name VARCHAR(20))START TRANSACTION;-- 开启一个临时事务insert into emp values(2, 'aaa');insert into emp values(3, 'bbb');COMMIT; -- 上面的sql组成一个事务,commit之后事务结束START TRANSACTION;-- 上面的commit之后,又回到了自动提交事物的状态,这时要执行事务操作的话,要重新开启一个临时事务,或者set autocommit=0;insert into emp values(1, 'aaa');insert into emp values('c', '123');COMMIT;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

结果如下:

sql执行结果

(5)开启多个命令行对自动提交模式的影响:由于每个SQL命令行窗口都是一个独立的连接session,因此相互之间互不影响,在一个命令行窗口中设置了自动提交模式并不会影响其他SQL命令行窗口。

3. 中间点

(1)SQL提供了中间点,允许回滚时不必全部回滚,而是回滚到中间点的位置;

(2)设置中间点的语法是:savepoint 自定义中间点的命名;
(3)中间点肯定是在事务的DML语句中间加入的
(4)考虑到中间点可以设置很多,因此回滚的时候必须制定到哪个中间点上,语法为: rollback to 中间点的名字;

4. JDBC对事务的支持
(1)由JDBC对事物的管理交由Connection, 都是Connection的对象方法实现的;
(2)首先关闭自动提交开启事务功能:void Connection.setAutoCommit(boolean autoCommit);//false表示关闭自动提交事务功能
(3)当然也可以查看自动提交功能是否开启:boolean Connection.getAutoCommit(); //true表示开启了自动提交事务功能
(4)开启事务功能后就是执行事务了,事务就是一条条DML语句,因此就是一条条stmt.executeUpdate语句了。
(5)提交任务:
Ⅰ当你执行到第一条DDL/DCL时自动提交(execute一条DDL/DCL语句);
Ⅱ void Connection.commit(); //显示提交
(6)回滚
Ⅰ如果事务执行过程中抛出异常则会自动隐式回滚;
Ⅱ显示回滚:void rollback();
(7)中间点
设置中间点
ⅠSavepoint Connection.setSavepoint();//在事务的某个位置设置一个中间点,该中间点没有命名,使用系统默认的命名
Ⅱ Savepoint setSavepoint(String name)//给中间点命名
Ⅲ 回滚到指定的中间点: void Connection.rollback(Savepoint savepoint);//回滚到指定的中间点,回滚到中间点的API就这么一个,回滚位置是由Savepoint对象指定的,并不是由中间点名称决定的,因此一般命名的setSavepoint方法不怎么用,但是那个命名还是可以使用的,那就是必须得到数据库的命令行中使用rollback to命令才能访问那个中间点的命名;

示例:事务在执行过程中遇到没有处理的异常将自动回滚

@Test    public void test3(){        Savepoint sp1 = null;                   try {                conn = C3P0Util.getConnection();                conn.setAutoCommit(false);//设置为手动提交事务                String sql1 = "update emp set emp_name='cc' where emp_id=3";                PreparedStatement pstmt = conn.prepareStatement(sql1);                pstmt.execute();                sp1 = conn.setSavepoint();                String sql2 = "insert into emp values(?,?)";                PreparedStatement pstmt2 = conn.prepareStatement(sql2);                pstmt2.setInt(1, 4);                pstmt2.setString(2, "dd");                          pstmt2.execute();                int a=1/0;//会报错                System.out.println("出现错误后并不会执行下面的conn.commit(),所以这句话不会被打印出来");                conn.commit();            }catch (Exception e) {                try {                    conn.rollback(sp1);//出现错误之后会回滚到指定的中间点                } catch (SQLException e1) {                    throw new RuntimeException(e);                }            }finally{                if(conn!=null){                    try {                        conn.close();                    } catch (SQLException e) {                        throw new RuntimeException(e);                    }                }                           }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
5.事务配合批量更新
(1)为了让批量更新能正确处理错误,应该将整个批处理包装成一个事务来处理,以便出现意外可以及时的回滚,毕竟批处理的量都比较大,如果出现了问题会导致大量数据不一致和不完整,后果不堪设想,因此一般批处理都要做成事务来执行,示例:
conn = C3P0Util.getConnection();        conn.setAutoCommit(false);        ...        Statement stmt = conn.createStatement();        stmt.addBatch(sql1);        stmt.addBatch(sql2);        stmt.addBatch(sql3);        stmt.addBatch(sql4);        ...        stmt.executeBatch();//返回int[]表示每个DML语句更新了多少行        conn.commit();        conn.setAutoCommit(true);//还原状态

转载地址:https://blog.csdn.net/happydecai/article/details/79791692 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SpringMVC工作原理
下一篇:面试准备专题——高并发高性能网站设计

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年03月11日 18时14分45秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

java list二分查找_java中的ArrayList和LinkedList的二分查找速度比 | 学步园 2021-06-24
php中的变量名称用什么表示,PHP变量,方法,类等名称中的有效字符是什么? 2021-06-24
pic32mx是什么cpu_PIC32MX单片机外设库使用(Ⅰ)- 系统时钟及I/O口基本设置 2021-06-24
用c 在mysql上存图片_C 批量保存图片进 mysql 利用MYSQL_BIND插入longblob 2021-06-24
mysql 1045 28000_mysql报关于用户密码1045(28000),几种处理方法 (zhuan) 2021-06-24
solr比mysql的优势_Solr与Elasticsearch的优缺点比较总结和归纳 2021-06-24
华为博士招聘上机考试题目_牛客网-华为-2020届校园招聘上机考试-3 2021-06-24
python中for可以做变量名吗_Python中使用动态变量名的方法 2021-06-24
mysql 日期转换天数_MySQL 日期操作 增减天数、时间转换、时间戳 2021-06-24
java对象去重复_JAVA中List对象去除重复值的方法 2021-06-24
java bss_[转] .bss段和.data段的区别 2021-06-24
java上传图片损坏_大神求助 上传图片后 图片损坏 2021-06-24
java socket唯一标识符_Java Socket编程之常识网络基础知识 2021-06-24
java给xyz大小排序_java递归实现string xyz排序 2021-06-24
arctime必须要java_Arctime使用教程 Arctime常见问题解答 2021-06-24
mysql pxc mysql5.7_mysql之PXC5.7.18集群系列——1. Percona XtraDB Cluster 搭建 2021-06-24
mysql 自适应字段宽度_box-sizing解决自适应布局容器宽度问题 2021-06-24
java 配置文件配置路径_Java读取配置文件路径设置 2021-06-24
vux 选择器_vue中的scoped分析以及在element-UI和vux中的应用 2021-06-24
java cache 有效期_springboot cache 自定义过期时间及自定义缓存key前缀 2021-06-24