spring之事务管理简单实例分析

首先实例情况如下所示:

张三 卡里有2000元,李四 卡里有2000元  ,现在张三转1000给李四,

这个过程分为2部分实现:

第一步:张三从卡里转走1000元,

第二步:李四卡里进账1000元,

上面这两个过程,当从张三卡里转出1000元成功,而后出现异常,不能继续往李四卡里转钱,则此时就会出现张三钱少了,而李四卡里钱没多的情况。

解决:

可以使用事务进行解决上面的问题,当出现异常时,进行回顾操作,即从张三卡里转走钱1000元成功,然后出现异常,则此时可以把从张三卡里转钱的动作进行回滚,相当于没有转钱

具体的实现步骤如下所示:(分为配置XML文件和注解的方式进行实现)

1.导入jar包和数据库表的相关配置;

2.实现实体类的编写

3.编写配置文件或者注解

4.编写测试文件进行测试

---------------------------------------------------------------------------------------

1.导入相关的jar包:

数据表中相关表的配置:

 

2.编写实体类,实体类包括service层和dao层

dao层是对数据库进行操作,在dao层中一般不涉及业务,具体的业务在service层中进行实现

 1 package com.gp.dao;
 2 
 3 import org.springframework.jdbc.core.JdbcTemplate;
 4 
 5 public class UserDao {
 6   private JdbcTemplate jdbcTemplate;
 7   public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
 8     this.jdbcTemplate = jdbcTemplate;
 9   }
10   
11   public void lessMoney(){
12       String sql="update acount set salary=salary-? where username=? ";
13       jdbcTemplate.update(sql,1000, "张三");
14   }
15   public void MoreMoney(){
16       String sql="update acount set salary=salary+? where username=? ";
17       jdbcTemplate.update(sql,1000, "李四");
18   }
19 }

 业务逻辑层的代码如下所示:

 1 package com.gp.service;
 2 
 3 import com.gp.dao.UserDao;
 4 
 5 public class UserService {
 6   private UserDao usersDao;
 7   public void setOrdersDao(UserDao usersDao) {
 8     this.usersDao = usersDao;
 9 }
10   public void runMoney(){
11       usersDao.lessMoney();
12          /**
13           * 此处有意添加异常信息,用于测试其事务的功能
14           */
15           int n=10/0;
16      
17       usersDao.MoreMoney();
18   }
19 }

3.编写配置文件:

说明:此处的配置文件约束文件比较全,还有就是配置比较多,

大致流程为;先进行数据源的配置,然后以数据源为参数注入到jdbcTemplate和事务管理器中,实现jdbc模板和事务管理器的创建

把jdbcTemplate注入到UserDao中进行对数据库的操作,再把UserDao注入到UserService中,进行业务逻辑调用封装的数据库操作任务,为了实现对业务逻辑中方法的事务管理,需要根据配置好的事务管理器进行配置事务通知和事务操作,最后在配置切面和切入点,把事务通知横切进目标对象的切入点中,实现对业务逻辑中方法的事务管理。

具体代码如下所示:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 4     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
 5     xsi:schemaLocation="http://www.springframework.org/schema/beans
 6            http://www.springframework.org/schema/beans/spring-beans.xsd
 7            http://www.springframework.org/schema/aop
 8            http://www.springframework.org/schema/aop/spring-aop.xsd
 9            http://www.springframework.org/schema/tx
10            http://www.springframework.org/schema/tx/spring-tx.xsd
11            http://www.springframework.org/schema/context
12            http://www.springframework.org/schema/context/spring-context.xsd">
13     <!-- 配置c3p0数据源 -->
14     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
15         <property name="driverClass" value="com.mysql.jdbc.Driver" />
16         <property name="jdbcUrl" value="jdbc:mysql:///mybatis" />
17         <property name="user" value="root" />
18         <property name="password" value="guo" />
19     </bean>
20     <!-- 配置jdbcTemplate -->
21     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
22         <property name="dataSource" ref="dataSource" />
23     </bean>
24 
25     <!-- 配置事务管理器 -->
26     <bean id="transactionManager"
27         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
28         <property name="dataSource" ref="dataSource" />
29     </bean>
30     <!-- 配置事务通知 -->
31     <tx:advice id="txadvice" transaction-manager="transactionManager">
32         <!-- 做事务操作 -->
33         <tx:attributes>
34             <!-- 设置进行事务操作的方法匹配规则 -->
35             <tx:method name="runMoney" propagation="REQUIRED" />
36         </tx:attributes>
37     </tx:advice>
38     <!-- 配置切面及切入点 -->
39     <aop:config>
40         <aop:pointcut expression="execution(* com.gp.service.UserService.runMoney(..))"
41             id="pointcut1" />
42         <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1" />
43     </aop:config>
44     <bean id="userDao" class="com.gp.dao.UserDao">
45         <property name="jdbcTemplate" ref="jdbcTemplate" />
46     </bean>
47     <bean id="userService" class="com.gp.service.UserService">
48         <property name="ordersDao" ref="userDao" />
49     </bean>
50 </beans>

4.最后编写测试类:

 1 package com.gp.test;
 2 
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5 
 6 import com.gp.service.UserService;
 7 
 8 public class TestUser {
 9     public static void main(String[] args) {
10         ApplicationContext ct = new ClassPathXmlApplicationContext("applicationContext.xml");
11         UserService userService = (UserService) ct.getBean("userService");
12         userService.runMoney();
13     }
14 }

运行结果为:

由此可知,在代码int n=10/0处报错,地下的内容无法继续执行下面,而数据库的结果显示为:

显示数据库的结果却是没变,即事务管理起作用,把张三转钱与李四卡里进钱看做一起执行,否则就进行回滚操作。

====================================================分界线

上面的实例中,配置文件的内容较多,可以使用注解的方式进行修改,只需修改配置文件和业务逻辑处理文件Service层

配置文件中修改后的代码如下所示:‘

<?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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.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
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 配置c3p0数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql:///mybatis" />
        <property name="user" value="root" />
        <property name="password" value="guo" />
    </bean>
    <!-- 配置jdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 第二步 开启事务注释 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="userDao" class="com.gp.dao.UserDao">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>
    <bean id="userService" class="com.gp.service.UserService">
        <property name="ordersDao" ref="userDao" />
    </bean>
</beans>

UserService文件修改后的内容如下所示:

 1 package com.gp.service;
 2 
 3 import org.springframework.transaction.annotation.Transactional;
 4 import com.gp.dao.UserDao;
 5 
 6 @Transactional
 7 public class UserService {
 8   private UserDao usersDao;
 9   public void setOrdersDao(UserDao usersDao) {
10     this.usersDao = usersDao;
11 }
12   public void runMoney(){
13       usersDao.lessMoney();
14       
15           int n=10/0;
16      
17       usersDao.MoreMoney();
18   }
19 }

实现结果同上所示。

 

补充内容:

事务隔离级别内容(四种)

default:使用后端数据库默认的隔离级别(spring中的选择项)

read_uncommit:允许读还未提交的改变了的数据。可能导致脏读,幻读,不可重复读

read_commit:允许在并发事务已经提交后读取。可防止脏读,但仍然可能出现幻读和不可重复读

repeatable_read:对相同字段多次读取的结果是一致的。可防止脏读,不可重复读,但仍然可能出现幻读

serializable:完全服从ACID的隔离级别。确保不会发生脏读,幻读和不可重复读,在所有隔离级别中是最慢的。

 

脏读:指一个事务在访问数据,并且对数据进行了修改,且这种数据还没提交到数据库,这个时候另一个事务也访问了这个数据,然后使用

幻读:事务在插入已经检查过不存在的数据时,发现数据已经存在了,这种事幻读

不可重复读:指在一个事务中多次读取同一个数据,由于其他事务的修改,导致读取的结果不一致,这种是不可重复读

 

posted on 2018-03-16 22:28  没有太晚的开始  阅读(175)  评论(0编辑  收藏  举报

导航