模块名:spring6-013-tx-bank(依赖如下)
jar
junit
junit
4.12
test
org.springframework
spring-jdbc
6.0.0
org.springframework
spring-context
6.0.0
mysql
mysql-connector-java
8.0.31
com.alibaba
druid
1.2.13
jakarta.annotation
jakarta.annotation-api
2.1.1
第⼆步:创建包结构
第三步:准备POJO类
public class Account {
private String actno;
private Double balance;
public Account(){}
public Account(String actno, Double balance) {
this.actno = actno;
this.balance = balance;
}
//get,set,toString方法
}
/*
专门负责账户信息的CRUD操作
DAO中只执行SQL语句,没有任何业务逻辑
也就是说DAO不和业务挂钩。
*/
public interface AccountDao {
//根据账号查询信息
Account selectByActno(String actno);
//更新账户信息
int update(Account act);
}
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Override
public Account selectByActno(String actno) {
String sql = "select actno,balance from t_act where actno=?";
Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno);
return account;
}
@Override
public int update(Account act) {
String sql = "update t_act set balance=? where actno=?";
int count = jdbcTemplate.update(sql, act.getBalance(),act.getActno());
return count;
}
}
/*
* 业务接口
* 事物就是在这个接口下控制的
* */
public interface AccountService {
//转账业务方法
void transfer(String fromActno,String toActno,double money);
}
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
//控制事物,因为在这个方法中要完成所有的转账业务
@Override
public void transfer(String fromActno, String toActno, double money) {
//查询转出账户的余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance()
public class SpringTxTest {
@Test
public void testSpringTx(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
try{
accountService.transfer("act-001","act-002",10000);
System.out.println("转账成功");
}catch (Exception e){
e.printStackTrace();
}
}
}
@Service("accountService")
@Transactional
public class AccountServiceImpl implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
//控制事物,因为在这个方法中要完成所有的转账业务
@Override
//@Transactional
public void transfer(String fromActno, String toActno, double money) {
//第一步:开启事物
//第二步:执行核心业务逻辑
//查询转出账户的余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance()
数据库表中数据: 发现少了1W
@Service("accountService")
@Transactional
public class AccountServiceImpl implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
//控制事物,因为在这个方法中要完成所有的转账业务
@Override
//@Transactional
public void transfer(String fromActno, String toActno, double money) {
//第一步:开启事物
//第二步:执行核心业务逻辑
//查询转出账户的余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance()
@ Transactional ( propagation = Propagation . REQUIRED )
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
@Resource(name="accountServiceImpl2")
private AccountService accountService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void save(Account act) {
//这里调用dao的insert方法
accountDao.insert(act);//保存act-003账户
//创建账户对象
Account act2 = new Account("act-004",1000.0);
accountService.save(act2);//保存act-004账户
}
}
@Service("accountServiceImpl2")
public class AccountServiceImpl2 implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
@Override
public void transfer(String fromActno, String toActno, double money) {
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void save(Account act) {
accountDao.insert(act);
}
}
@Test
public void testPropagation(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//获取1号service对象
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
Account act =new Account("act-003",100.0);
accountService.save(act);
}
IsolationService1:
@Service("i1")
public class IsolationService1 {
@Resource(name="accountDao")
private AccountDao accountDao;
//负责查询
//当前事物可以读取到别的事物没有提交的数据
// @Transactional(isolation = Isolation.READ_UNCOMMITTED)
//对方事物提交之后的数据我才能读取到
@Transactional(isolation = Isolation.READ_COMMITTED)
public void getByActno(String actno){
Account account =accountDao.selectByActno(actno);
System.out.println("查询到的账户信息:"+account);
}
}
IsolationService2:
@Service("i2")
public class IsolationService2 {
@Resource(name="accountDao")
private AccountDao accountDao;
//负责插入
@Transactional
public void save(Account act){
accountDao.insert(act);
//睡眠一会
try {
Thread.sleep(1000*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Test
public void testIsolation1(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
IsolationService1 i1 = applicationContext.getBean("i1", IsolationService1.class);
i1.getByActno("act-005");
}
@Test
public void testIsolation2(){
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
IsolationService2 i2 = applicationContext.getBean("i2", IsolationService2.class);
Account act = new Account("act-005", 500.0);
i2.save(act);
}
@ Transactional ( timeout = 10 )
以下代码的超时不会被计⼊超时时间
@Service("i2")
public class IsolationService2 {
@Resource(name="accountDao")
private AccountDao accountDao;
//负责插入
@Transactional(timeout = 10)//设置事物超时时间为10
public void save(Account act){
accountDao.insert(act);*/
//睡眠一会
try {
Thread.sleep(1000*15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Service("i2")
public class IsolationService2 {
@Resource(name="accountDao")
private AccountDao accountDao;
//负责插入
@Transactional(timeout = 10)//设置事物超时时间为10
public void save(Account act){
//睡眠一会
try {
Thread.sleep(1000*15);
} catch (InterruptedException e) {
e.printStackTrace();
}
accountDao.insert(act);
}
}
@Transactional(readOnly = true)
@Transactional(rollbackFor = RuntimeException.class)
表示只有发⽣RuntimeException异常或该异常的⼦类异常才回滚。
设置哪些异常不回滚事务
@Transactional(noRollbackFor = NullPointerException.class)
表示发⽣NullPointerException或该异常的⼦类异常不回滚,其他异常则回滚。
@Configuration//代替spring.xml文件,在这个类当中完成配置
@ComponentScan("com.powernode.bank")//组件扫描
@EnableTransactionManagement//开启事物注解驱动器,开启事物注解。告诉Spring框架,采用注解的方式去控制事物
public class Spring6Config {
// Spring框架,看到这个@Bean注解后,会调用这个被标注的方法,这个方法的返回值是一个java对象,这个java对象会自动纳入IoC容器管理。
// 返回的对象就是Spring容器当中的一个Bean了。
// 并且这个bean的名字是:dataSource
@Bean(name = "dataSource")
public DruidDataSource getDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring6");
dataSource.setUsername("root");
dataSource.setPassword("r38153");
return dataSource;
}
@Bean(name="jdbcTemplate")
public JdbcTemplate getJdbcTemplate(DataSource dataSource){//Spring在调用这个方法的时候会自动给我们传递过来一个dataSource对象。
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean(name="txManager")
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager txManager = new DataSourceTransactionManager();
txManager.setDataSource(dataSource);
return txManager;
}
}
@Test
public void testNoXml(){
ApplicationContext applicationContext =new AnnotationConfigApplicationContext(Spring6Config.class);
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
try{
accountService.transfer("act-001","act-002",10000);
System.out.println("转账成功");
}catch (Exception e){
e.printStackTrace();
}
}
jar
org.springframework
spring-context
6.0.0
org.springframework
spring-jdbc
6.0.0
mysql
mysql-connector-java
8.0.31
junit
junit
4.12
test
com.alibaba
druid
1.2.13
jakarta.annotation
jakarta.annotation-api
2.1.1
org.springframework
spring-aspects
6.0.11
Account:
public class Account {
private String actno;
private Double balance;
public Account(){}
public Account(String actno, Double balance) {
this.actno = actno;
this.balance = balance;
}
//get.set,toString方法
}
AccountDao:
/*
专门负责账户信息的CRUD操作
DAO中只执行SQL语句,没有任何业务逻辑
也就是说DAO不和业务挂钩。
*/
public interface AccountDao {
//根据账号查询信息
Account selectByActno(String actno);
//更新账户信息
int update(Account act);
}
AccountDaoImpl:
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Resource(name="jdbcTemplate")
private JdbcTemplate jdbcTemplate;
@Override
public Account selectByActno(String actno) {
String sql = "select actno,balance from t_act where actno=?";
Account account = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Account.class), actno);
return account;
}
@Override
public int update(Account act) {
String sql = "update t_act set balance=? where actno=?";
int count = jdbcTemplate.update(sql, act.getBalance(),act.getActno());
return count;
}
}
AccountService:
/*
* 业务接口
* 事物就是在这个接口下控制的
* */
public interface AccountService {
//转账业务方法
void transfer(String fromActno,String toActno,double money);
}
AccountServiceImpl:
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource(name="accountDao")
private AccountDao accountDao;
//控制事物,因为在这个方法中要完成所有的转账业务
@Override
public void transfer(String fromActno, String toActno, double money) {
//第一步:开启事物
//第二步:执行核心业务逻辑
//查询转出账户的余额是否充足
Account fromAct = accountDao.selectByActno(fromActno);
if (fromAct.getBalance()
测试程序:
public class BankTxTest {
@Test
public void testNoAnnotation() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
try {
accountService.transfer("act-001", "act-002", 10000.0);
System.out.println("转账成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
jar
org.springframework
spring-context
6.0.0
junit
junit
4.12
test
org.springframework
spring-test
6.0.0
User:
@Component
public class User {
@Value("张三")
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(){
}
public User(String name) {
this.name = name;
}
}
spring.xml:
程序测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class SpringJUnit4Test {
@Autowired
private User user;
@Test
public void testUser2(){
System.out.println(user.getName());
}
@Test
public void testUser(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println(user.getName());
}
}
引⼊JUnit5的依赖,Spring对JUnit⽀持的依赖还是:spring-test,如下:
org.junit.jupiter
junit-jupiter
5.9.0
test
程序测试:
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:spring.xml")
public class SpringJUnit5Test {
@Autowired
private User user;
@Test
public void testUser(){
System.out.println(user.getName());
}
}