一、事务
事务防止进行操作时,数据库里面的数据丢失。
二、Spring事务注解方式
注解方式:在配置文件中配置事务管理器,利用注解,管理事务。
实例
银行转账:一个账户向另一个账户转账。
1)先在数据库mysql中建立,账户和余额表,并对其赋值:
2)在程序中创建一个完整的javabean程序(Account类),其属性和mysql表中属性一致:
package com.bank.pajo;public class Account {private String actno;private Double balance;@Overridepublic String toString() {return "Account{" +"actno='" + actno + '\'' +", balance=" + balance +'}';}public Account() {}public Account(String actno, Double balance) {this.actno = actno;this.balance = balance;}public String getActno() {return actno;}public void setActno(String actno) {this.actno = actno;}public Double getBalance() {return balance;}public void setBalance(Double balance) {this.balance = balance;}
}
2)引入依赖(pom.xml):
<packaging>jar</packaging>
<!--仓库--><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories>
<!--依赖--><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.0-M2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.0.0-M2</version></dependency><!-- mysql jar包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency>
<!--这是一个数据库连接池,在此可以配置数据源信息--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.13</version></dependency><dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency></dependencies>
3)创建一个接口(Acount),用于存放对数据库进行操作的语句方法,查看和更新:
package com.bank.dao;
import com.bank.pajo.Account;
//只执行sql语句
public interface Acount {//查询账户Account selectBy(String actno);//更新int update(Account acc);
}
4)这个接口的实现类(AcountImp),将查看和修改的功能实现利用sql语句和JdbcTemplate:
package com.bank.dao;
import com.bank.pajo.Account;
import jakarta.annotation.Resource;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class AcountImp implements Acount{@Resourceprivate JdbcTemplate j;@Overridepublic Account selectBy(String actno) {//查看账户String sql="select actno,balance from t_act where actno=?";Account a=j.queryForObject(sql,new BeanPropertyRowMapper<>(Account.class),actno);return a;}@Overridepublic int update(Account acc) {//更新余额String sql="update t_act set balance =? where actno=?";int count= j.update(sql,acc.getBalance(),acc.getActno());return count;}
}
5)定义一个转账接口(AcountSer):
package com.bank.service;
public interface AcountSer {void transfer(String fromActno,String toAcrno,double money);
}
6)这个接口的实现类,进行转账功能:
package com.bank.service;
import com.bank.dao.AcountImp;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bank.pajo.Account;
@Service
public class AccountService implements AcountSer{@Resourceprivate AcountImp acountImp;//从这个账户转到另个账户@Transactional//事务管理器@Overridepublic void transfer(String fromActno, String toAcrno, double money) {Account from= acountImp.selectBy(fromActno);//这个账户信息if(from.getBalance()<money){throw new RuntimeException("余额不足");}Account to=acountImp.selectBy(toAcrno);//另一个账户信息from.setBalance(from.getBalance()-money);//一个钱数加to.setBalance(to.getBalance()+money);//一个钱数减//数据库更新int count= acountImp.update(from);//模拟异常String s=null;s.toString();count+=acountImp.update(to);if(count<2){throw new RuntimeException("转账失败,请联系银行");}}
}
spring.xml:
<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:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--组件扫描--><context:component-scan base-package="com.bank"></context:component-scan>
<!-- 配置数据源--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/spring6"/><property name="username" value="root"/><property name="password" value="123456"></property></bean>
<!-- 配置JdbcTemplate--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
<!-- 配置事务管理器--><bean id="txMange" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"></property></bean>
<!-- 事务注解驱动器开启,开启事务--><tx:annotation-driven transaction-manager="txMange"></tx:annotation-driven>
</beans>
测试类:
public class Test {@org.junit.Testpublic void test(){ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");AcountSer a= applicationContext.getBean("accountService", AcountSer.class);try{a.transfer("act-001","act-002",10000);}catch (Exception e){System.out.println("转账失败");e.printStackTrace();}}
}
成功案例(无模拟异常):
失败案例(有模拟异常) :刷新数据库的两个余额都未改变。
三、事务传播行为
重点为:REQUIRED和REQUIRES_NEW。
REQUIRES_NEW:事务A和事务B隔离开,若事务B发生异常,应对事务A进行捕捉异常,事务A就不会回滚,若不捕捉,则事务A发生回滚,数据无法保存。