Spring—CRUD—添加事物管理2020.4.25笔记
1.前言
根据前几天学习Spring内容可以只,所有的配置都可以交给Spring进行管理,但是正是由于Spring 的管理我们可能会出现一些事物上面的问题
比如:银行的操作系统,当A给B转账100时,出现了一些问题,导致A的钱给了但是B没有收到
;
今天就是解决这个问题
Spring导入的依赖
(这个先不看,后面会说到,这个是为了我后面好复习)
例如转账
当其中操作失败了,那么就会导致转账失败,更严重会导致系统的奔溃
(仔细看下面的图)
因为每一个accountDao.findAccountByName(xxxx)都会获取一个新的连接
解决
把一个转账的业务层设置一个connection,当其中有错误时,直接返还
2.业务层service
业务层代码
业务层接口
package com.xiao.service;
import com.xiao.doamin.Account;
import java.util.List;
/**
* @_PackageName:com.xiao.sercvice
* @_ClassName:AccountService
* @_Description:
* @_Author:笑老二
* @_data 2020/4/27 22:33
*/
public interface AccountService {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 保存
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param acccountId
*/
void deleteAccount(Integer acccountId);
/**
*
* @param resourceName 转账人名字
* @param accName 转账人信息
* @param money 转账钱数
*/
void transfer(String resourceName,String accName,Double money);
}
业务层实现类
package com.xiao.service.impl;
import com.xiao.dao.AccountDao;
import com.xiao.doamin.Account;
import com.xiao.service.AccountService;
import com.xiao.utils.TransactionManger;
import java.util.List;
/**
* @_PackageName:com.xiao.sercvice.impl
* @_ClassName:AccountServiceImpl
* @_Description:
* @_Author:笑老二
* @_data 2020/4/27 22:33
*/
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
private TransactionManger txManger;
public void setTxManger(TransactionManger txManger) {
this.txManger = txManger;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public List<Account> findAllAccount() {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
List<Account> accounts = accountDao.findAllAccount();
//3.提交事务
txManger.commit();
//4.返回结果
return accounts;
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
public Account findAccountById(Integer accountId) {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
Account account = accountDao.findAccountById(accountId);
//3.提交事务
txManger.commit();
//4.返回结果
return account;
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
public void saveAccount(Account account) {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
accountDao.saveAccount(account);
//3.提交事务
txManger.commit();
//4.返回结果
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
public void updateAccount(Account account) {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
accountDao.updateAccount(account);
//3.提交事务
txManger.commit();
//4.返回结果
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
public void deleteAccount(Integer accountId) {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
accountDao.deleteAccount(accountId);
//3.提交事务
txManger.commit();
//4.返回结果
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
public void transfer(String resourceName, String accName, Double money) {
try {
//1.开启事物
txManger.beginTransaction();
//2.执行操作
Account resourceA = accountDao.findAccountByName(resourceName);
Account accA = accountDao.findAccountByName(accName);
resourceA.setMoney(resourceA.getMoney()-100d);
accA.setMoney(accA.getMoney()+100d);
accountDao.updateAccount(resourceA);
accountDao.updateAccount(accA);
//3.提交事务
txManger.commit();
//4.返回结果
}catch (Exception e){
//5.回滚操作
txManger.rollback();
throw new RuntimeException(e);
}finally {
//6.释放连接
txManger.release();
}
}
}
3.持久层dao
持久层接口
package com.xiao.dao;
import com.xiao.doamin.Account;
import java.util.List;
/**
* 账户的持久层接口
*/
public interface AccountDao {
/**
* 查询所有
* @return
*/
List<Account> findAllAccount();
/**
* 查询一个
* @return
*/
Account findAccountById(Integer accountId);
/**
* 保存
* @param account
*/
void saveAccount(Account account);
/**
* 更新
* @param account
*/
void updateAccount(Account account);
/**
* 删除
* @param acccountId
*/
void deleteAccount(Integer acccountId);
/**
* 根据名称查询账户
* @param accountName
* @return 如果有唯一的一个结果就返回,如果没有结果就返回null
* 如果结果集超过一个就抛异常
*/
Account findAccountByName(String accountName);
}
持久层实现类
package com.xiao.dao.impl;
import com.xiao.dao.AccountDao;
import com.xiao.doamin.Account;
import com.xiao.utils.ConnectionUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.util.List;
/**
* @_PackageName:com.xiao.dao.impl
* @_ClassName:AccountDaoImpl
* @_Description:
* @_Author:笑老二
* @_data 2020/4/27 22:34
*/
public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;
private ConnectionUtils connectionUtils;
//不希望连接从数据源中拿,那么直接可以控制它
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
public void setRunner(QueryRunner runner) {
this.runner = runner;
}
public List<Account> findAllAccount() {
try{
return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public Account findAccountById(Integer accountId) {
try{
return runner.query(connectionUtils.getThreadConnection(),"select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public void saveAccount(Account account) {
try{
runner.update(connectionUtils.getThreadConnection(),"insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public void updateAccount(Account account) {
try{
runner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public void deleteAccount(Integer accountId) {
try{
runner.update(connectionUtils.getThreadConnection(),"delete from account where id=?",accountId);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public Account findAccountByName(String accountName) {
try{
return runner.query(connectionUtils.getThreadConnection(),"select * from account where name = ?",new BeanHandler<Account>(Account.class),accountName);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
4.获取连接ConnectionUtils
package com.xiao.utils;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @_PackageName:com.xiao.utils
* @_ClassName:ConnectionUtils
* @_Description:
* @_Author:笑老二
* @_data 2020/4/28 19:36
*/
public class ConnectionUtils {
private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
public 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();
//4.把connection传入ThreadLocal中
tl.set(conn);
}
//5.返回当前线程上的连接
return conn;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 返回线程
*/
public void removeConnection(){
tl.remove();
}
}
5.事物管理TransactionManger
package com.xiao.utils;
import java.sql.SQLException;
/**
* @_PackageName:com.xiao.utils
* @_ClassName:TransactionManger
* @_Description:事物管理的相关类
* @_Author:笑老二
* @_data 2020/4/28 19:43
*/
public class TransactionManger {
private ConnectionUtils connectionUtils;
public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}
/**
* 开启事物
*/
public void beginTransaction(){
try {
connectionUtils.getThreadConnection().setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 提交事物
*/
public void commit(){
try {
connectionUtils.getThreadConnection().commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 回滚事物
*/
public void rollback(){
try {
connectionUtils.getThreadConnection().rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
/**
* 关闭事物
*/
public void release(){
try {
connectionUtils.getThreadConnection().close();
connectionUtils.removeConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置Service -->
<bean id="accountService" class="com.xiao.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
<!--注入事物管理器-->
<property name="txManger" ref="transactionManger"/>
</bean>
<!--配置Dao-->
<bean id="accountDao" class="com.xiao.dao.impl.AccountDaoImpl">
<property name="runner" ref="runner"/>
<!--注入connectionUtils-->
<property name="connectionUtils" ref="connectionUtils"/>
</bean>
<!--jdbcTemplate-->
<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"/>
<!--配置dataSource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy_spring_account"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<!--配合connectionUtils-->
<bean id="connectionUtils" class="com.xiao.utils.ConnectionUtils">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事物管理器-->
<bean id="transactionManger" class="com.xiao.utils.TransactionManger">
<property name="connectionUtils" ref="connectionUtils"/>
</bean>
</beans>