spring基于注解开发实现自定义的事务支持

spring基于注解开发实现自定义的事务支持

1、定义一个管理连接的类ConnectionUtil,实现事务的核心思想就是使用ThreadLocal对象把Connection对象和当前线程绑定,从而使一个线程中只有一个能控制事务的对象。(事务是由Connection进行控制的)

package com.wy.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;

@Component
public class ConnectionUtil {

    private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    @Autowired
    private DataSource dataSource;


    /**
     * 获取当前线程上的连接(实现当前线程和Conection的绑定)
     *
     * @return
     */
    public Connection getThreadConn() {
        try {
            //1、从ThreadLocal上获取
            Connection conn = tl.get();
            //2.判断当前线程上是否有连接
            if (conn == null) {
                //1、从ThreadLocal上获取
                conn = dataSource.getConnection();
                //2、将连接绑定到当前线程上
                tl.set(conn);
            }
            return conn;
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }
    /**
     * 将线程和数据库的连接解绑
     */
    public void removeConn(){
        tl.remove();
    }
}

2、定义一个事务管理器,用于管理Connection的事务操作(该Connection是与当前线程绑定的connection)

package com.wy.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.SQLException;

/**
 * 事务管理器
 */
@Component("tx")
public class TransactionManager {

    @Autowired
    private ConnectionUtil connectionUtil;
    /**
     * 开启事务
     */
    public void beginTransaction() throws SQLException {
        connectionUtil.getThreadConn().setAutoCommit(false);
    }


    /**
     * 提交事务
     */
    public void commitTransaction() throws SQLException {
        connectionUtil.getThreadConn().commit();
    }


    /**
     * 回滚事务
     */
    public void rollbackTransaction() throws SQLException {
        connectionUtil.getThreadConn().rollback();
    }


    /**
     * 关闭事务
     * 细节:由于使用了数据库连接池,其实质就是将池中的线程与数据库的连接进行绑定
     * ***所以使用关闭事务的时候需要将线程和连接解绑
     */
    public void releaseTransaction() throws SQLException {
        //关闭连接
        connectionUtil.getThreadConn().close();

        //线程和连接解绑
        connectionUtil.removeConn();
    }
}

3、逻辑代码的实现

3.1配置类,用于spring在容器中创建数据源和queryRunner

package com.wy.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.sql.SQLException;

@Configuration
@ComponentScan({"com.wy"})
@PropertySource({"classpath:JdbcConfig.properties"})
public class AppConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource getDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * 当我不向queryRunner传入dataSource时,是支持事务的
     * 而传入时则事务失败
     * @param
     * @return
     */
    @Bean
    public QueryRunner getRunner()  {
        return new QueryRunner();
    }

    /**
     * 无论是否为QueryRunner注入数据源都可以,但是在实现CRUD的时候必须使用QunerryRuner带
     * Connection的方法,保证一个线程只能绑定一个connection,否则事务失败
     *
     */

//    @Bean
//    public QueryRunner getRunner(DataSource dataSource)  {
//        System.out.println("config  >>>>"+dataSource.hashCode());
//        return new QueryRunner(dataSource);
//    }

}

3.2 Dao的实现类

package com.wy.dao;

import com.wy.bean.Account;
import com.wy.util.ConnectionUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.sql.SQLException;
import java.util.List;

@Repository
public class AccountDao {

    @Autowired
    private QueryRunner queryRunner;

    @Autowired
    ConnectionUtil connectionUtil;


    /**
     * 查所有
     *
     * @return
     * @throws SQLException
     */
    public List<Account> findAll() throws SQLException {
        //注意:一定要使用ConnectionUtil中与线程绑定的Connection
        return queryRunner.query(connectionUtil.getThreadConn(),"select * from account",
                new BeanListHandler<Account>(Account.class));
    }

    /**
     * 根据id查
     *
     * @param id
     * @return
     */
    public Account findById(int id) throws SQLException {

        return queryRunner.query(connectionUtil.getThreadConn(),"select * from account where id = ?",
                new BeanHandler<Account>(Account.class), id);

    }


    /**
     * 保存
     *
     * @param account
     * @return
     */
    public int save(Account account) throws SQLException {

        return queryRunner.update(connectionUtil.getThreadConn(),"insert into account(accountname,money) values(?,?)",
                account.getAccountName(), account.getMoney());
    }

    /**
     * 修改
     *
     * @param account
     * @return
     */
    public int update(Account account) throws SQLException {
        return queryRunner.update(connectionUtil.getThreadConn(),"update account set accountname = ?,money = ? where id = ?",
                account.getAccountName(), account.getMoney(), account.getId());
    }

    /**
     * 删除
     * @param id
     * @return
     */
    public int delete(int id) throws SQLException {
        return queryRunner.update(connectionUtil.getThreadConn(),"delete from account where id = ?", id);
    }

}

3.3 Service的实现类,加入了事务的控制

package com.wy.service;

import com.wy.bean.Account;
import com.wy.dao.AccountDao;
import com.wy.util.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.List;

/**
 * 保证事务原子性操作的前提条件是:只有一个connection对象实现所有的CRUD工作。
 *
 * 所以,保证了一个操作中connection的单例就能保证事务的原子性
 * 可以使用ThreadLocal 对象把connection对象和当前线程绑定
 */
@Service
public class AccountService {

    @Autowired
    @Qualifier("tx")
    TransactionManager txManager;
    @Autowired
    AccountDao accountDao;

    public int save(Account account) throws SQLException {
        try{
            //1、开启事务
            txManager.beginTransaction();
            //2、执行操作

            int save = accountDao.save(account);
            //3、提交事务
            txManager.commitTransaction();

            //4、返回结果
            return save;
        }catch (Exception e){
            //5、事务回滚
            txManager.rollbackTransaction();
            throw new RuntimeException();
        }finally {
            //6、释放资源
            txManager.releaseTransaction();
        }

    }


    public int update(Account account) throws SQLException {
        try{
            //1、开启事务
            txManager.beginTransaction();
            //2、执行操作
            int update = accountDao.update(account);
            //添加异常测试是否能够控制事务
            int i = 1/0;
            //3、提交事务
            txManager.commitTransaction();
            //4、返回结果
            return update;
        }catch (Exception e){
            //5、事务回滚
            txManager.rollbackTransaction();
            throw new RuntimeException();
        }finally {
            //6、释放资源
            txManager.releaseTransaction();
        }
    }

    public int delete(int id) throws SQLException {
        try{
            //1、开启事务
            txManager.beginTransaction();
            //2、执行操作
            int update = accountDao.delete(id);
            //3、提交事务
            txManager.commitTransaction();
            //4、返回结果
            return update;
        }catch (Exception e){
            //5、事务回滚
            txManager.rollbackTransaction();
            throw new RuntimeException();
        }finally {
            //6、释放资源
            txManager.releaseTransaction();
        }

    }

    public List<Account>findAll() throws SQLException {
        try{
            //1、开启事务
            txManager.beginTransaction();
            List<Account> ls =  accountDao.findAll();
            
//            int i = 1/0;
            //3、提交事务
            txManager.commitTransaction();
            //4、返回结果
            return ls;
        }catch (Exception e){
            //5、事务回滚
            txManager.rollbackTransaction();
            throw new RuntimeException();
        }finally {
            //6、释放资源
            txManager.releaseTransaction();
        }
    }

    public Account findById(int id) throws SQLException {
        try{

            Account account =  accountDao.findById(id);
            //3、提交事务
            txManager.commitTransaction();
            //4、返回结果
            return account;
        }catch (Exception e){
            //5、事务回滚
            txManager.rollbackTransaction();
            throw new RuntimeException();
        }finally {
            //6、释放资源
            txManager.releaseTransaction();
        }
    }
}

3.4 测试类

package com.wy;

import com.wy.bean.Account;
import com.wy.config.AppConfiguration;
import com.wy.service.AccountService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.sql.SQLException;
import java.util.Iterator;

public class AccountTest {

    AnnotationConfigApplicationContext ctx;
    AccountService accountService;

    //初始化spring容器
    @Before
    public void before(){
        ctx = new AnnotationConfigApplicationContext(AppConfiguration.class);
        accountService = ctx.getBean(AccountService.class);
    }


    @Test
    public void fun1() throws SQLException {
        Iterator<Account> iterator = accountService.findAll().iterator();
        while(iterator.hasNext())
            System.out.println(iterator.next());
    }

    @Test
    public void fun2() throws SQLException {
        Account account = new Account(3,"王二麻子", 0);
        accountService.update(account);

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 是一个开源的 Java 开发框架,它简化了基于 Spring 框架的应用程序的开发过程。在 Spring Boot 中,通过使用简单的注解和配置,可以实现对数据库的增删改查操作。同时,Spring Boot 还提供了自定义事务管理器的功能。 在 Spring Boot 中实现增删改查操作十分简便。首先,在实体类中使用注解来声明表名和字段名。然后,使用 Spring Data JPA 或 MyBatis 等持久化框架,通过定义接口来定义增删改查的方法。在这些方法上使用注解来标识方法的功能,如 @Query、@Insert、@Update、@Delete 等。最后,通过在适当的地方调用这些方法,即可实现对数据库的增删改查操作。 自定义事务管理器是 Spring Boot 的一个重要特性。在一些特殊的业务场景中,可能需要对事务进行额外的控制,例如需要在一个事务中执行多个数据库操作。在这种情况下,可以使用自定义事务管理器来满足需求。自定义事务管理器需要定义一个实现了 PlatformTransactionManager 接口的类,并重写其中的方法。在方法中,可以编写与事务相关的代码,如事务的开始、提交和回滚等。然后,在需要进行事务管理的方法或类上使用 @Transactional 注解来指定自定义事务管理器。通过这种方式,可以实现事务自定义管理。 总结来说,Spring Boot 提供了简便的方式来实现对数据库的增删改查操作,并且支持自定义事务管理器。通过合理运用这些功能,可以提高开发效率和灵活性,满足各种业务需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值