Dynamic agent realizes transaction configuration

build database

CREATE TABLE springaccount(
	id INT(11) NOT NULL AUTO_INCREMENT,
	NAME VARCHAR(32) NOT NULL,
	ACCOUNT DOUBLE NOT NULL,
	PRIMARY KEY (id)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

Import dependent jar package

<packaging>jar</packaging>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-dbutils</groupId>
        <artifactId>commons-dbutils</artifactId>
        <version>1.7</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
</dependencies>

Create entity class

public class Account implements Serializable {
    
    
    private Integer id;
    private String name;
    private double account;

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public double getAccount() {
    
    
        return account;
    }

    public void setAccount(double account) {
    
    
        this.account = account;
    }

    @Override
    public String toString() {
    
    
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", account=" + account +
                '}';
    }
}

Writing tools

  1. Write a connection tool class
    It is used to obtain a connection from the data source and realize the binding with the thread
public class ConnectionUtils {
    
    

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

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
    
    
        this.dataSource = dataSource;
    }

    /**
     * 获取当前线程上的连接
     * @return
     */
    public Connection getThreadConnection() {
    
    
        try{
    
    
            //1.先从ThreadLocal上获取
            Connection conn = tl.get();
            //2.判断当前线程上是否有连接
            if (conn == null) {
    
    
                //3.从数据源中获取一个连接,并且存入ThreadLocal中
                conn = dataSource.getConnection();
                tl.set(conn);
            }
            //4.返回当前线程上的连接
            return conn;
        }catch (Exception e){
    
    
            throw new RuntimeException(e);
        }
    }

    /**
     * 把连接和线程解绑
     */
    public void removeConnection(){
    
    
        tl.remove();
    }
}
  1. Compile and transaction management related tools to
    open the transaction, commit the transaction, roll back the transaction, release the connection
public class TransactionManager {
    
    

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
    
    
        this.connectionUtils = connectionUtils;
    }

    public void beginTransaction(){
    
    
        try{
    
    
            connectionUtils.getThreadConnection().setAutoCommit(false);
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }
    public void commit(){
    
    
        try{
    
    
            connectionUtils.getThreadConnection().commit();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }
    public void rollback(){
    
    
        try{
    
    
            connectionUtils.getThreadConnection().rollback();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }
    public void release(){
    
    
        try{
    
    
            connectionUtils.getThreadConnection().close();
            connectionUtils.removeConnection();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }
}

Create Service Agent Factory

public class BeanFactory {
    
    

    private AccountService accountService;

    private TransactionManager txManager;

    public void setAccountService(AccountService accountService) {
    
    
        this.accountService = accountService;
    }

    public final void setTxManager(TransactionManager txManager) {
    
    
        this.txManager = txManager;
    }

    public AccountService getAccountService() {
    
    
        return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(),
                accountService.getClass().getInterfaces(),
                new InvocationHandler() {
    
    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
    
                        Object rtValue = null;
                        try {
    
    
                            //1.开启事务
                            txManager.beginTransaction();
                            //2.执行操作
                            rtValue = method.invoke(accountService, args);
                            //3.提交事务
                            txManager.commit();
                            //4.返回结果
                            return rtValue;
                        } catch (Exception e) {
    
    
                            //5.回滚操作
                            txManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
    
    
                            //6.释放连接
                            txManager.release();
                        }
                    }
                });
    }
}

Business Layer

public class AccountServiceImp implements AccountService {
    
    

    private AccountDao accountDao;


    public void setAccountDao(AccountDao accountDao) {
    
    
        this.accountDao = accountDao;
    }

    public void transfer(String sourceName, String targetName, float money) {
    
    
        Account sourceAccount = accountDao.findAccountByName(sourceName);
        Account targetAccount = accountDao.findAccountByName(targetName);
        sourceAccount.setAccount(sourceAccount.getAccount() - money);
        targetAccount.setAccount(targetAccount.getAccount() + money);
        accountDao.updateAccount(sourceAccount);
//        int a = 3 /0;
        accountDao.updateAccount(targetAccount);
    }
}

Persistence layer

public class AccountDaoImp implements AccountDao {
    
    

    private QueryRunner queryRunner;

    private ConnectionUtils connectionUtils;

    public void setQueryRunner(QueryRunner queryRunner) {
    
    
        this.queryRunner = queryRunner;
    }

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
    
    
        this.connectionUtils = connectionUtils;
    }

    public Account findAccountByName(String name) {
    
    
        try {
    
    
            List<Account> accounts = queryRunner.query(connectionUtils.getThreadConnection(),"select * from springaccount where name=?", new BeanListHandler<>(Account.class),name);
            if (accounts == null || accounts.size() == 0){
    
    
                return null;
            }
            if (accounts.size() > 1){
    
    
                throw new RuntimeException("结果不唯一,数据有问题");
            }
            return accounts.get(0);
        }catch (Exception e){
    
    
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateAccount(Account account) {
    
    
        try {
    
    
            queryRunner.update(connectionUtils.getThreadConnection(), "update springaccount set name=? ,account=? where id=?",account.getName(),account.getAccount(),account.getId());
        }catch (Exception e){
    
    
            throw new RuntimeException(e);
        }
    }
}

testing method

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTset {
    
    

    @Autowired
    @Qualifier(("proxyAccountService"))
    private AccountService accountService;
    @Test
    public void testFindAllUsers(){
    
    

        accountService.transfer("张三","李四",100);

    }
}

Configuration xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--配置代理的Service -->
    <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean>
    <!--配置beanFactory -->
    <bean id="beanFactory" class="com.whut.factory.BeanFactory">
        <!-- 注入Service-->
        <property name="accountService" ref="accountService"></property>
        <!-- 注入事务管理器-->
        <property name="txManager" ref="txManager"></property>
    </bean>
    <!--配置service-->
    <bean id="accountService" class="com.whut.service.imp.AccountServiceImp">
        <!-- 注入Dao-->
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置Dao对象-->
    <bean id="accountDao" class="com.whut.dao.imp.AccountDaoImp">
        <!--注入QueryRunner-->
        <property name="queryRunner" ref="queryRunner"></property>
        <!--注入ConnectionUtils -->
        <property name="connectionUtils" ref="connectionUtils"></property>

    </bean>

    <!--配置QueryRunner-->
    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean>

    <bean id="txManager" class="com.whut.utils.TransactionManager">
        <!--注入ConnectionUtils -->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>
    <bean id="connectionUtils" class="com.whut.utils.ConnectionUtils">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库必备信息-->
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/my_db?serverTimezone=UTC"/>
        <property name="user" value="root"/>
        <property name="password" value="fy123"/>
    </bean>
</beans>

Guess you like

Origin blog.csdn.net/qq_40857365/article/details/112317424