ConnectionUtils,
用于获取线程上的连接,使同一service上所有的dao方法公用一个connection发生异常时,可以回滚事务
TransactionManager,
用于管理service层上的方法,按照如下步骤:
1.开启事务
2.执行方法
3.提交事务
4.返回结果
5.回滚事务
6.释放资源
关系:
bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.c"></context:component-scan>
<!-- 配置数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/cjy"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="connectionUtil" class="com.c.utils.ConnectionUtil">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置accountService-->
<bean id="accountService" class="com.c.service.impl.AccountServiceImpl">
<property name="tm">
<bean class="com.c.utils.TransactionManager">
<property name="connectionUtil" ref="connectionUtil"/>
</bean>
</property>
</bean>
<!-- 配置accountDao-->
<bean id="accountDao" class="com.c.dao.impl.AccountDaoImpl">
<property name="queryRunner">
<bean class="org.apache.commons.dbutils.QueryRunner"></bean>
</property>
<property name="connectionUtil" ref="connectionUtil"/>
</bean>
</beans>
Account
package com.c.bean;
public class Account {
private Integer accountId;
private Integer userId;
private double money;
public Account() {
}
public Account(Integer accountId, Integer userId, double money) {
this.accountId = accountId;
this.userId = userId;
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"accountId=" + accountId +
", userId=" + userId +
", money=" + money +
'}';
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
AccountDaoImpl
package com.c.dao.impl;
import com.c.bean.Account;
import com.c.dao.AccountDao;
import com.c.utils.ConnectionUtil;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.springframework.stereotype.Repository;
import java.sql.SQLException;
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
private QueryRunner queryRunner;
private ConnectionUtil connectionUtil;//用于获取线程池上的连接,而不是每次自动获取
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
public void setConnectionUtil(ConnectionUtil connectionUtil) {
this.connectionUtil = connectionUtil;
}
public Account findAccount(Integer id1) throws SQLException {
return queryRunner.query(connectionUtil.getCurrentConnection(),"select * from account where accountId=?",new BeanHandler<Account>(Account.class),id1);
}
public void updateAccount(Account account1) throws SQLException {
queryRunner.update(connectionUtil.getCurrentConnection(),"update account set money=? where accountId =?",account1.getMoney(),account1.getAccountId());
}
}
AccountServiceImpl
package com.c.service.impl;
import com.c.bean.Account;
import com.c.dao.AccountDao;
import com.c.service.AccountService;
import com.c.utils.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.SQLException;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
private TransactionManager tm;
public void setTm(TransactionManager tm) {
this.tm = tm;
}
public void transferMoney(Integer id1, Integer id2) throws SQLException {
try {
//1.开启事务
tm.begin();
//2.执行方法
Account account1=accountDao.findAccount(id1);
Account account2=accountDao.findAccount(id2);
account1.setMoney(account1.getMoney()-100);
account2.setMoney(account2.getMoney()+100);
accountDao.updateAccount(account1);
int i=10/0;
accountDao.updateAccount(account2);
//3.提交事务
tm.commit();
//4.返回结果
System.out.println("转账成功");
} catch (SQLException e) {
//5.异常时回滚事务
tm.rollback();
e.printStackTrace();
} finally {
//6.释放资源
tm.release();
}
}
}
ConnectionUtil
package com.c.utils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* 用于获取线程池上的连接
*/
public class ConnectionUtil {
//定义用于绑定连接的线程
private ThreadLocal<Connection> threadLocal=new ThreadLocal<Connection>();
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Connection getCurrentConnection() throws SQLException {
//从线程中获取连接
Connection connection=threadLocal.get();
if(connection==null){
connection=dataSource.getConnection();
//在线程中存储新获得的连接
threadLocal.set(connection);
}
return connection;
}
//把连接和线程池解绑
public void remove(){
threadLocal.remove();
}
}
TransactionManager
package com.c.utils;
import java.sql.SQLException;
/**
* 用于配置service层的事务管理器
* 包括事务的开启,提交,回滚,释放资源
*/
public class TransactionManager {
private ConnectionUtil connectionUtil;
public void setConnectionUtil(ConnectionUtil connectionUtil) {
this.connectionUtil = connectionUtil;
}
//开启事务
public void begin() throws SQLException {
connectionUtil.getCurrentConnection().setAutoCommit(false);
}
//提交事务
public void commit() throws SQLException {
connectionUtil.getCurrentConnection().commit();
}
//回滚事务
public void rollback() throws SQLException {
connectionUtil.getCurrentConnection().rollback();
}
//释放资源
public void release() throws SQLException {
//关闭连接
connectionUtil.getCurrentConnection().close();
//把线程和连接解绑
connectionUtil.remove();
}
}