spring事务全注解开发

对于 @Transactional 注解,Spring 会根据目标对象是否实现了接口来决定使用哪种代理方式。如果目标对象实现了接口,Spring 会使用 JDK 动态代理;否则,它会使用 CGLIB 代理。
因此,@Transactional 注解的实现并不完全基于 JDK 接口代理,它还支持基于类的代理(通过 CGLIB)。具体使用哪种代理方式取决于目标对象是否实现了接口。

  • 引用的包
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>6.1.8</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.17</version>
        </dependency>

        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>
  • 定义接口
package com.powernode.bank.dao;


import com.powernode.bank.pojo.Account;

public interface AccountDao {
    //根据账号查询账户信息
    Account selectByActno(String actno);

    //更新账户信息
    int update(Account act);

    //保存账户信息
    int insert(Account act);
}
  • 定义接口实现类
package com.powernode.bank.dao.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.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 AccountDaoImpl implements AccountDao {

    @Resource
    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);
        System.out.println("笑"+account);
        return account;

    }

    @Override
    public int update(Account act) {
        String sql = "update t_act set balance = ? where actno = ?";
        int update = jdbcTemplate.update(sql, act.getBalance(), act.getActno());
        return update;
    }

    @Override
    public int insert(Account act) {
        String sql = "insert into t_act values(?,?)";
        return jdbcTemplate.update(sql,act.getActno(),act.getBalance());

    }
}
  • 实体类
package com.powernode.bank.pojo;

public class Account {
    private String actno;
    private Double 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;
    }

    @Override
    public String toString() {
        return "Account{" +
                "actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}
  • 定义Service
package com.powernode.bank.service;

import com.powernode.bank.pojo.Account;

public interface AccountService {
    void transfer(String fromActno, String toActno, double money);

    void save(Account act);
}
  • 定义Service实现类
package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;

@Service
public class AccountServiceImpl implements AccountService {
    @Resource
    private AccountDao accountDao;

    //控制事务
    @Override
    @Transactional
    public void transfer(String fromActno, String toActno, double money) {
        //查询余额
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money){
            throw new RuntimeException("余额不足!!");
        }
        //余额充足
        Account toAct = accountDao.selectByActno(toActno);
        //将内存中两个对象的余额先修改
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);

        //数据库更新
        int count = accountDao.update(fromAct);

        //模拟异常
       /* String s = null;
        s.toString();*/

        count += accountDao.update(toAct);



        if (count !=2){
            throw new RuntimeException("转账失败,联系银行");
        }
    }

    @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);
        try{
            accountService.save(act2); //保存act-004账户
        }catch (Exception e){

        }

    }
}
  • 编辑注解配置类
package com.powernode.bank.service;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import javax.xml.crypto.Data;


@Configuration
@ComponentScan(value = {"com.powernode.bank"})
@EnableTransactionManagement //开启事务注解
public class Spring6Config {

    //
    @Bean(name = {"druidDataSource2"})
    public DruidDataSource getDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://192.168.1.41:3306/test");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("Abc123***");
        return druidDataSource;
    }

    @Bean(name = "jdbcTemplate")
    //spring在调用这个方法时会自动传递过来druidDataSource对象
    public JdbcTemplate getJdbcTemplate(DataSource druidDataSource2){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(druidDataSource2);
        return jdbcTemplate;
    }

    @Bean(name = "txManager")
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource druidDataSource2){
        DataSourceTransactionManager txManager = new DataSourceTransactionManager();
        txManager.setDataSource(druidDataSource2);
        return txManager;
    }

}
  • 测试,此处没有用service中的save方法
@Test
    public void testNoXML(){
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Spring6Config.class);
        AccountService accountServiceImpl = annotationConfigApplicationContext.getBean("accountServiceImpl", AccountService.class);
        accountServiceImpl.transfer("act-001","act-002",10000);
        System.out.println("转账成功");
    }
posted @ 2024-06-19 18:31  文采杰出  阅读(26)  评论(0)    收藏  举报