• spring+mybatis之声明式事务管理初识(小实例)


      前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理.

    1.事务管理

      理解事务管理之前,先通过一个例子讲一下什么是事务管理:取钱。 
    比如你去ATM机取1000块钱,大体有两个步骤:首先输入密码金额,银行卡扣掉1000元钱;然后ATM出1000元钱。这两个步骤必须是要么都执行要么都不执行。如果银行卡扣除了1000块但是ATM出钱失败的话,你将会损失1000元;如果银行卡扣钱失败但是ATM却出了1000块,那么银行将损失1000元。所以,如果一个步骤成功另一个步骤失败对双方都不是好事,如果不管哪一个步骤失败了以后,整个取钱过程都能回滚,也就是完全取消所有操作的话,这对双方都是极好的。 事务就是用来解决类似问题的。事务是一系列的动作,它们综合在一起才是一个完整的工作单元,这些动作必须全部完成,如果有一个失败的话,那么事务就会回滚到最开始的状态,仿佛什么都没发生过一样。 在企业级应用程序开发中,事务管理必不可少的技术,用来确保数据的完整性和一致性。 

      事务有四个特性:ACID

    • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
    • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
    • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
    • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

    2.小实例工程

      (1)工程目录:

      

      (2)建立数据库transaction,建立一张user表:

      

      (3)建立User.java类:

      

    package com.gnc.model;
    
    public class User {
        private String id;
        private String name;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public User() {
    
        }
    
        public User(String id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
    }

      (4)建立UserDao.java数据访问接口:

      

    package com.gnc.dao;
    
    import java.util.List;
    import java.util.Map;
    
    import com.gnc.model.User;
    
    public interface UserDao {
        public int countAll();
        public void insertUser(User user);
        public List<User> getAllUser();
        public User getById(String id);
        public void deleteUser(String id);
        public void updateUser(Map<String,Object> map);
    
    }

      (5)建立实现UserDaoImpl.java类:

      

    package com.gnc.daoImpl;
    
    import java.util.List;
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.gnc.dao.UserDao;
    import com.gnc.mapper.UserMapper;
    import com.gnc.model.User;
    
    @Service("userDao")
    public class UserDaoImpl implements UserDao {
        @Autowired
        private UserMapper userMapper;
    
        public int countAll() {
            return this.userMapper.countAll();
        }
    
        @Override
        public void insertUser(User user) {
            this.userMapper.insertUser(user);
    
        }
    
        @Override
        public List<User> getAllUser() {
            return this.userMapper.getAllUser();
        }
    
        @Override
        public User getById(String id) {
            return this.userMapper.getById(id);
        }
    
        @Override
        public void deleteUser(String id) {
            this.userMapper.deleteUser(id);
    
        }
    
        @Override
        public void updateUser(Map<String, Object> map) {
            this.userMapper.updateUser(map);
        }
    
    }

      (6)建立UserDao接口访问映射文件UserDaoMapper.xml:

      

    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.gnc.mapper.UserMapper">
    
        <parameterMap id="parameterMapUser"  type="com.gnc.model.User" >
            <parameter property="id" />
            <parameter property="name" />
        </parameterMap>
    
        <resultMap id="resultMapUser" type="com.gnc.model.User" >
            <result property="id" column="id" />
            <result property="name" column="name" />
        </resultMap>
    
        <insert id="insertUser" parameterMap="parameterMapUser">
            INSERT INTO user(id,name)
            VALUES(?,?)
        </insert>
        <select id="countAll" resultType="int">
            select count(*) c from user;
        </select>
        <select id="getAllUser" resultMap="resultMapUser">
            SELECT * FROM user
        </select>
        <select id="getById" parameterType="String" resultMap="resultMapUser">
            SELECT * FROM user
            WHERE id=#{value}
        </select>
        <delete id="deleteUser" parameterType="String">
            DELETE FROM user
            WHERE id=#{value}
        </delete>
        <update id="updateUser" parameterType="java.util.Map">
            UPDATE user
            SET name=#{name}
            WHERE id=#{id}
        </update>
    </mapper>

      (7)建立UserService.java接口类:

      

    package com.gnc.service;
    
    import java.util.Map;
    
    import com.gnc.model.User;
    
    public interface UserService {
        public int countAll();
    
        public void insertUser(User user);
    
        public void update_insert(Map map, User user);
    
    }

      (8)建立UserServiceImpl.java实现类:

      

    package com.gnc.serviceImpl;
    
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import com.gnc.dao.UserDao;
    import com.gnc.model.User;
    import com.gnc.service.UserService;
    
    @Service("userService")
    public class UserServiceImpl implements UserService {
        @Autowired
        private UserDao userDao;
    
        public int countAll() {
            return this.userDao.countAll();
        }
    
        @Override
        public void insertUser(User user) {
            this.userDao.insertUser(user);
            throw new RuntimeException("Error");
        }
    
        @Override
        public void update_insert(Map map, User user) {
            this.userDao.updateUser(map);
            this.userDao.insertUser(user);
            throw new RuntimeException("Error");
    
        }
    
    }

      (9)建立mybatis配置文件MyBatis-Configuration.xml:

      

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <mappers>
            <mapper resource="UserDaoMapper.xml"/>
        </mappers>
    </configuration>

      (10)建立数据库配置文件config.properties:

      

    db.driverClass=org.gjt.mm.mysql.Driver
    db.jdbcUrl=jdbc:mysql://localhost:3306/transaction
    db.user=root
    db.password=geningchao
    #
    db.initialPoolSize=20
    db.maxIdleTime=60
    db.maxPoolSize=200
    db.minPoolSize=50
    #
    db.acquireIncrement=3
    db.acquireRetryDelay=1000
    db.acquireRetryAttempts=30
    db.breakAfterAcquireFailure=false

      (11)建立spring配置文件applicationContext.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"
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="
         http://www.springframework.org/schema/beans  
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
         
         http://www.springframework.org/schema/context  
         http://www.springframework.org/schema/context/spring-context-3.0.xsd  
         
         http://www.springframework.org/schema/tx 
         http://www.springframework.org/schema/tx/spring-tx.xsd 
         
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
         
         http://www.springframework.org/schema/mvc  
         http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    
        <!-- 加载配置文件 -->
        <context:property-placeholder location="config.properties" />
        <!-- 指定spring注解注入层 -->
        <context:component-scan base-package="com.gnc" />
        <!-- 数据库连接池管理 -->
        <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close">
            <property name="driverClass" value="${db.driverClass}"></property>
            <property name="jdbcUrl" value="${db.jdbcUrl}"></property>
            <property name="user" value="${db.user}"></property>
            <property name="password" value="${db.password}"></property>
    
    
            <property name="initialPoolSize" value="${db.initialPoolSize}"></property>
    
            <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
            <property name="maxIdleTime" value="${db.maxIdleTime}"></property>
            <!--连接池中保留的最大连接数。Default: 15 -->
            <property name="maxPoolSize" value="${db.maxPoolSize}"></property>
            <property name="minPoolSize" value="${db.minPoolSize}"></property>
    
            <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
            <property name="acquireIncrement" value="${db.acquireIncrement}"></property>
            <!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
            <property name="acquireRetryDelay" value="${db.acquireRetryDelay}"></property>
            <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
            <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}"></property>
            <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 
                获取连接失败后该数据源将申明已断开并永久关闭。Default: false -->
            <property name="breakAfterAcquireFailure" value="${db.breakAfterAcquireFailure}"></property>
        </bean>
    
        <!-- ================================事务相关控制================================================= -->
    
        <bean name="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="c3p0DataSource"></property>
        </bean>
    
        <tx:advice id="userTxAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="delete*" propagation="REQUIRED" read-only="false"
                    rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" />
                <tx:method name="insert*" propagation="REQUIRED" read-only="false"
                    rollback-for="java.lang.RuntimeException" />
                <tx:method name="update*" propagation="REQUIRED" read-only="false"
                    rollback-for="java.lang.Exception" />
                <tx:method name="find*" propagation="SUPPORTS" />
                <tx:method name="get*" propagation="SUPPORTS" />
                <tx:method name="select*" propagation="SUPPORTS" />
            </tx:attributes>
        </tx:advice>
    
        <aop:config>
            <aop:pointcut id="pc"
                expression="execution(public * com.gnc.service.*.*(..))" /> <!--把事务控制在Service层 -->
            <aop:advisor pointcut-ref="pc" advice-ref="userTxAdvice" />
        </aop:config>
    
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="c3p0DataSource" />
            <property name="configLocation" value="MyBatis-Configuration.xml" />
        </bean>
    
    
        <bean class="org.mybatis.spring.mapper.MapperFactoryBean">
            <property name="mapperInterface" value="com.gnc.mapper.UserMapper" />
            <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        </bean>
    
    
    
    </beans>

      (12)建立测试类UserServiceTest.java:

      

    package com.gnc.test;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import com.gnc.model.User;
    import com.gnc.service.UserService;
    
    public class UserServiceTest {
        
        @Test
        public void userServiceTest(){
            @SuppressWarnings("resource")
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService)context.getBean("userService");
            User user =new User();
            user.setId("003");
            user.setName("樱木花道");
            
            Map map=new HashMap();
            map.put("id", "001");
            map.put("name", "方舟子");
            try {
                  System.out.println(userService.countAll());
                  userService.update_insert(map, user);
            } catch (Exception e) {
                e.printStackTrace();
            }
           
          
        }
    }

     3.工程分析

      该工程属于声明式事务管理,事务管理的主要配置是写在spring的配置文件当中,工程运行时,先加载spring配置文件,通过spring配置文件得到mybatis配置文件,得到映射文件,进行事务处理以及书屋管理.但是这种事务管理方式限制了包的分级结构和函数名的前缀,所以一般情况下,我们使用注解式事务管理,注解式事务管理实例将在下一章节给出并进行说明!

      以上仅是个人观点,若有不对,敬请扶正!

  • 相关阅读:
    疫情控制
    数据结构1
    NOIP 模拟 921
    ml-agents项目实践(一)
    Appium的安装及简单的使用介绍
    移动设备管理平台的搭建(基于STF/ATXServer2)
    ClickHouse利器—如何提高留存计算速度
    Linux基本操作命令
    深度学习与强化学习的两大联姻:DQN与DDPG的对比分析
    漏洞扫描软件AWVS的介绍和使用
  • 原文地址:https://www.cnblogs.com/geningchao/p/6628452.html
Copyright © 2020-2023  润新知