spring-事务

一、为什么要使用事务及事务的特性

  事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。
  事物的特性:
  1、原子性(事务不可分割,一个事务就是一个最小的单元,这里面的操作是一块的执行的。)
  2、一致性(因为是一个单元,将相当于一个球,动的时候是一个球在动,里面的东西都是一块的,提交就都提交,撤回就都撤回)
  3、隔离性(当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离)
  4、持久性(指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作)

二、数据资源并发访问(隔离级别不同)时可能会出现的情况

  1.脏读:读到另一个未提交事务的数据
  2.不可重复读:B事务读取了两次数据,但在两次中间有另一个事务对数据进行了修改并提交,导致读到的数据两次不一样。(行影响)
  3.幻读:B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样。(表影响)
  **幻读与不可重复读的区别:都是读取了两次数据。不可重复读是针对一行数据,数据内容前后不一致。幻读是针对表,前后读出的行数不一样。

三、数据库的隔离级别

  为了解决上面出现的问题,主流数据库都会提供四种事务隔离级别。
  1.读未提交(Read Uncommitted)所有事务都能看到其他事务未提交的数据。但这只能防止更新丢失,不能解决脏读,不可重复读和幻读。
  2.读已提交(Read Committed)事务只能看到其他事物已提交的数据的改变,这个可以解决脏读问题,但对不可重复读和幻读无效。这是大多数数据库系统的默认隔离级别
  3.可重复读(Repeatable Read)读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。Mysql默认使用该隔离级别。这可以通过“共享读锁”和“排他写锁”实现,即事务需要对某些数据进行修改必须对这些数据加 X 锁,读数据时需要加上 S 锁,当数据读取完成并不立刻释放 S 锁,而是等到事物结束后再释放。所以是对修改的数据加锁,所以增加数据并不能禁止,所以不能防止幻读。
  4.可串行化(Serializable)事务只能一个接着一个地执行,不能并发执行。但可能导致大量的超时现象和锁竞争,通常数据库不会用这个隔离级别

脏读不可重复读幻读
读未提交×××
读已提交××
可重复读×
可串行化

四、spring实现事务

1.spring_dao.xml:

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

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/eiji/mapper/userMapper.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--结合AOP实现事务织入-->
    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--哪些方法使用事务-->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务切入-->
    <aop:config>
        <aop:pointcut id="pointCut" expression="execution(* com.eiji.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/>
    </aop:config>

</beans>

2.UserMapperImpl:

public class UserMapperImpl implements UserMapper {
    SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public void insertUser(User user) {
        sqlSession.getMapper(UserMapper.class).insertUser(user);
    }

    public void deleteUser(int id) {
        sqlSession.getMapper(UserMapper.class).deleteUser(id);
    }

    public List<User> selectUser() {
        return sqlSession.getMapper(UserMapper.class).selectUser();
    }
}

3.测试类:

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper bean =  context.getBean(UserMapper.class);
        bean.insertUser(new User(14,"果然少年","231424"));
        bean.deleteUser(13);

        List<User> users = bean.selectUser();
        for (User user : users) {
            System.out.println(user);
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值