【Spring】(十三)声明式事务

声明式事务


1.回顾事务

  • 把一组业务当作一个业务做;要么都成功,要么都失败。
  • 事务在项目开发中,涉及到数据的一致性问题,很重要
  • 确保完整性和一致性。

  • 事务ACID原则:

    • 原子性
    • 一致性
    • 隔离性:多个业务可能操作同一个资源,防止数据损坏。
    • 持久性:事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中。

    数据库的ACID

    ACID 和 CAP 一致性的区别


2.环境搭建

  • 1.mybatis-config.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>
        <typeAliases>
            <package name="pojo"/>
        </typeAliases>
    
    </configuration>
    
  • 2.spring-dao.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"
           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">
    
        <!--DataSource:使用Spring的数据源替换Mybatis的配置  c3p0  dbcp  druid
        这里使用Spring提供的JDBC: org.springframework.jdbc.datasource -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <property name="url" value="jdbc:mysql://localhost:3306/mybatiss?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8" />
            <property name="username" value="root" />
            <property name="password" value="root" />
        </bean>
    
        <!--SqlSessionFactory-->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
    
            <!--绑定Mybatis核心配置文件-->
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
            <property name="mapperLocations" value="classpath:mapper/*.xml" />
        </bean>
    
    </beans>
    
  • 3.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:aop="http://www.springframework.org/schema/aop"
           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">
    
        <import resource="spring-dao.xml" />
    
        <!--注册bean-->
        <bean id="userMapper" class="mapper.UserMapperImpl">
            <property name="sqlSessionFactory" ref="sqlSessionFactory" />
        </bean>
    
    </beans>
    
  • 4.User

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  • 5.UserMapper

    public interface UserMapper {
        public List<User> selectUser();
    
        //添加一个用户
        public int addUser(User user);
    
        //删除一个用户
        public int deleteUser(int id);
    }
    
  • 6.UserMapper.xml

    *这里为了delete故意打错成deletes,为了提供后面事务回滚的测试环境。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="mapper.UserMapper">
    
        <select id="selectUser" resultType="user">
            select * from mybatiss.user;
        </select>
    
        <insert id="addUser" parameterType="user">
            insert into mybatiss.user (id, name, pwd) values (#{id},#{name},#{pwd});
        </insert>
    
        <delete id="deleteUser" parameterType="int">
            deletes from mybatiss.user where id=#{id}
        </delete>
    
    </mapper>
    
  • 7.UserMapperImpl

    public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    
        public List<User> selectUser(){
            User user=new User(6,"akairo","111");
            addUser(user);
            deleteUser(6);
    
            UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
            return mapper.selectUser();
        }
    
        public int addUser(User user) {
            return getSqlSession().getMapper(UserMapper.class).addUser(user);
        }
    
        public int deleteUser(int id) {
            return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
        }
    }
    
  • 8.测试

    public class MyTest {
    
        @Test
        public void test() {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
    
            List<User> userList = userMapper.selectUser();
            for (User user : userList) {
                System.out.println(user);
            }
        }
    }
    
  • 结果:由于删除sql语句错误,最后结果是成功插入6号用户,但删除失败。

    没有开启事务,这里破坏了select()操作的原子性。



3.Spring中的事务管理

  • 声明式事务:AOP【这里使用】
  • 编程式事务:需要在代码中,进行事务的管理

  • 在spring-dao.xml中增加配置

    	<!--配置声明式事务-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <constructor-arg ref="dataSource" />
        </bean>
    
        <!--结合AOP实现事务的织入-->
        <!--配置事务通知-->
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <!--给哪些方法配置事务-->
            <!--配置事务的传播特性:new propagation -->
            <tx:attributes>
                <tx:method name="add*" propagation="REQUIRED"/>
                <tx:method name="delete*" propagation="REQUIRED"/>
                <tx:method name="update*" propagation="REQUIRED"/>
                <tx:method name="select*" read-only="true" />
    <!--            <tx:method name="*" propagation="REQUIRED" />-->
            </tx:attributes>
        </tx:advice>
    
        <!--配置事务切入-->
        <aop:config>
            <aop:pointcut id="txPointCut" expression="execution(* mapper.*.*(..))" />
            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
        </aop:config>
    

    *Spring中声明式事务处理,配置切面时,propagation属性的说明:

    https://blog.csdn.net/sayoko06/article/details/79164858

  • 结果:由于开起了事务,保证了原子性,所以最后结果不变。

posted @ 2021-01-27 21:46  musecho  阅读(110)  评论(0)    收藏  举报