hooyantsing's Blog

第112次课程_Spring整合Mybatis及事务管理

字数统计: 2.1k阅读时长: 9 min
2020/02/25

源辰76班

第112次课程

2020.02.25

内容

Spring整合Mybatis及事务管理

项目路径:

1.Spring-jdbc 连接数据库

1.1.基础

必要依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
<dependency>
       <groupId>org.springframework</groupId>
           <artifactId>spring-jdbc</artifactId>
           <version>4.3.17.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
       <version>5.1.47</version>
</dependency>

Spring xml方式配置

bank-beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- jdbc 连接数据库 -->
    <bean id="dataSource"
       class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName"
           value="${jdbc.driverClassName}"  />
       <property name="url"  value="${jdbc.url}" />
       <property name="username"  value="${jdbc.username}" />
       <property name="password"  value="${jdbc.password}" />
    </bean>
    
    <!-- 读取数据库配置文件 -->
    <context:property-placeholder  location="jdbc.properties"/>
    
    <!-- 执行SQL模板对象配置和使用 -->
    <bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
       <property name="dataSource"  ref="dataSource"></property>
    </bean>

数据库配置文件

jdbc.properties

1
2
3
4
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1/bank
jdbc.username=root
jdbc.password=a

测试

BankTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.yc.spring.bank;
import java.sql.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.jdbc.core.JdbcTemplate;
import  org.springframework.test.context.ContextConfiguration;
import  org.springframework.test.context.junit4.SpringRunner;
import com.yc.spring.bank.action.BankAction;
import com.yc.spring.bank.bean.Account;
@RunWith(SpringRunner.class)
@ContextConfiguration("/bank-beans.xml")
public class BankTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Test
    public void test2() {
       Date now =  jdbcTemplate.queryForObject("select now()",  Date.class);
       System.out.println(now);
    }
}

1.2.项目案例

2.Spring 事务管理

Spring xml方式配置

bank-beans.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd">
     
     <!-- 相当于java注解:@ComponentScan("com.yc.spring.bank") 包扫描 -->
     <context:component-scan  base-package="com.yc.spring.bank"></context:component-scan>
     
     <!-- AOP XML 配置方案 -->
     <aop:config>
        <!-- 切点定义:aop:pointcut
                   技术来源:AspectJ
                   execution (*  com.xyz.myapp.service.*.*(..))
                   执行方法           (返回值                   .包名.类名(所有参数列表))*表示所有
        -->
        <aop:pointcut expression="execution  (* com.yc.spring.bank.biz.*.*(..))"  id="bankBiz"/>
        <!-- 切面定义:aop:aspect -->
        <aop:aspect id="myAspect"  ref="logAdvice">
           <!-- 通知位置定义 -->
           <aop:before  pointcut-ref="bankBiz" method="before"/>
        </aop:aspect>      
     </aop:config>
     
     <!-- 增强类/通知类定义 -->
     <bean id="logAdvice"  class="com.yc.spring.bank.aop.LogAdvice"></bean>
     
     <!-- AspectJ自动代理 -->
     <aop:aspectj-autoproxy />
     
     
     <!--  ================================================================================ -->
    <!-- jdbc 连接数据库 -->
    <bean id="dataSource"
       class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName"
           value="${jdbc.driverClassName}"  />
       <property name="url"  value="${jdbc.url}" />
       <property name="username"  value="${jdbc.username}" />
       <property name="password"  value="${jdbc.password}" />
    </bean>
    
    <!-- 读取数据库配置文件 -->
    <context:property-placeholder  location="jdbc.properties"/>
    
    <!--  -->
    <bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
       <property name="dataSource"  ref="dataSource"></property>
    </bean>
    
    
     <!--  ================================================================================ -->
     
    
    <!-- Spring 事务配置 -->
    <!-- 1.配置事务管理器 -->
    <bean id="txManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"  ref="dataSource"/>
    </bean>
    <!-- 2.添加事务命名空间 关键字tx -->
    <!-- 3.添加事务注解驱动 -->
    <tx:annotation-driven  transaction-manager="txManager"/>
    <!-- 4.业务方法的事务配置
        一般情况下,事务注解是要加在 业务层bean上(@Service)
     -->
    

<!-- 传播行为 意义 *REQUIRED{默认值} 业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务
       NOT_SUPPORTED 声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行
       *REQUIRESNEW 属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行
       MANDATORY 该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
       *SUPPORTS 这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行
       Never 指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行  NESTED
       如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效 -->
    
<!-- 隔离级别 含义 DEFAULT 使用后端数据库默认的隔离级别(spring中的的选择项)  READ_UNCOMMITED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
       READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生  REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。
       SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。 -->
    
</beans>

AccountBiz.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package com.yc.spring.bank.biz;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.yc.spring.bank.bean.Account;
import com.yc.spring.bank.bean.Record;
import com.yc.spring.bank.dao.AccountDao;
import com.yc.spring.bank.dao.RecordDao;

@Service
/*
* 事务注解
* @Transactional(
*             isolation = Isolation.DEFAULT , //隔离级别:4类 有关脏读、不可重复读和幻读
*             propagation = Propagation.REQUIRED , //传播行为:7类
*             readOnly = false , //只读事务
*             timeout = 3000 , //事务超时设置,默认是不限时
*             transactionManager = "其他的事务管理器" , //手动的设置事务管理器
*             rollbackFor , //重点:Spring默认情况下只会在运行期异常出现时,执行回滚,那么如果你有其他的类型的异常要回滚事务,就必须设置该属性。
*             noRollbackFor , //设置不回滚的异常类型
* )
*/
@Transactional
public class AccountBiz {
    
    @Autowired
    private AccountDao aDao;
    @Autowired
    private RecordDao rDao;
    
    /**
     *     存款业务
     */
    public void deposit(Account account) {
        System.out.println("模拟存款业务!");
        aDao.update(account);
        Record r = new Record();
        r.setAccountId(account.getId());
        r.setMoney(account.getMoney());
        
        //运行期异常  测试事务
        //int i = 1/0;
        
        rDao.insert(r);
    }
    
    /**
     *     取款业务
     */
    public void withdraw(Account account) {
        System.out.println("模拟取款业务!");
        aDao.update(account);
        rDao.insert(new Record());
    }
    
    /**
     *     转账业务
     */
    public void transfer(Account account1, Account account2) {
        System.out.println("模拟转账业务!");
        aDao.update(account1);
        aDao.update(account2);
        rDao.insert(new Record());
        rDao.insert(new Record());
    }
    
    /**
     * 查询明细
     */
    public List<Record> details(){
        return new ArrayList<Record>();
    }
    
    public List<Record> details1(){
        int a = 1/0;
        return new ArrayList<Record>();
    }
    
}

CATALOG