Spring的事务管理
事务:是数据库中的概念,在Dao层。一般情况需要将事务提升到业务层,为了能够使用事物的特性来管理具体的业务;
事务的隔离级别:
-
读未提交(read-uncommit):由于一个事务在对数据进行修改但未提交时,另一个事务读取到修改后的数据但因为一些原因修改数据的事务回滚了,出现了脏读;
-
读已提交(read-commited):解决了脏读的问题,但会出现虚读,当一个事务在查询数据的时候,另一个修改数据的事务刚好提交,再次查询时,两次数据不一致;
-
可重复读(repeatable-read mysql默认):解决了虚读的问题,但会出现幻读,例如当一个事务查询一次数据,在这时另一个事务插入了几条数据,当再次查询时出现了几条之前没有的数据;
-
串行化(Serializable):解决了幻读的问题,最高的隔离级别,通过强制事务排序,使之不可能相互冲突,从而解决幻读问题;
事务的四大特性: -
原子性:不可分割,要不一起成功,要不失败;
-
一致性:事务的前后数据要保持一致;
-
持久性:只要提交就会将数据持久化到数据库;
-
隔离性:没有隔离性的会发生一些读取问题,会出现脏读、幻读、不可重复读、虚读;
Spring事务管理API
事务管理器是PlatFormTransactionManager接口对象,主要用于完成事务的提交、回滚、及获取事务的状态信息。
常用的两个实现类:
DataSourceTransactionManager:使用JDBC或MyBatis进行持久化数据时使用;
HibernateTransactionManager:使用Hibernate进行持久化数据时使用;
Spring事务的默认回滚方式是:发生运行时异常回滚,发生检查时异常提交;
事务定义接口TransactionDefinition定义了事务描述相关的三类常量:
事务隔离级别:isolation(5)
事务传播行为:propagation(7)最常见的是REQUIRED;
事务默认超时时限:timeout
这里举的例子是银行与基金的关系,例:用农业银行账户买入基金
配置式
1.写相关的实现类
```
public class Account {
private int aid;
private String aname;
private double balance;
public int getAid() {
return aid;
}
public void setAid(int aid) {
this.aid = aid;
}
public String getAname() {
return aname;
}public void setAname(String aname) { this.aname = aname; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } @Override public String toString() { return "Account{" + "aid=" + aid + ", aname='" + aname + '\'' + ", balance=" + balance + '}'; } } ``` ``` public class Fund { private int fid; private String fname; private int amount; public int getFid() { return fid; } public void setFid(int fid) { this.fid = fid; } public String getFname() { return fname; } public void setFname(String fname) { this.fname = fname; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } @Override public String toString() { return "Fund{" + "fid=" + fid + ", fname='" + fname + '\'' + ", amount=" + amount + '}'; } } ``` 2.service的实现类(转账异常时用事务回滚) ``` public class FundServiceImpl implements FundService { private AccountDao accountDao; private FundDao fundDao; public AccountDao getAccountDao() { return accountDao; } public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public FundDao getFundDao() { return fundDao; } public void setFundDao(FundDao fundDao) { this.fundDao = fundDao; } @Override public void buyFund(Account account, Fund fund) throws FundException { accountDao.updateAccount(account); if(1==1){ throw new FundException("出现异常请联系客服!"); } fundDao.updateFund(fund); } } ``` 3.持久层就是进行更新操作,在这不进行介绍 4.配置文件spring.xml 加载jdbc配置文件 (如果是web项目的话location=“classpath:jbdc.properties”),这是一个Jav ``` <context:property-placeholder location="jdbc.properties"></context:property-placeholder> ``` 注册数据源(默认的数据源是:DriverManagerDataSource 另外两个是BasicDataSource、ComboPooledDataSource) ``` <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> ``` 注册相应的Dao、Service ``` <!--注册Dao--> <bean id="fundDaoImpl" class="com.hxh.mapper.impl.FundDaoImpl"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="accountDaoImple" class="com.hxh.mapper.impl.AccountDaoImple"> <property name="dataSource" ref="dataSource"></property> </bean> <!--注册service--> <bean id="fundServiceImpl" class="com.hxh.service.impl.FundServiceImpl"> <property name="accountDao" ref="accountDaoImple"></property> <property name="fundDao" ref="fundDaoImpl"></property> </bean> ```
注册事物管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> ``` 注册事物通知
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="buyFund" isolation="DEFAULT" propagation="REQUIRED" rollback-for="FundException"/> </tx:attributes> </tx:advice> ``` AOP配置
<aop:config> <aop:pointcut id="fundPc" expression="execution(* *..service.*.buyFund())"></aop:pointcut> <aop:advisor advice-ref="txAdvice" pointcut-ref="fundPc"></aop:advisor> </aop:config>
**注解式** 将配置文件中注册事物注解驱动(事务通知不用) ``` <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> ``` 在事务方法之前添加注释 ``` @Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED,rollbackFor = FundException.class) @Override public void buyFund(Account account, Fund fund) throws FundException { accountDao.updateAccount(account); if(1==1){ throw new FundException("出现异常请联系客服!"); } fundDao.updateFund(fund); } ```