spring JDBC 事务管理

spring JDBC 事务管理

spring JDBC 环境

添加依赖

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>spring</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>spring</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
<!--    单元测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
<!--    spring框架-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.16</version>
    </dependency>
<!--    spingTest-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.3.16</version>
    </dependency>
<!--    aop-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.9</version>
    </dependency>
<!--    jdbc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.3.16</version>
    </dependency>
<!--    mysql-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.19</version>
    </dependency>
<!-- c3p0 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>

  </dependencies>

  <build>

  </build>
</project>

在resources下配置jdbc 环境

spring.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/contex" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
         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"
>

    <!-- bean definitions here -->

    <context:component-scan base-package="org.example"/>

    <aop:aspectj-autoproxy/>

<!--    jdbc配置文件加载-->
    <context:property-placeholder location="jdbc.properties"/>

<!--    c3p0 数据源配置-->

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
<!--    jdbcTemplate 模板对象 注入数据源-->
   <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
         <property name="dataSource" ref="dataSource"/>

   </bean>

</beans>
jdbc.properties
#mysql???  
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/数据库名字?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
#??????  
jdbc.username=root
#?????  
jdbc.password=password

数据库

CREATE TABLE `tb_account`  (
  `account_id` int NOT NULL AUTO_INCREMENT,
  `account_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `account_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `money` double(11, 2) NOT NULL,
  `remark` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `create_time` datetime NOT NULL,
  `updata_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  `user_id` int NOT NULL,
  PRIMARY KEY (`account_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of tb_account
-- ----------------------------
INSERT INTO `tb_account` VALUES (1, '账户1', '建设银行', 1000.00, '零花钱', '2022-03-31 00:02:48', '2022-03-31 00:02:54', 1);
INSERT INTO `tb_account` VALUES (2, '账户2', '工商银行', 10000.00, '奖金', '2022-03-31 00:04:40', '2022-03-31 00:04:43', 1);

SET FOREIGN_KEY_CHECKS = 1;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hi6pWbip-1649157590573)(C:\Users\19869\AppData\Roaming\Typora\typora-user-images\image-20220405152528395.png)]

实体类

package org.example.domain;

import java.util.Date;

public class Account {
    private Integer accountId;
    private String accountName;
    private String accountType;
    private Double money;
    private String remark;
    private Date createTime;
    private Date updateTime;
    private Integer userid;

    public Account() {
    }

    public Account( String accountName, String accountType, Double money, String remark, Integer userid) {
        this.accountName = accountName;
        this.accountType = accountType;
        this.money = money;
        this.remark = remark;
        this.userid = userid;
    }

    public Integer getAccountId() {
        return accountId;
    }

    public void setAccountId(Integer accountId) {
        this.accountId = accountId;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getAccountType() {
        return accountType;
    }

    public void setAccountType(String accountType) {
        this.accountType = accountType;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }

    @Override
    public String toString() {
        return "Account{" +
                "accountId=" + accountId +
                ", accountName='" + accountName + '\'' +
                ", accountType='" + accountType + '\'' +
                ", money=" + money +
                ", remark='" + remark + '\'' +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                ", userid=" + userid +
                '}';
    }
}

,来看一个转账事务

dao

public interface AccountDao {
    //支出
    public int outAccount(Integer accountId , double money);
    //收入
    public int inAccount(Integer accountId, double money);
import org.example.domain.Account;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.List;
@Repository
public class AccountDaoImpl implements AccountDao{
    @Resource
    private JdbcTemplate jdbcTemplate;
    @Override
    public int outAccount(Integer accountId, double money) {
        String sql = "update tb_account set money = money - ? where account_id =?";
        Object[] objects ={money ,accountId};
        return jdbcTemplate.update(sql,objects);
    }

    @Override
    public int inAccount(Integer accountId, double money) {
        String sql = "update tb_account set money = money+ ? where account_id =?";
        Object[] objects ={money ,accountId};
        return jdbcTemplate.update(sql,objects);
    }
}

service

import org.example.dao.AccountDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class AccountService {
    @Resource
    AccountDao accountDao;
    public int updateAccountByTranfer(Integer outId,Integer inId,double money){
        int code =0;
        int i = accountDao.outAccount(outId, money);
        int i1 = accountDao.inAccount(inId, money);
            if(i==1 && i1==1){
                code=1;
            }
        return code;
    }

}

Test

import org.example.Service.AccountService;
import org.junit.Test;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)  //将运行环境运行在spring 测试环境下
@ContextConfiguration(locations = {"classpath:spring.xml"})//获得上下文环境、
public class springTest extends BaseTest {
    @Resource
    private AccountService accountService;

    @Test
    public void test (){
        int code = accountService.updateAccountByTranfer(1, 2, 500.00);
        if (code==1){
            System.out.println("转账成功");
        }
    }
}

//输出 转账成功

数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4rqAyt32-1649157590574)(C:\Users\19869\AppData\Roaming\Typora\typora-user-images\image-20220405152932560.png)]

这样子是正常的我们来搞个异常

会报错来看数据库

账户一少了500.但是账户2并没有多500.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U8u6wKzJ-1649157590576)(C:\Users\19869\AppData\Roaming\Typora\typora-user-images\image-20220405153405320.png)]

这样子就要有事务的介入了

在这里插入图片描述

在这里插入图片描述

事务的四大特性

原子性:共生死,要么全部成功,要么全部失败!一致性(一致性)

一致性:事务在执行前后,数据库中数据要保持一致性状态。(如转账的过程账户操作后数据必须保持一致)·

隔离性(lsolation)
事务与事务之间的执行应当是相互隔离互不影响的。(多个角色对统一记录进行操作必须保证没有任何干扰),当然没有影响是不可能的,为了让影响级别降到最低,通过隔离级别加以限制:
1.未提交(读未提交)
隔离级别最低的一种事务级别.在这种隔离级别下,会引发脏读、不可重复读和幻读.

2.READ_COMMIT(读已提交)读到的都是别人提交后的值。这种隔离级别下,会引发不可重复读和幻读,但避免了脏读。

3.REPEATABLE_READ(可重复读)
读到的都是别人提交后的值.这种隔离级别下,会引发不可重复读和幻读,但避免了脏读.

.4.SERIALIZABLE(串行化)
最严格的隔离级别.在可序列化隔离级别下,所有事务按照次序依次执行.脏读、不可重复读、幻读都不会出现.

持久性:事务一旦提交,数据库不会改变

Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。

spring 事务配置

添加依赖

 xmlns:tx="http://www.springframework.org/schema/tx"

        http://www.springframework.org/schema/tx https://www.springframework.org/schema/aop/spring-tx.xsd





spring.xml

<!--spring 事务配置-->
<!--    开启Aop代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--    配置事务管理器-->
    <bean id="txManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        数据源 c3p0-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
<!--       配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="txManger">
<!--定义什么方法需要事务处理-->
        <tx:attributes>
            <tx:method name="updateAccountByTranfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
<!--    aop设置-->
    <aop:config>
   <aop:pointcut id="cut" expression="execution(* org.example.Service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
    </aop:config>

注解配置

<!--spring 事务配置-->
<!--    开启Aop代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!--    配置事务管理器-->
    <bean id="txManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        数据源 c3p0-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启事务通知-->
    <tx:annotation-driven transaction-manager="txManger"/>

在方法上添加注解 @Transactional(propagation = Propagation.REQUIRED)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值