对事物的理解

面试过程中,主考官问道:谈谈你对事物的理解,感觉当时回答的好没有连贯性。事后总结如下:


谈谈我对事物的理解,从如下几个方面进行剖析:

一、事物的特性

二、对事物产生的原因

三、如何解决事物

四、延伸

 

一、事物的特性

对于一个事物必须遵循ISO/IEC所定制的ACID原则。

A:原子性(atomicity),一个不可切割的整体,不能在分,例如开关要么开,要么关,中间没有操作;军人,要么战死,要么凯旋,绝不会投降。

C:一致性(consistency),所操作的东西必须一致,多个因素产生的因素必须守恒(如何能量守恒一样),例如你在银行转钱给别人了,别人就一定能收到钱。

I:隔离性(isolation),隔离性在多个事物进行同时操作的时候就会产生问题。

D:持久性(durability),一定事物完成,就会不会恢复,例如数据一旦commit,就写入到磁盘中,造成不可逆的情况。

遵循这样四种特性的的才能称之为一个事物。

 

 

二、事物会产生的问题

事物产生的原因是有事物的隔离这个特性产生的,多事物同时并发执行对同一个数据库的记录进行操作的时候,会产生如下问题:

a.      数据丢失

很好理解:第一次提交(跟新)的数据,被第二次提交的数据(跟新)覆盖了,导致数据丢失。

b.      不可以重复读

在读数据的时候,我读第一次跟新的数据没问题,我还是同样的操作,读数据的时候确发现不一样,中间被第二个人跟新了数据导致把第一次提交的数据给覆盖掉了。

c.      虚读

在读数据的时候,我读第一次提交的数据没问题,我还是同样的操作,读数据的时候确发现不一样,中间被第二个人提交了数据导致把第一次提交的数据给覆盖掉了。

d.      脏读

读取数据的时候,读取了之前还没有提交的数据。

 

三、如何解决事物产生的问题

数据库中有如下几个事物级别可以解决事物产生的这四个问题:

1.      SERIALIZABLE

完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。

2.      REPEATABLE_READ

对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。

3. READ_COMMITTED

           允许在并发事务已经提交后读取。可防止脏读,但幻读和不可重复读仍可发生。

4.       READ_UNCOMMITED   

     允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读

四种事物级别由上往下依次降低,但是性能确越来越好。

Mysq的默认事物级别低,但是性能好,默认的是READ_COMMITTED.(MYSQL的数据引擎偶多种,如ISAM,MYISAM,HEAP,INNODB,BERKLEY.,myisam是不支持事物的,INNODB支持事物)

Oracle的默认级别是REPEATABLE_READ.

 

延伸一、数据库底层实现机制是如何解决的呢?

数据库底层可以加锁进行控制,如悲观锁,乐观锁。

悲观锁:使用数据库底层的机制,对需要更新的数据进行锁定,防止并发问题,实现方式加入for update,例如:

update  studentsset id = 10   where id = 5 for update;

这样当前事物就会锁定改行,其他事物是不能进行操作改行的的。

 

乐观锁:通过版本控制来实现,解决事物更新丢失的问题。例如hibernate中的解决方案是:

<!-- 使用此属性解决丢失更新问题-->

         <versionname="myVersion"/>

此时在成员变量中定义一个:privateInteger myVersion;//加入一版本属性,解决丢失更新问题

一旦数据跟新:此时myVersion自动自增。若另一个事务操作此myVersion不一样的数据记录则会抛出异常。

 

Mysql默认使用的是排他锁:一个事物获取了一个数据行的排他锁,其他事物就不能在获取该行的其他所(排他锁或者共享锁),即一个事物在读取一个数据行的时候,其他事物不能对该数据进行crud操作。设置排他锁的语句:select … for update

 

排他锁:一个事物获取了一个数据行的共享锁,其他事物能获取该行对应的共享锁,但不能获取排他锁,即一个事物在读取一个数据行的时候,其他事物也可以读,但是不能对该数据进行cud操作。设置共享锁的语句:select … lock in share mode.

 

 

延伸二、框架Spring对事物的解决方案

1.      Spring对事物的支持

Spring事务管理高层抽象主要包括3个接口:

a.PlatformTransactionManager事务管理器 

b.TransactionDefinition事务定义信息(隔离、传播、超时、只读)

c.TransactionStatus 事务具体运行状态

 

其中Spring对PlatformTransactionManager事物管理的接口实现有

 

Spring为不同的持久化框架提供了不同PlatformTransactionManager接口实现

a.org.springframework.jdbc.datasource.DataSourceTransactionManager

  使用Spring JDBC或MyBatis 进行持久化数据时使用

b.org.springframework.orm.hibernate3.HibernateTransactionManager

 使用Hibernate3.0版本进行持久化数据时使用

 

Spring提供事务传播行为类型说明:

PROPAGATION_REQUIRED       支持当前事务,如果不存在 就新建一个

PROPAGATION_SUPPORTS        支持当前事务,如果不存在,就不使用事务

PROPAGATION_MANDATORY  支持当前事务,如果不存在,抛出异常

PROPAGATION_REQUIRES_NEW      如果有事务存在,挂起当前事务,创建一个新的事务

PROPAGATION_NOT_SUPPORTED   以非事务方式运行,如果有事务存在,挂起当前事务

PROPAGATION_NEVER    以非事务方式运行,如果有事务存在,抛出异常

PROPAGATION_NESTED   如果当前事务存在,则嵌套事务执行

 

2.      Spring对事物的配置方式

Spring 支持两种方式事务管理

    1.编程式的事务管理

       在实际应用中很少使用

    2.通过TransactionTemplate手动管理事务

       声明式事务管理,开发中推荐使用(代码侵入性最小,Spring的声明式事务是通过AOP实现的)

编程事务管理:

步骤1:

    配置DataSourceTransactionManager

  

 <!-- 配置DataSourceTransactionManager-->

    <bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

                 <property name="dataSource"ref="dataSource" />

    </bean>

    <!-- 配置TransactionTemplate-->

    <bean id="transactionTemplate"class="org.springframework.transaction.support.TransactionTemplate">

       <property name="transactionManager"ref="txManager" />

    </bean>

   

    <!-- service层中的类 使用TransactionTemplate-->

    <bean id="userService"class="com.feng.service.UserService">

       <property name="transactionTemplate"ref="transactionTemplate" />

             <propertyname="userDao" ref="userDao" />

    </bean>


注:在userService中必须含有transactionTemplate这个类。在可以在:

           

 transactionTemplate.execute(newTransactionCallbackWithoutResult() {

                     

                      @Override

                      protected voiddoInTransactionWithoutResult(TransactionStatus status) {

                                ...在里面完成相应的数据逻辑单元

                      }

             });


    则该execute方法中有控制事务的功能。

   

在xml中申明事事务(常用):

  

 <!-- 配置DataSourceTransactionManager只是针对JDBC或者myBatis -->

    <bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

                 <propertyname="dataSource" ref="dataSource" />

    </bean>

 

    <!--事物通知  -->

    <tx:advice id="myAdvice"transaction-manager="txManager">

             <tx:attributes>

                      <!-- 配置哪些方法需要事物通知-->

                      <tx:methodname="save*" propagation="REQUIRED"/>

                      <tx:methodname="find*" read-only="true"/>

                      <!-- 除了上面的方法-->

                      <tx:methodname="*" propagation="REQUIRED"/>

             </tx:attributes>

    </tx:advice>

    <!-- AOP方式 进行代理 -->

    <aop:config>

             <aop:pointcutexpression="execution(* com.feng.service.*Service.*(..))"id="myPointcut"/>

             <aop:advisoradvice-ref="myAdvice" pointcut-ref="myPointcut"/>

    </aop:config>


 

也可以使用注解:

    beans.xml中配置如下:

  

 <!-- 配置DataSourceTransactionManager只是针对JDBC或者myBatis -->

    <bean id="txManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

                 <propertyname="dataSource" ref="dataSource" />

    </bean>

 

 

   

    <!-- 事务的注解驱动,支持事务注解 -->

    <tx:annotation-driventransaction-manager="txManager"/>


需要事物控制的类:

packagecom.feng.service;

 

importjava.sql.SQLException;

 

importjavax.annotation.Resource;

 

importorg.springframework.stereotype.Service;

importorg.springframework.transaction.annotation.Transactional;

 

importcom.feng.dao.UserDao;

importcom.feng.domian.User;

@Service

@Transactional

publicclass UserService {

    @Resource

    private UserDao userDao;

    public void test() {

             User user = newUser("555", "333");

             try {

                      userDao.save(user);

                     

                     

                      user.setId(1);

                      userDao.update(user);

             } catch (SQLException e) {

                      e.printStackTrace();

             }

    }

    @Transactional(readOnly=true)

    public void find() {

            

    }

}

 


以上几种配置方式都可以达到对事物进行控制。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值