事务回顾
事务的概念:
事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。
事务的特点:
- A原子性:要么都成功,要么都失败
- C一致性:使数据库从一个一致状态到另一个一致状态
- I隔离性:多线程、进程访问数据库的互相影响
- D持久性:事务一旦提交,则改变是持久的
事务并发访问的问题
- 脏读:指一个事务读取了另外一个事务未提交的数据。
- 不可重复读:一个事务重新读取了前一事务已经提交的数据
- 虚读:实质一个事务内读取到了别的事务插入的数据,导致前后读取不一致
事务的隔离等级
读未提交:Read uncommitted 不能防止脏读
读已经提交的:Read committed 可以防止脏读,但不能防止不可重复读
读可以重复读的:Repeatable read 可防止不可重复读,但不能防止虚读
序列化:Serializable 可避免脏读、不可重复读、虚读情况的发生,但效率低
Spring事务管理
Spring事务管理常用对象
- PlatformTransactionManager(平台事务管理器)
-
- 平台事务管理器,spring要管理事务,必须使用事务管理器;
进行事务配置时,必须配置事务管理器。
有多种实现,通过实现此接口,Spring可以管理任何实现了这些接口的事务。开发人员可以使用统一的编程模型来控制管理事务。
- 平台事务管理器,spring要管理事务,必须使用事务管理器;
-
- 常见的事务管理器的实现
DataSourceTransactionManager :jdbc开发时事务管理器,采用JdbcTemplate
HibernateTransactionManager:hibernate开发时事务管理器,整合hibernate
- 常见的事务管理器的实现
- TransactionDefinition(事务定义)
- TransactionStatus(事务状态)
PlatformTransactionManager api详解
TransactionStatus getTransaction(TransactionDefinition definition)
事务管理器 通过“事务详情”,获得“事务状态”,从而管理事务。 获取事务状态后,Spring根据传播行为来决定如何开启事务;
- void commit(TransactionStatus status) 根据状态提交
- void rollback(TransactionStatus status) 根据状态回滚
TransactionStatus
这个接口的作用就是获取事务的状态(回滚点、是否完成、是否新事物、是否回滚)属性
TransactionDefinition
这个接口的作用就是定义事务的名称、隔离级别、传播行为、超时时间长短、只读属性等。
- 常用定义
PROPAGATION_REQUIRED
支持现有的事务,如果没有则新建一个事务
PROPAGATION_REQUIRES_NEW
总是发起一个新事务。如果当前已存在一个事务,则将其挂起。
使用转账的案例作为 演示案例,去测试spring提供的事物解决方案是否可行。
#方法一
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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.bamzhy"></context:component-scan>
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbutils"/>
<property name="user" value="root"/>
<property name="password" value="12345"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
</beans>
- xml逻辑链:
datasource里边包含property,将datasource注入transactionManager,将transactionmanager注入transactiontemplate
(transactiontemplate包含transactionmanager)
service层实现:
@Service("service")
public class AccountService implements AccoutService {
@Autowired
AccoutDao dao;
@Autowired
TransactionTemplate transactionTemplate;
@Override
public void transafer(String from, String to, int money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
//保证doInTransactionWithoutResult方法里边的代码在事务里边
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//查询账户
Account fromAc = dao.queryAccount(from);
Account toAc = dao.queryAccount(to);
//业务计算
fromAc.setMoney(fromAc.getMoney() - money);
toAc.setMoney(toAc.getMoney() + money);
//更新账户
dao.updateAccount(fromAc);
//int i=1/0;
dao.updateAccount(toAc);
}
});
}
}
- 代码逻辑链:
在service层定义好dao层对象、transactiontemplate对象以及核心方法。
在核心方法里调用transactionTemplate.execute(new TransactionCallbackWithoutResult(){})方法并复写doInTransactionWithoutResult(TransactionStatus transactionStatus) ,并且在此方法中填入需要在事务中执行的代码。
执行时get service层的实例,强转为service类型并调用核心方法,即可完成了Spring下的事务管理。
值得一提的是dao层的class可以继承JdbcSupport并且复写一些方法。
@Repository
public class AccoutDaoImpl extends JdbcDaoSupport implements AccoutDao {
//构造方法
@Autowired
public AccoutDaoImpl(DataSource ds) {
this.setDataSource(ds);
}
@Override
public Account queryAccount(String name) {
//得到数据库中name=?的数据
List<Account> query = getJdbcTemplate().query("select * from account where name = ?",
new Object[]{name},
new BeanPropertyRowMapper<Account>(Account.class)
);
return query.get(0);
}
@Override
public boolean updateAccount(Account account) {
int update = getJdbcTemplate().update("update account set money= ? where name =?",
new Object[]{account.getMoney(), account.getName()});
return update==1?true:false;
}
}
#方法二
使用事务模板配置实现
原理:配置一个Service的代理类(TransactionProxyFactoryBean),去增强service的转账方法
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbutils"/>
<property name="user" value="root"/>
<property name="password" value="12345"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
<bean id="serviceproxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--这里是增强目标-->
<property name="target" ref="service"/>
<!--这里是目标实现类-->
<property name="proxyInterfaces" value="com.bamzhy.bean.service.AccoutService"/>
<!--这里是事务管理-->
<property name="transactionManager" ref="txManager"/>
<!--事务属性-->
<property name="transactionAttributes">
<!--具体属性-->
<props>
<prop key="transafer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
获取实例时使用getBean(servicepoxy)代理来完成
#方法三
通过Spring tx xml配置实现
xmlns:tx=”http://www.springframework.org/schema/tx”
xsi:schemaLocation=”http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd “
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<!--构建切面-->
<aop:config >
<aop:pointcut id="mypointcut"
expression="execution( * com.bamzhy.bean.service.impl.AccountService.*(..))"/>
<aop:advisor advice-ref="myadvice" pointcut-ref="mypointcut"/>
</aop:config>
<!--事物的增强的实现-->
<tx:advice id="myadvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transafer" isolation="REPEATABLE_READ" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
#方法四 通过Spring tx 注解实现
- xml文件中增加以下注解:
< tx:annotation-driven transaction-manager=”txManager”/>
< bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
< property name=”dataSource” ref=”datasource”>
< /bean>
< bean id=”datasource” class=”com.mchange.v2.c3p0.ComboPooledDataSource”>
< property name=”jdbcUrl” value=”jdbc:mysql://localhost:3306/dbutils”/>
< property name=”user” value=”root”/>
< property name=”password” value=”12345”/>
< property name=”driverClass” value=”com.mysql.jdbc.Driver”/>
< /bean> - 在service中配置事务注解:
@Transactional(isolation=Ioslation.DEFAULT,propagation=Propagation.REQUIRED)
// isolation隔离 propagation 传播
具体赋值可看之前的TransactionDefinition的两张图