Java面试准备资料五

184 阅读6分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

十一、Spring事务

1、事务特性(ACID)

  • 原子性(Atomicity):事务应该当作一个单独单元的操作,这意味着整个序列操作要么是成功,要么是失败的。

    保证1-6所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第五步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态。

  • 一致性(Consistency):这表示数据库的引用完整性的一致性,表中唯一的主键等。转账前后双方账户金额总和不变

    在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等。

  • 隔离性(Isolation):可能同时处理很多有相同的数据集的事务,每个事务应该与其他事务隔离,以防止数据损坏。

    在A向B转账的整个过程中,只要事务还没有提交(commit),查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。 如果在A给B转账的同时,有另外一个事务执行了C给B转账的操作,那么当两个事务都结束的时候,B账户里面的钱应该是A转给B的钱加上C转给B的钱再加上自己原有的钱。

  • 持久性(Durability):一个事务一旦完成全部操作后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

    一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化(会把数据写入数据库做持久化保存)!

2、事务隔离级别

1. 未提交读(Read uncommitted)

允许脏读,也就是可能读取到其他会话中未提交事务修改的数据(数据库一般不用)

2. 已提交读(Read committed)

只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

数据的读取都是不加锁的,但是数据的写入、修改和删除是需要加锁的

3. 可重复读(Repeatable read)

可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读(幻读)

4. 可串行化(Serializable )

完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。解决幻读

5. 不可重复读和幻读的区别

  • 在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据,就可以实现可重复读了
  • 但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免
  • 需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

3、 编程式事务

在代码中硬编码(不推荐使用)

基于 TransactionTemplate 的编程式事务管理

  • 配置文件形式

事务管理器bean:transactionManager

事务管理模板bean:TransactionTemplate

4、声明式事务

在配置文件中配置(推荐)

Spring的声明式事务管理是建立在Spring AOP机制上的,其本质是对目标方法前后进行拦截,并在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

  • 基于XML方式+AspectJ

事务管理器bean

配置事务方法:

 <tx:advice id="advice" transaction-manager="txManager">
     <tx:attributes>
         <tx:method name="*" propagation="REQUIRED"/>  
         上面就表示所有方法都加事务,然后传播特性为:REQUIED
     </tx:attributes>
 </tx:advice>
  • 基于注解(Annotation)方式

@Transactional

6、Spring的传播特性

定义:

两个事务相互调用,应该怎么处理

7种传播特性(2+4+1):

  • 完全不要事务(2种)
  1. TransactionDefinition.PROPAGATION_NEVER:以非事务运行,如果当前存在事务,则抛出异常 2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务运行,如果当前存在事务,则把事务挂起
  • 可有可无(1种)
  1. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • 必须要有事务(4种)
  1. TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  2. TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
  3. TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  4. TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

十二、Java异常处理机制

1. 抛出异常

  • throw exception
  • throw:手动抛出异常,一般由程序员在方法内抛出Exception的子类异常。 throws:声明在方法名之后,告诉调用者,该方法可能会抛出异常,也就是说异常发生后会抛给调用者,由调用者处理异常。

2. 捕获异常

  • try-catch-finally机制

十三、HashSet特性与如何判断存入的对象是否重复

  • HashSet实现了Set接口,所以里面存储的数据具有无序性,同时保证不可重复性
  • 底层采用HashMap存储,通过equals方法和hashcode方法确定数据元素的唯一性

十四、谈谈多线程以及进程与线程的区别

进程与线程的区别

  • 进程是运行中的程序,线程是进程的内部的一个执行序列。
  • 进程是资源分配的单元,线程是执行行单元
  • 进程间切换代价大,线程间切换代价小
  • 进程拥有资源多,线程拥有资源少
  • 多个线程共享进程的资源

多线程

  • 一个程序内部可以同时实现多个操作
  • 一个进程(应用程序)并发执行多个线程(任务)
  • 线程是进程的一个基本单位。多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的
  • Java多线程实现方式主要有三种:继承Thread类实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。