相信大家面试都经常会被问到框架相关的,或者有没有用过事务?那么看篇文章就对了。
1.什么是事务
所谓事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。
说白了就是要么一起成功,要么一起失败。不存在一些成功一些失败。充分说明了事务的原子性。
举个现实中最通俗易懂的栗子

以上就是我们经常会通过银行的转账系统来转账。如果没有事务,别人本来需要转账给你1000的 结果别人的账户里扣了1000 但是你的账户还是之前的0,你肯定会不开森不会同意的吧。事务的重要性就体现出来了,银行既要保证别人的利益又要保证你的利益。所以理解和使用事务还是非常重要的。尤其是金融行业。
2.事务的特性(简称ACID):
原子性 (Atomicity) :要么全做,要么全不做。
一致性 (Consistency) :说的是全部做,和全不做,这时数据库处于一致性,如果一个做,一个不做,就认为不一致。
隔离性(Isolation) :一个事务的执行不能被其他事务干扰,即一个事务的内部操作以及使用的数据对其他并发事务是隔离的。
持续性 (Durability) :一个事务一旦提交,它对数据库中数据的改变就应该是永久行的。、
3.事务并发操带来哪些问题
3.1丢失修改
两个事务T1和T2读入同一个数据并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失。
3.2不可重复读
事务T1读取数据后,事务T2执行更新操作,使得T1无法再现前一次读到的结果。
3.3读脏数据
T1修改某一个数据并将其写回磁盘,事务T2读到T1修改之后的数据,这时T1由于某种原因被撤销,数据恢复到原来的值,T1读到的数据为脏数据。
3.4幻读
事务T1读取数据后,事务T2执行插入操作,T1再次读取,使T1出现了幻觉。
4.事务的API介绍
4.1 事务管理器PlatformTransactionManager
spring为不同的持久化框架提供了不同的PlatformTransactionManager

4.2 TransactionDefinition事务定义信息(隔离,传播,超时,只读)
4.2.1 隔离级别
设置隔离级别可防止并发导致的问题。

如果选择DEFAULT则是数据库默认的隔离级别。
MySQL 默认REPEATABLE_READ
Oracle默认 READ_COMMITTED
4.2.2 事务的传播行为

4.2.3 TransactionStatus事务具体运作状态
void flush();冲洗数据库底层会话
boolean hasSavePoint();返回该事务是否有一个保存点
boolean isCompleted();返回事务是否提交或者回滚
boolean isNewTransaction();返回是否是一个新事务
boolean isRollbackOnly();判断这个事务是否已经设置了rollback-only。
void setRollbackOnly();设置这个事务rollback-only。
4.2.4 SavepointManager
事务回滚点管理接口,提供创建、释放回滚点,或者回滚到指定的回滚点。
方法摘要:
Object createSavepoint()
Create a new savepoint.
创建一个新的回滚点。
void releaseSavepoint(Object savepoint)
Explicitly release the given savepoint.
释放一个给定的回滚点。
void rollbackToSavepoint(Object savepoint)
Roll back to the given savepoint.
回滚到给定的回滚点。
5.转账示例
5.1 编程式事务管理
5.1.1 创建数据库

5.1.2 Dao层
- public interface AccountDao {
-
-
-
-
-
-
- public void outMoney(String out,Double money);
-
-
-
-
-
-
- public void inMoney(String in,Double money);
- }
-
-
- public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
-
-
-
-
-
-
- @Override
- public void outMoney(String out, Double money) {
- String sql = "update account set money = money-? where name = ?";
- this.getJdbcTemplate().update(sql, money, out);
- }
-
-
-
-
-
-
- @Override
- public void inMoney(String in, Double money) {
- String sql = "update account set money = money+? where name = ?";
- this.getJdbcTemplate().update(sql,money,in);
- }
-
-
- }
5.1.3 Service层
- public interface AccountService {
-
-
-
-
-
-
-
- public void transfer(String out,String in,Double money);
- }
-
-
- public class AccountServiceImpl implements AccountService {
-
-
- private AccountDao accountDao;
-
-
-
- private TransactionTemplate transactionTemplate;
-
-
-
-
-
-
-
- @Override
- public void transfer(final String out, final String in, final Double money) {
-
-
-
-
-
- transactionTemplate.execute(new TransactionCallbackWithoutResult() {
-
-
- @Override
- protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
- accountDao.outMoney(out, money);
-
- accountDao.inMoney(in, money);
- }
- });
- }
-
-
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
-
-
- public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
- this.transactionTemplate = transactionTemplate;
- }
-
-
- }
5.1.4 xml配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
-
-
- <!-- 引入外部的属性文件 -->
- <context:property-placeholder location="classpath:jdbc.properties"/>
-
- <!-- 配置c3p0连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driverClass}" />
- <property name="jdbcUrl" value="${jdbc.url}" />
- <property name="user" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
-
- <!-- 配置业务层类 -->
- <bean id="accountService" class="com.zs.spring.demo1.AccountServiceImpl">
- <property name="accountDao" ref="accountDao" />
- <!-- 注入事务管理的模板 -->
- <property name="transactionTemplate" ref="transactionTemplate" />
- </bean>
-
- <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
- <bean id="accountDao" class="com.zs.spring.demo1.AccountDaoImpl">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- 配置DAO类(未简化) -->
- <!-- <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <bean id="accountDao" class="com.zs.spring.demo1.AccountDaoImpl">
- <property name="jdbcTemplate" ref="jdbcTemplate" />
- </bean> -->
-
- <!-- ==================================1.编程式的事务管理=============================================== -->
- <!-- 配置事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- 配置事务管理的模板:Spring为了简化事务管理的代码而提供的类 -->
- <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
- <property name="transactionManager" ref="transactionManager"/>
- </bean>
-
- </beans>
5.1.5 测试类
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext1.xml")
- public class TransactionTest {
-
-
- @Resource(name="accountService")
- private AccountService accountService;
-
- @Test
- public void demo1(){
- accountService.transfer("aaa", "bbb", 200d);
- }
- }
5.2 使用xml配置申明式事务管理
代码侵入性小,是通过spring aop 实现的。
5.2.1 使用XML配置声明式的事务管理(原始方式)
Service层的变化
- public class AccountServiceImpl implements AccountService {
-
-
- private AccountDao accountDao;
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
-
-
-
-
-
-
-
- @Override
- public void transfer( String out, String in, Double money) {
- accountDao.outMoney(out, money);
-
- accountDao.inMoney(in, money);
-
- }
-
- }
xml的变化
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
-
-
- <!-- 引入外部的属性文件 -->
- <context:property-placeholder location="classpath:jdbc.properties"/>
-
- <!-- 配置c3p0连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driverClass}" />
- <property name="jdbcUrl" value="${jdbc.url}" />
- <property name="user" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
-
- <!-- 配置业务层类 -->
- <bean id="accountService" class="com.zs.spring.demo2.AccountServiceImpl">
- <property name="accountDao" ref="accountDao" />
- </bean>
-
- <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
- <bean id="accountDao" class="com.zs.spring.demo2.AccountDaoImpl">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- ==================================2.使用XML配置声明式的事务管理(原始方式)=============================================== -->
-
- <!-- 配置事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- 配置业务层的代理 -->
- <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
- <!-- 配置目标对象 -->
- <property name="target" ref="accountService" />
- <!-- 注入事务管理器 -->
- <property name="transactionManager" ref="transactionManager"></property>
- <!-- 注入事务的属性 -->
- <property name="transactionAttributes">
- <props>
- <!--
- prop的格式:
- * PROPAGATION :事务的传播行为
- * ISOTATION :事务的隔离级别
- * readOnly :只读
- * -EXCEPTION :发生哪些异常回滚事务
- * +EXCEPTION :发生哪些异常不回滚事务
- -->
- <prop key="transfer">PROPAGATION_REQUIRED</prop>
- <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
- <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
- </props>
- </property>
- </bean>
-
-
- </beans>
test类的变化
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext2.xml")
- public class TransactionTest {
-
-
-
-
-
-
- @Resource(name="accountServiceProxy")
- private AccountService accountService;
-
- @Test
- public void demo1(){
- accountService.transfer("aaa", "bbb", 200d);
- }
- }
5.3 使用XML配置声明式的事务管理,基于tx/aop
5.3.1 xml配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
-
-
- <!-- 引入外部的属性文件 -->
- <context:property-placeholder location="classpath:jdbc.properties"/>
-
- <!-- 配置c3p0连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driverClass}" />
- <property name="jdbcUrl" value="${jdbc.url}" />
- <property name="user" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
-
- <!-- 配置业务层类 -->
- <bean id="accountService" class="com.zs.spring.demo3.AccountServiceImpl">
- <property name="accountDao" ref="accountDao" />
- </bean>
-
- <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
- <bean id="accountDao" class="com.zs.spring.demo3.AccountDaoImpl">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- ==================================3.使用XML配置声明式的事务管理,基于tx/aop=============================================== -->
-
- <!-- 配置事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- 配置事务的通知 -->
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <!--
- propagation :事务传播行为
- isolation :事务的隔离级别
- read-only :只读
- rollback-for:发生哪些异常回滚
- no-rollback-for:发生哪些异常不回滚
- timeout :过期信息
- -->
- <tx:method name="transfer" propagation="REQUIRED"/>
- </tx:attributes>
- </tx:advice>
-
- <!-- 配置切面 -->
- <aop:config>
- <!-- 配置切入点 -->
- <aop:pointcut expression="execution(* com.zs.spring.demo3.AccountService+.*(..))" id="pointcut1"/>
- <!-- 配置切面 -->
- <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
- </aop:config>
-
-
- </beans>
5.3.2 test的变化
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration("classpath:applicationContext3.xml")
- public class TransactionTest {
-
-
-
- @Resource(name="accountService")
- private AccountService accountService;
-
- @Test
- public void demo1(){
- accountService.transfer("aaa", "bbb", 200d);
- }
- }
5.4 事务注解的实现
5.4.1 xml配置
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:task="http://www.springframework.org/schema/task"
- xsi:schemaLocation="http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
- http:
-
-
- <!-- 引入外部的属性文件 -->
- <context:property-placeholder location="classpath:jdbc.properties"/>
-
- <!-- 配置c3p0连接池 -->
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
- <property name="driverClass" value="${jdbc.driverClass}" />
- <property name="jdbcUrl" value="${jdbc.url}" />
- <property name="user" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
-
- <!-- 配置业务层类 -->
- <bean id="accountService" class="com.zs.spring.demo4.AccountServiceImpl">
- <property name="accountDao" ref="accountDao" />
- </bean>
-
- <!-- 配置DAO类(简化,会自动配置JdbcTemplate) -->
- <bean id="accountDao" class="com.zs.spring.demo4.AccountDaoImpl">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- ==================================4.使用注解配置声明式事务============================================ -->
-
-
- <!-- 配置事务管理器 -->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
-
- <!-- 开启注解事务 -->
- <tx:annotation-driven transaction-manager="transactionManager"/>
-
- </beans>
5.4.2 Serverce
- *@Transactional(Propagation.REQUIRED)中的的属性
- *propagation :事务的传播行为
- *isolation :事务的隔离级别
- *readOnly :只读
- *rollbackFor :发生哪些异常回滚
- *noRollbackFor :发生哪些异常不回滚
- *rollbackForClassName 根据异常类名回滚
- */
- @Transactional
- public class AccountServiceImpl implements AccountService {
-
-
- private AccountDao accountDao;
-
-
-
-
-
-
-
-
- @Override
- public void transfer( String out, String in, Double money) {
- accountDao.outMoney(out, money);
-
- accountDao.inMoney(in, money);
-
- }
-
-
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
-
-
- }
- <pre code_snippet_id="2296147" snippet_file_name="singit" name="code" class="java"><pre code_snippet_id="2296147" snippet_file_name="singit"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
-
- </pre>
- <pre code_snippet_id="2296147" snippet_file_name="singit" name="code" class="java"><pre code_snippet_id="2296147" snippet_file_name="singit"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
-
- </pre>
- <pre code_snippet_id="2296147" snippet_file_name="singit" name="code" class="java"><pre code_snippet_id="2296147" snippet_file_name="singit"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
-
- </pre>
声明:本篇文章经http://www.imooc.com/learn/478整理而出。如有侵权请联系博主,谢谢。