1.什么是事务
事务是逻辑上的一组操作,要么都执行,要么都不执行。
我们系统的每个业务方法可能包括了多个原子性的数据库操作,比如下面的 savePerson()
方法中就有两个原子性的数据库操作。这些原子性的数据库操作是有依赖的,它们要么都执行,要不就都不执行。
搭配视频教程学习:https://www.bilibili.com/video/BV1nz4y1d7uy
public void savePerson() {
personDao.save(person);
personDetailDao.save(personDetail);
}
另外,需要格外注意的是:事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的innodb
引擎。但是,如果把数据库引擎变为 myisam
,那么程序也就不再支持事务了!
2.在什么时候想到使用事务
当我们的操作涉及到多个表,或者是多个sql语句的增加insert删除delete修改update的时候,需要保证这些语句都是成功才能完成我们的功能;或者保证这些语句都失败,保证操作是符合要求的。最明了的例子就是转账,从A账户转到B账户中,要保证从A中扣除的金额一定要加到B里去。如果A到B转账成功,那么A扣B加,要保证A和B的账户是均衡的。如果A向B转账的过程中扣款失败了,那就应该把操作都回退,A也不扣,B也不加,保证A和B中账户数据的平衡。
在java代码中写程序,控制事务,此时事务应该放在哪里呢?
在开发中,事务是放在serviceImpl类的业务方法上的,因为一个业务方法可能涉及到多个dao的调用,执行多个sql语句。
3.使用JDBC访问数据库,还是Mybatis访问数据库怎么处理事务
JDBC访问数据库,处理事务:连接对象Connection conn;事务提交 conn.commit ();事务回滚:conn.rollback ();
Mybatis 访问数据库,处理事务:事务提交:SqlSession.commit ();事务回滚:SqlSession.rollback ();
4. 问题3中事务的处理方式有什么不足
(1)不同的数据库访问技术,处理事务的对象,方法不同。JDBC使用的是Connection对象,Mybatis访问对象使用的事SqlSession。方法不同就需要了解不同数据库访问技术使用事务的原理。
(2)掌握多种数据库中事务的处理逻辑,知道什么时候提交,什么时候回滚。
(3)处理事务的多种方法。
总结:多种数据库的访问技术,有不同的事务处理的机制,对象,方法。
5.怎么解决问题4中的这些不足
spring提供了一种处理事务的统一模型,能使用统一的步骤,方式,完成多种不同数据库访问技术的事务处理。
使用spring的事务处理机制,可以完成MyBatis访问数据库的事务处理。
使用spring的事务处理机制,可以完成Hibernate访问数据库的事务处理。
6.处理事务需要怎么做,做什么
Spring处理事务的模型,使用的步骤都是固定的。我们只需要把事务使用的信息提供给spring就可以了。
(1) 事务内部提交,回滚事务,使用的是事务管理器对象,代替我们完成事务的提交commit()和回滚rollback ()操作。事务管理器是一个接口和他的众多实现类。事务管理器是PlatformTransactionManager接口对象,接口中定义了事务的重要方法:一个是提交commit(),一个是回滚rollback();
这个接口的实现类有很多:spirng把每一种数据库访问技术对应的事务处理类都创建好了。
如果我们使用的是MyBatis访问数据库,那Spring创建好的是DataSourceTansactionManager;
如果我们使用的是Hibernate访问数据库,那Spring创建好的是HibernateTansactionManager。
那我们怎么去用Spring创建好的这些事务处理类呢?
我们需要告诉Spring我们使用的是那种数据库访问技术。
怎么告诉Spring呢?
需要声明数据库访问技术对应的事务管理器的实现类,在spring的配置文件中使用声明就可以了,声明之后spring就知道我们用的是那种数据库访问技术了。
例如,我们要使用MyBatis访问数据库,我们就应该在xml配置文件中声明一个DataSourceTansactionManager的bean对象;
(2)我们的业务方法需要什么样的事务呢?需要提供一下事务的类型。
- 说明方法需要的事务:
事务的隔离级别:有4个值。在TransactionDefinition中定义了事务描述相关的3类常量:分别是事务隔离级别、事务传播行为以及事务默认超时时限。在事务隔离级别中定义了5个事务隔离级别的常量,这些常量都以ISOLATION_开头,形如ISOLATION_xxx 。
default:采用数据库默认的隔离级别。MySql的默认隔离级别为可重复读(repeatable_read ),Oracle 默认为读已提交(read_commit )。
另外的4个真正有效值:
- read _uncommitted:读未提交。未解决任何并发问题。
- read _commited:读已提交。解决脏读,存在不可重复读和幻读。
- repeatable_read:可重复读。解决脏读和不可重复读,存在幻读。
- serializable:串行化,不存在并发问题。
- 事务的超时时间(timeout),表示一个方法最长的执行时间,如果方法执行时超过了这个时间,事务就回滚。超时时间的单位是s,默认是-1,代表没有超时时间。
事务的传播行为:控制业务方法是不是有事务的,是什么样的事务的。
- 事务的传播行为一共有7个(propagation_xxx):表示我们的业务方法在调用时,事务在方法之间是如何使用的。通过传播行为,我们能控制这个方法到底有没有事务,有什么样的事务。
propagation _required :指定的方法必须有事务。若存在事务,就加入到当前事务中,若没有事务就创建一个新事务。是spring中最常见的事务传播行为,也是默认的事务传播行为。
举例:
如果传播行为加在doOther()方法上。doSome()方法内调用doOther()方法。如果doSome()方法在调用doOther()方法时就是在事务内运行的,那么doOther()方法的执行也加入到已存在的该事务内执行。如果doSome()方法在调用doOther()方法时没有在事务内执行,那么doOther()方法会自己创建一个事务,并在这个新创建的事务中执行。
propagation _requires new :新事务。方法在执行时一定是新建一个事务,不用别人提供的事务。如果当前已经存在事务,就将当前事务挂起,知道新事务执行完毕。
propagation _supports :指定的方法支持当前事务,但是如果当前没有事务,也可以执行。就是说,有事务也可以,没事务也行。
propagation_mandatory 、propagation _nested 、propagation _never 、propagation _not _supported 。
(3)提交事务、回滚事务的时机
- 当业务方法执行成功,没有异常抛出,当方法执行完毕,Spring在方法执行后提交事务。事务管理器commit
- 当你的业务方法抛出运行时异常或者error,Spring执行回滚,调用事务管理器的rollback运行时异常的定义:RuntimeException和他的子类都是运行时异常,例如NullPointException、NumberFormatException
- 当你的业务方法抛出非运行时异常,主要是受查异常时,提交事务。受查异常的定义:在你写代码时,必须处理的异常,例如IOException和SQLException。
总结Spring的事务:
- 管理事务的是事务管理器及其实现类。
- Spring的事务是一个统一管理模型:
- 指定要使用的事务管理器的实现类,使用xml配置文件中的标签
- 指定哪些类,哪些方法需要加入事务的功能
- 指定方法需要的隔离级别,传播行为和超时时间
我们需要告诉Spring我们的项目中类信息,方法的名称,方法的事务传播行为。