jdbc executebatch 非事务_面试:Mybatis事务请讲解一下?
1.说到数据库事务,人们脑海里自然不自然的就会浮现出事务的四大特性、四大隔离级别、七大传播特性。四大还好说,问题是七大传播特性是哪儿来的?是Spring在当前线程内,处理多个数据库操作方法事务时所做的一种事务应用策略。事务本身并不存在什么传播特性,不要混淆事务本身和Spring的事务应用策略。(当然,找工作面试时,还是可以巧妙的描述传播特性的)
2.一说到事务,人们可能又会想起create、begin、commit、rollback、close、suspend。可实际上,只有commit、rollback是实际存在的,剩下的create、begin、close、suspend都是虚幻的,是业务层或数据库底层应用语意,而非JDBC事务的真实命令。
create(事务创建):不存在。begin(事务开始):姑且认为存在于DB的命令行中,比如Mysql的start transaction命令,以及其他数据库中的begin transaction命令。JDBC中不存在。close(事务关闭):不存在。应用程序接口中的close()方法,是为了把connection放回数据库连接池中,供下一次使用,与事务毫无关系。suspend(事务挂起):不存在。Spring中事务挂起的含义是,需要新事务时,将现有的connection1保存起来(它还有尚未提交的事务),然后创建connection2,connection2提交、回滚、关闭完毕后,再把connection1取出来,完成提交、回滚、关闭等动作,保存connection1的动作称之为事务挂起。在JDBC中,是根本不存在事务挂起的说法的,也不存在这样的接口方法。因此,记住事务的三个真实存在的方法,不要被各种事务状态名词所迷惑,它们分别是:conn.setAutoCommit()、conn.commit()、conn.rollback()。conn.close()含义为关闭一个数据库连接,这已经不再是事务方法了。
1. Mybaits中的事务接口Transaction
public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException;}
有了文章开头的分析,当你再次看到close()方法时,千万别再认为是关闭一个事务了,而是关闭一个conn连接,或者是把conn连接放回连接池内。
事务类层次结构图:
(Made In Intellij Idea IDE)
JdbcTransaction:单独使用Mybatis时,默认的事务管理实现类,就和它的名字一样,它就是我们常说的JDBC事务的极简封装,和编程使用mysql-connector-java-5.1.38-bin.jar事务驱动没啥差别。其极简封装,仅是让connection支持连接池而已。
ManagedTransaction:含义为托管事务,空壳事务管理器,皮包公司。仅是提醒用户,在其它环境中应用时,把事务托管给其它框架,比如托管给Spring,让Spring去管理事务。
org.apache.ibatis.transaction.jdbc.JdbcTransaction.java部分源码。
@Override public void close() throws SQLException { if (connection != null) { resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } connection.close(); } }
面对上面这段代码,我们不禁好奇,connection.close()之前,居然调用了一个resetAutoCommit(),含义为重置autoCommit属性值。connection.close()含义为销毁conn,既然要销毁conn,为何还多此一举的调用一个resetAutoCommit()呢?消失之前多喝口水,真的没有必要。
其实,原因是这样的,connection.close()不意味着真的要销毁conn,而是要把conn放回连接池,供下一次使用,既然还要使用,自然就需要重置AutoCommit属性了。通过生成connection代理类,来实现重回连接池的功能。如果connection是普通的Connection实例,那么代码也是没有问题的,双重支持。
2. 事务工厂TransactionFactory
顾名思义,一个生产JdbcTransaction实例,一个生产ManagedTransaction实例。两个毫无实际意义的工厂类,除了new之外,没有其他代码。
type="JDBC" />
mybatis-config.xml配置文件内,可配置事务管理类型。
3. Transaction的用法
无论是SqlSession,还是Executor,它们的事务方法,最终都指向了Transaction的事务方法,即都是由Transaction来完成事务提交、回滚的。
配一个简单的时序图。
(Made In Visual Paradigm)
代码样例:
public static void main(String[] args) { SqlSession sqlSession = MybatisSqlSessionFactory.openSession();try { StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = new Student(); student.setName("yy"); student.setEmail("email@email.com"); student.setDob(new Date()); student.setPhone(new PhoneNumber("123-2568-8947"));
studentMapper.insertStudent(student); sqlSession.commit(); } catch (Exception e) { sqlSession.rollback(); } finally { sqlSession.close(); } }
注:Executor在执行insertStudent(student)方法时,与事务的提交、回滚、关闭毫无瓜葛(方法内部不会提交、回滚事务),需要像上面的代码一样,手动显示调用commit()、rollback()、close()等方法。
因此,后续在分析到类似insert()、update()等方法内部时,需要忘记事务的存在,不要试图在insert()等方法内部寻找有关事务的任何方法。
4. 你可能关心的有关事务的几种特殊场景表现(重要)
1. 一个conn生命周期内,可以存在无数多个事务。
// 执行了connection.setAutoCommit(false),并返回 SqlSession sqlSession = MybatisSqlSessionFactory.openSession();try { StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = new Student(); student.setName("yy"); student.setEmail("email@email.com"); student.setDob(new Date()); student.setPhone(new PhoneNumber("123-2568-8947"));
studentMapper.insertStudent(student);// 提交 sqlSession.commit();
studentMapper.insertStudent(student);// 多次提交 sqlSession.commit(); } catch (Exception e) { // 回滚,只能回滚当前未提交的事务 sqlSession.rollback(); } finally { sqlSession.close(); }
对于JDBC来说,autoCommit=false时,是自动开启事务的,执行commit()后,该事务结束。以上代码正常情况下,开启了2个事务,向数据库插入了2条数据。JDBC中不存在Hibernate中的session的概念,在JDBC中,insert了几次,数据库就会有几条记录,切勿混淆。而rollback(),只能回滚当前未提交的事务。
2. autoCommit=false,没有执行commit(),仅执行close(),会发生什么?
try { studentMapper.insertStudent(student);} finally { sqlSession.close();}
就像上面这样的代码,没有commit(),固执的程序员总是好奇这样的特例。
insert后,close之前,如果数据库的事务隔离级别是read uncommitted,那么,我们可以在数据库中查询到该条记录。
接着执行sqlSession.close()时,经过SqlSession的判断,决定执行rollback()操作,于是,事务回滚,数据库记录消失。
下面,我们看看org.apache.ibatis.session.defaults.DefaultSqlSession.java中的close()方法源码。
@Override public void close() { try { executor.close(isCommitOrRollbackRequired(false)); dirty = false; } finally { ErrorContext.instance().reset(); } }
事务是否回滚,依靠isCommitOrRollbackRequired(false)方法来判断。
private boolean isCommitOrRollbackRequired(boolean force) { return (!autoCommit && dirty) || force; }
在上面的条件判断中,!autoCommit=true(取反当然是true了),force=false,最终是否回滚事务,只有dirty参数了,dirty含义为是否是脏数据。
@Override public int insert(String statement, Object parameter) { return update(statement, parameter); }
@Override public int update(String statement, Object parameter) { try { dirty = true; MappedStatement ms = configuration.getMappedStatement(statement); return executor.update(ms, wrapCollection(parameter)); } catch (Exception e) { throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
源码很明确,只要执行update操作,就设置dirty=true。insert、delete最终也是执行update操作。
只有在执行完commit()、rollback()、close()等方法后,才会再次设置dirty=false。
@Override public void commit(boolean force) { try { executor.commit(isCommitOrRollbackRequired(force)); dirty = false; } catch (Exception e) { throw ExceptionFactory.wrapException("Error committing transaction. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
因此,得出结论:autoCommit=false,但是没有手动commit,在sqlSession.close()时,Mybatis会将事务进行rollback()操作,然后才执行conn.close()关闭连接,当然数据最终也就没能持久化到数据库中了。
3. autoCommit=false,没有commit,也没有close,会发生什么?
studentMapper.insertStudent(student);
干脆,就这一句话,即不commit,也不close。
结论:insert后,jvm结束前,如果事务隔离级别是read uncommitted,我们可以查到该条记录。jvm结束后,事务被rollback(),记录消失。通过断点debug方式,你可以看到效果。
这说明JDBC驱动实现,已经Kao虑到这样的特例情况,底层已经有相应的处理机制了。这也超出了我们的探究范围。
但是,一万个屌丝程序员会对你说:Don't do it like this. Go right way。
警告:请按正确的try-catch-finally编程方式处理事务,若不从,本人概不负责后果。
注:无参的openSession()方法,会自动设置autoCommit=false。
总结:Mybatis的JdbcTransaction,和纯粹的Jdbc事务,几乎没有差别,它仅是扩展支持了连接池的connection。另外,需要明确,无论你是否手动处理了事务,只要是对数据库进行任何update操作(update、delete、insert),都一定是在事务中进行的,这是数据库的设计规范之一。读完本篇文章,是否颠覆了你心中目前对事务的理解呢?
--END--
▐ 推荐
【大数据】教程 完整版
【JAVA】从零基础到精通完整版视频 附源码+工具+笔记文档 IDEA版
【Web前端】WEB前端全栈工程师开发 附完整视频+源码+工具
【软件测试】从零基础到软件测试工程师 附完整视频+工具+面试简历
【Python】从零基础到精通完整版视频教程 附源码+工具+文档
Java高并发,如何解决?什么方式解决?| 文末送书
公众号ID|javabaiwen
小编微信|619531440
每天分享技术干货
视频|电子书|面试题|开发经验
jdbc executebatch 非事务_面试:Mybatis事务请讲解一下?相关推荐
- jdbc executebatch 非事务_jdbc技术
1.什么是JDBC JDBC(Java DataBase Connectivity)java 数据库连接 是JavaEE 平台下的技术规范 定义了在Java 语言中连接数据,执行SQL 语句的标准 可 ...
- mongodb 事务_初探MongoDB事务机制
背景 最近有一个业务需要同时写两个表,并且需要保证数据的正确性.我们的项目线上的 MongoDB 版本是 4.0,查了一下发现 4.0 版本的 MongoDB 已经支持副本集中的事务了,于是做了一下调 ...
- java 静态方法 调用非静态方法_面试官:为什么java中静态方法不能调用非静态方法或变量?...
这个可能很多人之前学习jvm的时候都会遇到,属于一个小问题,写这篇文章的原因是我在看java相关的面试题目中遇到的,因此顺手总结一下: 一.例子 我们先看效果: 我们在静态方法main中调用非静态变量 ...
- mysql sqlserver 事务_[MSSQL]SQLServer事务语法_MySQL
事务全部是关于原子性的.原子性的概念是指可以把一些事情当做一个单元来看待.从数据库的角度看,它是指应全部执行或全部都不执行的一条或多条语句的最小组合. 为了理解事务的概念,需要能够定义非常明确的边界. ...
- synchronized不能锁静态变量_面试官:请说一下对象锁和类锁的区别
有锁才有自由 生活中不存在绝对的自由,绝对的自由通常对应的无序和混沌,只有在道德.法律.伦理的约束下的相对自由,才能使人感受到自由. 而在多线程编程中,锁是至关重要的,锁就是道德,就是法律约束,没有锁 ...
- b树删除节点每次只能删一个吗_面试官,请不要问我B+树了!!
每当我们执行某个 SQL 发现很慢时,都会下意识地反应是否加了索引,那么大家是否有想过加了索引为啥会使数据查找更快呢,索引的底层一般又是用什么结构存储的呢,相信大家看了标题已经有答案了,没错!B+树! ...
- 如何把class里的vector结构体memcpy出来_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector...
以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...
- arraylist 后往前遍历_面试官:请说出线程安全的 ArrayList 有哪些,除了Vector
以下环境是 JDK 1.8 ArrayList 的初始容量 面试官:你看过 ArrayList 的源码? Python 小星:看过 面试官:那你说下ArrayList 的初始容量是多少? Python ...
- 面试后要请你吃饭_面试问同事请吃饭唯独不叫你咋办?小伙说这是好机会,当场被录取...
分享职场故事,交流职场经验,欢迎关注"罗波". 不知道大家在面试的过程中,有没有遇到过一些考官出了非常奇葩或者让你难以回答的题目.曾经在一次人事招聘的面试环节中,我的朋友小何就遇到 ...
最新文章
- GPUImage 简介
- leetcode(链表专题)
- 快速部署ldap服务
- 信息学奥赛一本通 1068:与指定数字相同的数的个数 | OpenJudge NOI 1.5 12
- (15)Node.js 自定义模块
- Nexus 安装与配置
- django 分页(2) 使用类 页码显示
- 酒店产生蜱虫原因及如何处理
- 如何设计一个超级牛逼的 Feed 流系统
- 作为面试官的一点心得
- 计算机登录界面怎么切换用户,windows10开机界面怎么切换用户
- 【informix】解决启动报错大全,以及解决办法
- 【边学边记_12】——VGA原理与FPGA实现
- 3种字符设备驱动编程
- 同时打开多个远程桌面连
- JAVA计算机毕业设计基于vue技术的汽车维修检测系统设计与实现源码+数据库+系统+lw文档
- 微信小程序监听app.js中的globalData属性,
- SpringBoot + Spring Cloud +Vue 管理系统后台搭建(七、业务代码通用CURD实现)
- EmailAll 强大的邮箱收集工具(企业邮箱收集)
- 我的世界服务器不显示计分板,我的世界计分板教程 计分板指令详解
热门文章
- USACO 3.2.6 Sweet Butter 香甜的黄油(最短路)
- centos 安装 Pip 的方法总结
- mysql left join 几个意思
- C# COM Object for Use In JavaScript / HTML, Including Event Handling(转载)
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 权限管理
- 实现文本超出显示省略号
- Mac 下如何安装odps eclipse插件
- 更改自身web项目的图标(默认为tomcat的小喵咪)
- 疯狂连连看之开发界面布局
- Failed to connect to bitbucket.org port 443: Operation timed out